`What does it mean by speak, friend, and enter?' asked Merry.
'That is plain enough,' said Gimli. `If you are a friend, speak the password, and the doors will open, and you can enter.'
—The Fellowship of the Ring, Book 2, Chapter 4
System calls are the fundamental, most stable interface that is provided by the operating system. They are how user programs request the vast majority of kernel actions: creating, reading, and destroying files; allocating and freeing dynamic memory; executing new programs, etc.
In this studio, you will:
Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete.
As you work through these exercises, please record your answers, and when finished email your results to dferry@email.wustl.edu with the phrase System Calls Studio in the subject line.
Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.
man syscalls
.
Navigate outside of the linux source code directory
and make a new directory for your userspace programs, and a new file called
lib_call.c
. In Linux, all users have an associated user ID number.
Write a short program that reads your user ID, then attempts to set it to
zero (the root uid),
and then reads it again with the functions getuid
and setuid
. Use the man pages at
man getuid
and man setuid
to understand what header
files you need to include and how to call these functions.
Since the call to setuid
may fail, we need to do proper unix
style error checking. Store the return value from setuid into a variable,
and follow it up with something like:
if( return_val != 0 ) printf("Error to setuid failed! Reason: %s\n", strerror(errno));
Again, you can use the man pages to determine which header files to include
with the commands man printf
, man strerror
, and
man errno
.
At the end of your program, write out the before and after values of the user ID. As the answer to this question, copy and paste your program output.
man syscall
(this is a different page
than we accessed before, which was man syscalls
).
Copy your program to a new file called native_call.c
and replace
the calls to getuid
and setuid
with calls to
syscall
. To do so, you will have to determine their ARM
architecture specific system call numbers by looking at the linux source files
arch/arm/include/uapi/asm/unistd.h
As the answer to this exercise, copy and paste your program output.
setuid
and give any process the root user ID (this is a bad thing
in general, but it is illustrative). You will write the second system call,
which will print a message into the kernel log.
Note:When making changes to the linux source code, add the comment //AOS before each section. This, along with generating file diffs is how we will keep track of the changes made to the kernel.
There are five discrete tasks we need to accomplish to do so:
First, we declare two new function prototypes that take no arguments at the
bottom of include/linux/syscalls.h
. Before doing so, make a backup
with the command cp syscalls.h syscalls.h.orig
You can use the prototype for
sys_getuid
as a template for this. Make sure that you use
void
in the argument list to indicate no arguments, since in
C programming a function declared f(void)
is not the same as
a function declared f()
(which inidicates that the function may
take any number of parameters of unknown type). Our new system call is going
to do something relatively bad (in operating system terms), so call it
sys_badcall
. Make a second prototype that accepts one integer
parameter and call it what you would like.
As the answer to this exercise, give the two function prototypes you've made.
arch/arm/kernel/
.
The naming convention for a file that only implements a system call is to
call the file by the syscall name, so since our prototype is called
sys_badcall
, you would create the file sys_badcall.c
.
(Additionally, there are other places we could have put this file, but since
we're only adding this call for the ARM architecture, this is the most
appropriate place.) Make a second file for your second system call in the
same place and with the same naming convention.
For the implementation of sys_badcall
, copy and paste the
contents of the file found here. Take a moment
to look through this file. Notice that the function declaration isn't a normal
declaration, but actually made through the macro SYSCALL_DEFINE0
(the zero comes from that this syscall takes zero arguments, and is defined
in include/linux/syscalls.h
).
For the implementation of your second syscall, use sys_badcall.c as a
template. You'll need to change the SYSCALL_DEFINE0
macro to
reference the name you came up with, as well as the fact that this function
accepts an integer parameter. You do this by passing the type and the name of
the parameter to the macro as such:
SYSCALL_DEFINE1( your_name, int, param_name )
In the body of this syscall, use the kernel function printk
to print a message along with the value of the parameter. You can use
printk
as you would use printf
. Be sure to return
a proper return value from this function.
Leave the answer to this exercise blank.
arch/arm/kernel/
) and add our two new files to the end of the
object file list, which starts on the line with obj-y
(make sure
you do not add your files after a \
character, as this specifies
the start of a new line.
Leave the answer to this exercise blank.
arch/arm/include/uapi/asm/unistd.h
.
Before modifying this file, make a copy into unistd.h.orig
.
Then, open the file and write system call numbers 388 and 389 for
sys_badcall and your own system call near the bottom of the file. Use the
other system calls as a template for how to do so.
Next we will modify arch/arm/kernel/calls.S
. This is actually
an ARM assembly language file that defines the system call table. Similar to
before, first make a backup of calls.S
and then
add two new invocations of the CALL
macro near the end
of the file for sys_badcall
and your function.
Finally, we need to update the symbol that tells the kernel how many system
calls that it has. Go to arch/arm/include/asm/unistd.h
, make a
backup copy, and update the value of __NR_syscalls
to 392. This
seems strange, but on the ARM architecture the system call table can only be
certain sizes. See the enrichment exercises for more info.
Leave this exercise blank.
arch
, init
,
drivers
, etc.) you should issue the command make
clean
to remove previous build products.
Then, to differentiate your
next kernel from your current, we'll modify the kernel LOCALVERSION. Rather
than using the menuconfig
like last time, it's faster and easier
to modify the configuration directly. In the base directory, open the file
called .config
(the leading period means that this is a hidden
file that is not normally displayed) and modify the
CONFIG_LOCALVERSION
string to reflect the fact that this new
kernel implements studio 2.
You can now build your new kernel following the procedure outlined in studio 1.
uname -a
), you're now ready invoke your new system
calls. First, make a copy of lib_call.c
and call it
badcall_call.c
. Then, replace the call to
setuid
with a native system call to sys_badcall
.
As the answer to this exercise, copy and paste the output from
badcall_call.c
.
dmesg
.
As the answer to this exercise, copy and paste the last few lines of the system message log.
To submit this studio, include the answers to exercises given above, attach the userspace programs you wrote, as well as diffs of the kernel source code files you modified. To create a diff, use the diff program with the backup versions of the source code you modified.
For example: diff -up unistd.h unistd.h.orig > unistd.h.diff
For this studio, you will submit:
arch/arm/kernel/
include/linux/
arch/arm/include/uapi/asm/
arch/arm/include/asm/
arch/arm/kernel/
If you don't have an original copy for any of these files, you can find them in the original source code package.
man syscall
.
The kernel code that contains the entry point for system calls is found
in arch/arm/kernel/entry-common.S
.