Title: Class 18: System Calls
Date: 2014-04-03
Category: Classes
Tags: operating systems, kernel, kernel programming, system calls, setuid
Author: David Evans

   <div class="todo"> 
   <center>
**Schedule your PS4 demo by 11:59pm today**: [Signup Form](https://docs.google.com/spreadsheet/ccc?key=0Au4I_91g4pu3dGZIdVYzNndRRGdJMHpwYWJVQWxBaGc&usp=sharing)<br>
[PS4](|filename|../../pages/ps/ps4/ps4.md) is due **Sunday, 6 April**.</b> 
   </center>
   </div>

<center>
<iframe src="http://www.slideshare.net/slideshow/embed_code/33284434" width="476" height="400" frameborder="2" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</center>

## Course Goal Reminder: Minimizing Magic

<center>
<iframe width="640" height="360" src="//www.youtube-nocookie.com/embed/yXF_zp9R6Vw?list=PLvpsxlEF9cP1Gt9pVrGznW_PW81rtN-dA" frameborder="2" allowfullscreen></iframe>
</center>

By the time you finish PS4 (that is, this Sunday!), you really should
feel like you understand everything important that is going on in a
computing system, from the level of a web service like Google or
Facebook down to the level of a transistor (but not necessarily the
physics that makes the transistor work).  There are, of course, lots of
details and clever algorithms needed to make things work efficiently,
but nothing should seem beyond your understanding about how these
systems work.

The one important gap we have left to cover in this class is how to
build concurrency abstractions like the MutexArc without starting with
mutual exclusion mechanisms.  I promised to talk about this back in
[Class 14](|filename|../class14/class14.md) (when Leslie Lamport won the
Turing Award), but will finally get around to it next week.  The other
major gap that you may still have is how a compiler turns a high-level
program into something at the level of machine code.  We won't cover
that in this class, but you should have a reasonable idea how this works
from cs2150, and I would encourage you to take a compilers course to
learn more.

If there are other gaps in your understanding between the transistor and
web service, you should comment about them below, or email me directly,
and I'll try to include these topics in remaining classes.

# Access Control

<center>
<iframe width="640" height="360" src="//www.youtube-nocookie.com/embed/ceU8JvQ5lcA?list=PLvpsxlEF9cP1Gt9pVrGznW_PW81rtN-dA" frameborder="2" allowfullscreen></iframe>
</center>

Why is `chroot` not a completely satisfactory way to limit the files that might be exposed by a web server?
<div class="gap">

</div>

Should file permissions be part of the directory structure or part of the inode?
<div class="gap">

</div>

```C
struct inode {
        umode_t                 i_mode;
        unsigned short          i_opflags;
        uid_t                   i_uid;
        gid_t                   i_gid;
        unsigned int            i_flags;
        ...
```
From [include/linux/fs.h](http://lxr.free-electrons.com/source/include/linux/fs.h)

Why is `chmod 666 filename` usually a bad idea?
<div class="gap">

</div>

## setuid

<center>
<iframe width="640" height="360" src="//www.youtube-nocookie.com/embed/SH5euOg18Bw?list=PLvpsxlEF9cP1Gt9pVrGznW_PW81rtN-dA" frameborder="2" allowfullscreen></iframe>
</center>

Why does `setuid(0)` do?  When should it be allowed?
<div class="gap">

</div>


How does changing the effective uid to serve a web request follow the
_principle of least priviledge_?
<div class="gap">

</div>


Hao Chen, David Wagner, and Drew Dean.  [_Setuid Demystified_](http://www.cs.berkeley.edu/~daw/papers/setuid-usenix02.pdf)
(USENIX Security 2002).

From Apache httpd's [support/suexec.c](|filename|./suexec.c):

```C
/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * ...
 */

/*
 * suexec.c -- "Wrapper" support program for suEXEC behaviour for Apache
 ***********************************************************************
 * NOTE! : DO NOT edit this code!!!  Unless you know what you are doing,
 *         editing this code might open up your system in unexpected
 *         ways to would-be crackers.  Every precaution has been taken
 *         to make this code as safe as possible; alter it at your own
 *         risk.
 ***********************************************************************
 */

...
    /*
     * Log the transaction here to be sure we have an open log
     * before we setuid().
     */
    log_no_err("uid: (%s/%s) gid: (%s/%s) cmd: %s\n",
               target_uname, actual_uname,
               target_gname, actual_gname,
               cmd);

    /*
     * Error out if attempt is made to execute as root or as
     * a UID less than AP_UID_MIN.  Tsk tsk.
     */
    if ((uid == 0) || (uid < AP_UID_MIN)) {
        log_err("cannot run as forbidden uid (%lu/%s)\n", (unsigned long)uid, cmd);
        exit(107);
    }

    /*
     * Error out if attempt is made to execute as root group
     * or as a GID less than AP_GID_MIN.  Tsk tsk.
     */
    if ((gid == 0) || (gid < AP_GID_MIN)) {
        log_err("cannot run as forbidden gid (%lu/%s)\n", (unsigned long)gid, cmd);
        exit(108);
    }

    /*
     * Change UID/GID here so that the following tests work over NFS.
     *
     * Initialize the group access list for the target user,
     * and setgid() to the target group. If unsuccessful, error out.
     */
    if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 0)) {
        log_err("failed to setgid (%lu: %s)\n", (unsigned long)gid, cmd);
        exit(109);
    }

    /*
     * setuid() to the target user.  Error out on fail.
     */
    if ((setuid(uid)) != 0) {
        log_err("failed to setuid (%lu: %s)\n", (unsigned long)uid, cmd);
        exit(110);
    }

    /*
     * Get the current working directory, as well as the proper
     * document root (dependant upon whether or not it is a
     * ~userdir request).  Error out if we cannot get either one,
     * or if the current working directory is not in the docroot.
     * Use chdir()s and getcwd()s to avoid problems with symlinked
     * directories.  Yuck.
     */
    if (getcwd(cwd, AP_MAXPATH) == NULL) {
        log_err("cannot get current working directory\n");
        exit(111);
    }

    if (userdir) {
        if (((chdir(target_homedir)) != 0) ||
            ((chdir(AP_USERDIR_SUFFIX)) != 0) ||
            ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
            ((chdir(cwd)) != 0)) {
            log_err("cannot get docroot information (%s)\n", target_homedir);
            exit(112);
        }
    }
    else {
        if (((chdir(AP_DOC_ROOT)) != 0) ||
            ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
            ((chdir(cwd)) != 0)) {
            log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT);
            exit(113);
        }
    }

    if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
        log_err("command not in docroot (%s/%s)\n", cwd, cmd);
        exit(114);
    }

    /*
     * Stat the cwd and verify it is a directory, or error out.
     */
    if (((lstat(cwd, &dir_info)) != 0) || !(S_ISDIR(dir_info.st_mode))) {
        log_err("cannot stat directory: (%s)\n", cwd);
        exit(115);
    }

    /*
     * Error out if cwd is writable by others.
     */
    if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & S_IWGRP)) {
        log_err("directory is writable by others: (%s)\n", cwd);
        exit(116);
    }

    /*
     * Error out if we cannot stat the program.
     */
    if (((lstat(cmd, &prg_info)) != 0) || (S_ISLNK(prg_info.st_mode))) {
        log_err("cannot stat program: (%s)\n", cmd);
        exit(117);
    }

    /*
     * Error out if the program is writable by others.
     */
    if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & S_IWGRP)) {
        log_err("file is writable by others: (%s/%s)\n", cwd, cmd);
        exit(118);
    }

    /*
     * Error out if the file is setuid or setgid.
     */
    if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & S_ISGID)) {
        log_err("file is either setuid or setgid: (%s/%s)\n", cwd, cmd);
        exit(119);
    }

    /*
     * Error out if the target name/group is different from
     * the name/group of the cwd or the program.
     */
    if ((uid != dir_info.st_uid) ||
        (gid != dir_info.st_gid) ||
        (uid != prg_info.st_uid) ||
        (gid != prg_info.st_gid)) {
        log_err("target uid/gid (%lu/%lu) mismatch "
                "with directory (%lu/%lu) or program (%lu/%lu)\n",
                (unsigned long)uid, (unsigned long)gid,
                (unsigned long)dir_info.st_uid, (unsigned long)dir_info.st_gid,
                (unsigned long)prg_info.st_uid, (unsigned long)prg_info.st_gid);
        exit(120);
    }
    /*
     * Error out if the program is not executable for the user.
     * Otherwise, she won't find any error in the logs except for
     * "[error] Premature end of script headers: ..."
     */
    if (!(prg_info.st_mode & S_IXUSR)) {
        log_err("file has no execute permission: (%s/%s)\n", cwd, cmd);
        exit(121);
    }

#ifdef AP_SUEXEC_UMASK
    /*
     * umask() uses inverse logic; bits are CLEAR for allowed access.
     */
    if ((~AP_SUEXEC_UMASK) & 0022) {
        log_err("notice: AP_SUEXEC_UMASK of %03o allows "
                "write permission to group and/or other\n", AP_SUEXEC_UMASK);
    }
    umask(AP_SUEXEC_UMASK);
#endif /* AP_SUEXEC_UMASK */

    /* Be sure to close the log file so the CGI can't mess with it. */
    if (log != NULL) {
#if APR_HAVE_FCNTL_H
        /*
         * ask fcntl(2) to set the FD_CLOEXEC flag on the log file,
         * so it'll be automagically closed if the exec() call succeeds.
         */
        fflush(log);
        setbuf(log, NULL);
        if ((fcntl(fileno(log), F_SETFD, FD_CLOEXEC) == -1)) {
            log_err("error: can't set close-on-exec flag");
            exit(122);
        }
#else
        /*
         * In this case, exec() errors won't be logged because we have already
         * dropped privileges and won't be able to reopen the log file.
         */
        fclose(log);
        log = NULL;
#endif
    }

    /*
     * Execute the command, replacing our image with its own.
     */
#ifdef NEED_HASHBANG_EMUL
    /* We need the #! emulation when we want to execute scripts */
    {
        extern char **environ;

        ap_execve(cmd, &argv[3], environ);
    }
#else /*NEED_HASHBANG_EMUL*/
    execv(cmd, &argv[3]);
#endif /*NEED_HASHBANG_EMUL*/

    /*
     * (I can't help myself...sorry.)
     *
     * Uh oh.  Still here.  Where's the kaboom?  There was supposed to be an
     * EARTH-shattering kaboom!
     *
     * Oh well, log the failure and error out.
     */
    log_err("(%d)%s: exec failed (%s)\n", errno, strerror(errno), cmd);
    exit(255);
}

```

Identify at least 10 ways this code is better than Apple's SSL implementation:
<div class="gap">

</div>

## Implementing System Calls

<center>
<iframe width="640" height="360" src="//www.youtube-nocookie.com/embed/MjgvV7LulsI?list=PLvpsxlEF9cP1Gt9pVrGznW_PW81rtN-dA" frameborder="2" allowfullscreen></iframe>
</center>

What is `libc` and why does it exist?
<div class="gap">

</div>

Why can't `setuid` in glibc call directly into the kernel?
<div class="gap">

</div>

## Exploring the Kernel

Here's how to get the linux source code for the kernel you are running:

```bash
apt-get source linux-image-$(uname -r)
```

(this works in Ubuntu using the bash shell, you may need to do something
slightly different on other platforms).

Here's an example of a useful command for searching the kernel code:
```bash
find . -name "*.h" -print | xargs grep "IA32_SYSCALL_VECTOR"
```

What does `set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall)` (in linux-3.2.0/arch/x86/kernel/traps.c) do?
<div class="gap">

</div>

What are all the steps in going from the `setuid(uid)` call in `suexec.c` to changing the user id of the running process?
<div class="gap">

</div>

<div id="disqus_thread"></div>

<script type="text/javascript">
        /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
        var disqus_shortname = 'rust-class'; // required: replace example with your forum shortname
	var disqus_url = 'http://www.rust-class.org/class-18-system-calls.html';

        /* * * DON'T EDIT BELOW THIS LINE * * */
        (function() {
            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
            dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
        })();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
