http://www.cc.gatech.edu/classes/AY2002/cs3210_spring/p1.html CS 3210 Operating System Design (Linux) Fall 2001 • College of Computing, Georgia Tech Project 1: Let the Games
Begin DUE: Tu 12 Feb (Sign up for a demo time
on the Swiki) Objective We
are going to be implementing a system call (lets call it cloak) and
also use a
file in the proc filesystem ( /proc/stealth ). The implementation will
be done
in a single kernel module, which will be inserted in at runtime into
the
kernel. The aim of the system call would be to hide a given process
from the ps
command, and also turn this functionality on/off with the help of a
file in the
/proc filesystem. Initially, I will give a
brief description of modules and how
they work, how to implement a system call as a module and some
information
about the /proc filesystem. There is a reading list
right at the end of the
writeup,which may prove useful. Also you are expected to have been
attending
class and understanding what was happening there! J Grading Criteria (100
Points) 1.
Code and documentation
that implement the stealth system call. You must sign up for a demo
time with
one of the TA's to show your working code. You are not required to turn
in a
hard copy of your code. This will be worth 85 Points of the project
grade,
broken down as: a.
35 Points
for a working read/write /proc/stealth. b.
35 Points
for a working cloak system call. c.
30 points
for answering question during the demo. The Project
After completing this
project you should be able to answer the following questions. We will ask these questions during your demo
and everyone in your team is expected to be able to answer them: 1.
How did you implement the
"cloak" system call? What
kernel source files and routines you used as well as how your
implementation
met the specification explained below. 2.
How did you implement /proc/stealth? What
functions did you
have to write to interface with the proc file system and how your code
transferred
data to and from the proc file? 3.
Specifically, what is the
journey of the cloak system call through
the kernel? Especially the details
involving how the user level library call gets converted to an actual
system
call. Be sure to include the sys_call_table, the syscallX() macro, int x80, how
values are returned from the system call and
how errors are indicated. Useful
resources are Bovet & Cesati, man
2 –intro man
page, and the kernel
#include files dealing with system calls. Modules Modules are
written in C,
like the rest of the Linux kernel, with two important differences from
programming user level programs:
When you compile
a kernel
module a module.o object file is produce. This
is what you “insert” into a running kernel. To
do this you would run:
/sbin/insmod
module.o To remove the
module, run:
/sbin/rmmod
module Note that the
name of the
module to remove does not end in “.o”.
To see a list of the currently installed modules run:
/sbin/lsmod
init_module() is the function that is called when the
module is
installed into the kernel via /sbin/insmod. There is also a cleanup_module() function
that is called when the module is removed from the kernel via /sbin/rmmod. init_module() and cleanup_module() are the only two functions needed to have
a
completely functioning module. Again, to see which modules are
currently loaded
in the kernel, run /sbin/lsmod, or do a 'cat' on /proc/modules. Re-read the
first couple of
chapters of Rubini for an excellent introduction to implementing kernel
modules. System
Calls
So the first
step in
creating a system call is to choose an available number in the sys_call_table to use. You can
either enter
your system call into this array using a module or by putting it
directly into
the kernel source. For all system calls
you implement in this class you will use a module. It is easier to use
modules
because you will not have to re-compile the entire kernel each time you
modify
your system call. How to
implement a system call as a module To access the sys_call_table array you need to define it as an extern
at the top of your module
source file.
When the module is initialized, in init_module(), you will need to first save the old
entry of the
array. You may be wondering why you
have to save the current function pointer in the array because you
chose an
array index that was unused. The reason
is the kernel has a default function there that simply returns an error
saying
the system call with this number is not implemented. When the module is
unloaded you will restore that default function. Here is a
skeleton module
for a system
call. /proc
File System Proc files can
be used to
obtain information about the system (i.e. /proc/interrupts) or to change certain kernel parameters
at runtime.
Look at the man page for proc files and also the documentation for them
under linux/Documentation/filesystems/proc.txt. The /proc files we are
interested in for this project provide information about running
processes. The directory name, under
/proc, to identify each running process is its PID number. Here is an
example
of a special /proc/<pid> entry named /proc/self. Obviously
"self" is not an actual system
PID but it will correspond to
whichever process is currently reading /proc/self. For
example, the
command:
ls /proc/self
produces:
cmdline cwd environ exe
fd maps mem
root stat statm
status which is the information
about the process running the ls
command which
read /proc/self. Try
this out. Is self the shell process or is
it something different? The reason the self file is in /proc is so
that applications can get useful
information about themselves. The ps command also gets
process information from the /proc/<pid> entries.
Specifically, ps
looks at the stat,
statm and status proc files in each
<pid> directory. So to prevent a process
from showing up when we run the ps command , we will hide the process
from the
proc filesystem. Rather than
explain how to
create and use a /proc file here, follow the link below to an excellent
Howto that concisely
details how to
create, use, and destroy /proc files. http://www.kernelnewbies.org/documents/kdoc/procfs-guide/lkprocfsguide.html Implementing the Cloak
System Call As mentioned earlier, we
are going to create a "cloak" system call that hides a process from
the system. Actually, to hide a process
completely is very hard to implement because there are a number of ways
to
detect a process. For example, if you
knew a possible PID for a cloaked process you could send that PID a
signal and
see if it responded. So we are just going to hide a process from /proc,
which
will also hide the process from the ps command. Your group needs to
implement a system call to hide the specified process from the /proc
file
system. Implement the system call as a kernel module. Here's how a
process
would use the call to hide itself:
main(){
....
hide_process(getpid());
....
unhide_process(getpid());
.... After calling the hide_process() system call, this
process would be hidden from /proc as well as
the ps command. The unhide_process() call would bring the
process back; i.e. you have to make hiding
reversible. If either of these system calls is
called with a PID that does
not exist you need to return the proper error code, you can find which
error
code this is by searching through the kernel #include files (linux/include/linux). The task list is a
circular linked list of task structures (process control blocks or
PCBs). The /proc file system is implemented in linux/fs/proc. A
scan of the task list
is made to generate the /proc/<pid> entries on demand. A simple modification to this code will
allow a process to not be detected. The
system must be able to keep track of which processes are cloaked. You must do this in the
kernel; you're not allowed to modify the ps command! PART 2: Implement the
Read/write /proc/stealth File A) You need to have a
read/write
proc file where you can turn the entire stealth system on or off. For
example,
writing a "1" to /proc/stealth would allow you to call hide_process() and writing "0" would
disable this feature as well as
make any currently hidden processes visible again. It
is valid to call hide_process() on process X when the system
is turned off, when the system is turned back on process X should now
be
hidden. B) Create another proc
file that prints the current list of hidden processes when read. You might want to do this anyway for
debugging, obviously you wouldn't want this if you were deploying
stealth J Some Specifics Whenever you do anything
with the task list you need to do the proper locking, to ensure the
list is not
corrupted. For example, if you only
want to read information in a task struct you only need a read lock:
read_lock(&tasklist_lock);
/*
do some reading */
read_unlock(&tasklist_lock); but if you want to write
to any value in a task struct need a write lock:
write_lock(&tasklist_lock);
/*
do some writing */
write_unlock(&tasklist_lock); Hopefully your
modifications won’t require locking , but it is advised to do it to be
completely safe! BONUS (Have Some Fun) ·
Create another set of
system calls that take in a user name and hide all of those users’
processes. This cannot break the
earlier system and they should all work together, e.g. hiding all of a
user's
processes and then selectively un-hiding a few should be possible. (5
Points) ·
Modify your system call
module such that only root can use it. ( 5 Points ) ·
Extend above to be able
to hide and unhide a specific users process based on the process'
executable
name. e.g.: hide_user_process(linus,gcc) (5 Points) ·
Make a system which
install new system calls for the user. For eg. A call like install_sys_call(
pointer to func , int num_args , args…..) Helpful ·
Bovet & Cesati
Chapter
8 (System Calls) ·
linux/fs/proc/*.c ·
http://www.kernelnewbies.org/documents "Procfs
Guide" under "Kerneldoc".
This will tell you everything you need to know to create a proc
file
that can be read or written. ·
linux/Documentation/filesystems/proc.txt This
is a thorough overview of all the proc files, section 1.1 is a short
bit about
process-specific data. A Last Bit of Advice ·
Make sure to follow the
Procfs Guide on kernelnewbies.org and understand where in memory you
are
reading and writing data from/to. ·
If you haven't already,
learn the "tags" feature of your favorite editor (vim and emacs
support this). This is not necessary, but being able to do a:
make tags in
the top of the kernel source tree and easily jump around the kernel
source will
save you a great deal of time. |