Operating Systems 2022F: Assignment 4

From Soma-notes
Revision as of 04:49, 25 November 2022 by Soma (talk | contribs) (→‎Questions)

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.

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