Difference between revisions of "Operating Systems 2022F: Assignment 4"

From Soma-notes
Jump to navigation Jump to search
Line 10: Line 10:
# [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.
# [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.
# [2] How important is line 204?  What about 205?  Explain what happens when these lines are not present.
# [4] Change c3000procreport so that it reports not just the calling process but also lists all of the process's ancestors until there are no more to report.  You should support up to 10 levels of ancestor processes.  Each report should be on a line saying "PID's parent is PID", where the PID's are process IDs.


==Source==
==Source==

Revision as of 00:57, 25 November 2022

This assignment is still being developed.

Questions

  1. [1] Download, build, and install the c3000procreport module. What is reported in the kernel log when the module is installed?
  2. [2] When you run cat /dev/procreport, what does it report? Give sample output and explain what each part means briefly.
  3. [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.
  4. [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?
  5. [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?
  6. [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.
  7. [2] How important is line 204? What about 205? Explain what happens when these lines are not present.
  8. [4] Change c3000procreport so that it reports not just the calling process but also lists all of the process's ancestors until there are no more to report. You should support up to 10 levels of ancestor processes. Each report should be on a line saying "PID's parent is PID", where the PID's are process IDs.

Source

c3000procreport.zip

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");
}