Operating Systems 2022F: Assignment 4
This assignment is still being developed.
Questions
- [1] Download, build, and install the c3000procreport module. What is reported in the kernel log when the module is installed?
- [2] When you run cat /dev/procreport, what does it report? Give sample output and explain what each part means briefly.
- [2] Run bpftrace watch_procreport.bt in one terminal and then run dd if=/dev/procreport bs=1024 count=1. What does the bpftrace script report? Why are we getting this output? Explain what you see.
- [2] If you run the command dd if=/dev/procreport seek=1 bs=1024 count=1, what happens? Does bpftrace watch_procreport.bt give you any insight as to what is happening?
- [2] What is the purpose of line 122, a call to put_user()? Why can't this line be replaced with a simple array assignment?
- [1] What is the purpose of line 107, a call to put_user()? Remove this line and report how the behavior of the module changes.
- [2] How important is line 204? What about 205? Explain what happens when these lines are not present.
Source
c3000procreport.c
/*
c3000procreport.c
Anil Somayaji
November 21, 2022
creates a device /dev/procreport that, when read,
reports on the process reading the device
based on newgetpid and 3000physicalview
Carleton University COMP 3000, Fall 2022
*/
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/pgtable_types.h>
#define dbg(format, arg...) do { if (debug) pr_info(CLASS_NAME ": %s: " format, __FUNCTION__, ## arg); } while (0)
#define err(format, arg...) pr_err(CLASS_NAME ": " format, ## arg)
#define info(format, arg...) pr_info(CLASS_NAME ": " format, ## arg)
#define warn(format, arg...) pr_warn(CLASS_NAME ": " format, ## arg)
#define alert(format, arg...) pr_alert(CLASS_NAME ": " format, ## arg)
#define DEVICE_NAME "procreport"
#define CLASS_NAME "comp3000"
static struct class* procreport_class = NULL;
static struct device* procreport_device = NULL;
static int procreport_major;
unsigned long procreport_get_physical(unsigned long addr)
{
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
unsigned long pfn = 0;
unsigned long phys = 0;
pgd = pgd_offset(current->mm, addr);
if (!pgd || pgd_none(*pgd) || pgd_bad(*pgd)) {
err("Invalid pgd for address 0x%016lx\n", addr);
return phys;
}
p4d = p4d_offset(pgd, addr);
if (!p4d || p4d_none(*p4d) || p4d_bad(*p4d)) {
err("Invalid p4d for address 0x%016lx\n", addr);
return phys;
}
pud = pud_offset(p4d, addr);
if (!pud || pud_none(*pud) || pud_bad(*pud)) {
err("Invalid pud for address 0x%016lx\n", addr);
return phys;
}
pmd = pmd_offset(pud, addr);
if (!pmd || pmd_none(*pmd) || pmd_bad(*pmd)) {
err("Invalid pmd for address 0x%016lx\n", addr);
return phys;
}
pte = pte_offset_map(pmd, addr);
if (!pte || pte_none(*pte)) {
err("Invalid pte for address 0x%016lx\n", addr);
return phys;
}
pfn = pte_pfn(*pte);
phys = (pfn << PAGE_SHIFT) + (addr % PAGE_SIZE);
return phys;
}
EXPORT_SYMBOL(procreport_get_physical);
static int procreport_open(struct inode *the_inode, struct file *f)
{
return 0;
}
static ssize_t procreport_read(struct file *f, char *buf, size_t len,
loff_t *offset)
{
size_t i, msglen;
pid_t thepid;
unsigned long buf_phys;
char message[100];
if (*offset > 0) {
return 0;
}
thepid = task_tgid_vnr(current);
put_user('0', buf);
buf_phys = procreport_get_physical((unsigned long) buf);
snprintf(message, 100,
"Your PID is %d!\n"
"Buffer at 0x%016lx virtual is at 0x%016lx physical.\n",
thepid, (unsigned long) buf, buf_phys);
msglen = strlen(message);
if (len < msglen) {
msglen = len;
}
for (i = 0; i < msglen; i++) {
put_user(message[i], buf++);
}
*offset = i;
return i;
}
static int procreport_release(struct inode *the_inode, struct file *f)
{
return 0;
}
static struct file_operations procreport_fops = {
.open = procreport_open,
.read = procreport_read,
.release = procreport_release,
};
static char *procreport_devnode(struct device *dev, umode_t *mode)
{
if (mode)
*mode = 0444;
return NULL;
}
static int __init procreport_init(void)
{
int retval;
procreport_major = register_chrdev(0, DEVICE_NAME,
&procreport_fops);
if (procreport_major < 0) {
err("failed to register device: error %d\n",
procreport_major);
retval = procreport_major;
goto failed_chrdevreg;
}
procreport_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(procreport_class)) {
err("failed to register device class '%s'\n", CLASS_NAME);
retval = PTR_ERR(procreport_class);
goto failed_classreg;
}
procreport_class->devnode = procreport_devnode;
procreport_device = device_create(procreport_class, NULL,
MKDEV(procreport_major, 0),
NULL, DEVICE_NAME);
if (IS_ERR(procreport_device)) {
err("failed to create device '%s'\n", DEVICE_NAME);
retval = PTR_ERR(procreport_device);
goto failed_devreg;
}
info("procreport device registered using major %d.\n",
procreport_major);
return 0;
failed_devreg:
class_unregister(procreport_class);
failed_classreg:
unregister_chrdev(procreport_major, DEVICE_NAME);
failed_chrdevreg:
return -1;
}
static void __exit procreport_exit(void)
{
device_destroy(procreport_class, MKDEV(procreport_major, 0));
class_unregister(procreport_class);
unregister_chrdev(procreport_major, "procreport");
info("Unloading procreport module.\n");
return;
}
module_init(procreport_init);
module_exit(procreport_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Somayaji <soma@scs.carleton.ca>");
MODULE_DESCRIPTION("c3000procreport character device module");
watch_procreport.bt
kprobe:procreport_devnode
{
printf("devnote called.\n");
}
kprobe:procreport_get_physical
{
printf("get_physical called.\n");
}
kprobe:procreport_open
{
printf("open called.\n");
}
kprobe:procreport_read
{
printf("read called.\n");
}
kretprobe:procreport_read
{
printf("read returned %d.\n", retval);
}
kprobe:procreport_release
{
printf("release called.\n");
}