Session 3 - Introduction to Kernel Space and API

Tasks

Download and unzip the tasks archive sesiune-03 on the virtual machine.

# My syscall #* Use the code in the my_syscall directory. # code in kernel directory is a kernel module and code in user is an user space application. # my_syscall.c implements a module that adds a custom syscall on position 0 in the syscall table. # Note: In the later kernel version, the syscall table cannot be accessed from modules (is not exported) but our kernel was modified in order to export it. # bell.c implements the userspace part (caller) of our syscall. It uses the syscall libc function to make a system call identified by number. #* compile the kernel module and insert it into the running kernel # use dmesg to confirm load. #* compile the userspace utility ('make bell') and run it. # use dmesg again to see that your kernel code has been run by the bell process. # Bonus: remove the kernel module, run the bell utility and see dmesg for you first Oups message :) Any idea why that happened? # Task information #* While in kernel space, the syscall handler function has access to several kernel structures. Like information about processes. # each process in the system has an instance of task_struct. # 'current' is a macro that points to the task_struct of the process that currently runs the kernel code. # Use 'current→pid' in a printk inside the syscall handler to see the process ID of the process using the syscall.

  1. Using kernel linked lists
    • Create a link list that is empty when the module loads.
    • A list element contains the PID of a process.
    • Add a new element each time the my_syscall system call is accessed.
    • When the modules is unloaded, print (using printk) the PIDs in the list.
    • Don't forget to free all resources before unloading the module!
    • Use this code for inspiration:
      #include <linux/slab.h>
      #include <linux/list.h>
       
      struct pid_list {
          pid_t pid;
          struct list_head list;
      };
       
      LIST_HEAD(my_list);
       
      static int add_pid(pid_t pid)
      {
          struct pid_list *ple = kmalloc(sizeof *ple, GFP_KERNEL);
       
          if (!ple)
              return -ENOMEM;
       
          ple->pid = pid;
          list_add(&ple->list, &my_list);
       
          return 0;
      }
       
      static int del_pid(pid_t pid)
      {
          struct list_head *i, *tmp;
          struct pid_list *ple;
       
          list_for_each_safe(i, tmp, &my_list) {
              ple = list_entry(i, struct pid_list, list);
              if (ple->pid == pid) {
                  list_del(i);
                  kfree(ple);
                  return 0;
              }
          }
       
          return -EINVAL;
      }
       
      static void destroy_list(void)
      {
          struct list_head *i, *n;
          struct pid_list *ple;
       
          list_for_each_safe(i, n, &my_list) {
              ple = list_entry(i, struct pid_list, list);
              list_del(i);
              kfree(ple);
          }
      }
  2. Protecting the list
    • Use a spinlock to protect the critical actions on the list.
sesiuni/kernel/day-3.txt · Last modified: 2013/07/03 09:39 by mbarbulescu