System Calls

2,228 views

Published on

University of Virginia
cs4414: Operating Systems
http://rust-class.org

For embedded notes, see:
http://rust-class.org/class-18-system-calls.html

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,228
On SlideShare
0
From Embeds
0
Number of Embeds
1,011
Actions
Shares
0
Downloads
74
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

System Calls

  1. 1. Plan for Today Access Control User IDs System Calls 1 Sign up for PS4 demos today! PS4 is due 11:59pm Sunday, 6 April
  2. 2. Minimizing Magic 2 Itsallmagic! Physics Four Years Studying Computing at an Elite Public University Itsall understandable! (andIcandomagicalthings!) Cool Computing Stuff Class 1:
  3. 3. Course Goal Reminder: Minimizing Magic3 Itsallmagic! Physics Cool Computing Stuff cs1110 cs2110 cs2150 cs2150 cs2330 cs3330 cs3102 cs4414 cs4610 cs4414 cs4414 electives Class 1:
  4. 4. Course Goal Reminder: Minimizing Magic4 Itsallmagic! Physics Cool Computing Stuff cs1110 cs2110 cs2150 cs2150 cs2330 cs3330 cs3102 cs4414 cs4610 cs4414 cs4414 electives Class 1: If you have any gaps left (other than synchronization primitives), post then in comments or email me.
  5. 5. What’s wrong with Zhtta? 5
  6. 6. What’s wrong with Zhtta? 6 Note: because of the way pathnames are handled, I think it is probably actually secure (except for links in www/).
  7. 7. 7 Why Might Letting Anyone Read Any File on your Machine Be a Bad Idea? LMGTFY
  8. 8. 8 This is serious: actually trying the passwords would be wrong and criminal.* * Just because someone “broadcasts” their password or uses laughable security, doesn’t mean the FBI considers it “authorized” access. Whether it is you or Google that is breaking the law in this case is unclear.
  9. 9. Unix(Sort-of) “Solution” 9
  10. 10. Zhtta and Apache’s (Partial) Solution 10 DocumentRoot /home/evans/htdocs/ Apache will only serve files in DocumentRoot’s subtree. in httpd.conf:
  11. 11. Apache’s (Partial) Solution 11 DocumentRoot /home/evans/htdocs/ Opps! Now it will follow symlinks inside DocumentRoot subtree to anywhere… in httpd.conf: <Directory /> Options FollowSymLinks </Directory>
  12. 12. Apache’s (Further) Solution 12 User #-1 Apache starts running as root (uid = 0) to be able to listen on port 80, which is default web port. By default, switches to run as uid = -1 (“nobody”) when processing requests. in httpd.conf:
  13. 13. 13 bash-3.2$ ps aux | grep httpd dave 20926 0.0 0.0 2423356 208 p0 R+ 10:15PM 0:00.00 grep httpd _www 20923 0.0 0.0 2437400 700 ?? S 10:15PM 0:00.00 httpd root 20922 0.0 0.0 2437400 2376 ?? Ss 10:15PM 0:00.05 httpd # after one request bash-3.2$ ps aux | grep httpd dave 20934 0.0 0.0 2432768 620 p0 S+ 10:16PM 0:00.00 grep httpd _www 20932 0.0 0.0 2437400 700 ?? S 10:16PM 0:00.00 httpd _www 20931 0.0 0.0 2437400 700 ?? S 10:16PM 0:00.00 httpd _www 20930 0.0 0.0 2437400 896 ?? S 10:16PM 0:00.00 httpd _www 20923 0.0 0.0 2437400 1800 ?? S 10:15PM 0:00.01 httpd root 20922 0.0 0.0 2437400 2376 ?? Ss 10:15PM 0:00.05 httpd
  14. 14. Access Control 14 How does the OS know whether or not the (effective) user can read a file?
  15. 15. 15
  16. 16. 16
  17. 17. 17
  18. 18. 18 Size of File (bytes) Device ID User ID Group ID File Mode (permission bits) Link count (number of hard links to node) … Diskmap
  19. 19. Access Control Matrix 19 Users Files /alice/www/index.html /dave/secrets.txt /alice/secrets.txt root read, write read, write read, write dave read read, write - www read - - Can Unix-like file system support this?
  20. 20. 20 Size of File (bytes) Device ID User ID Group ID File Mode (permission bits) Link count (number of hard links to node) … Diskmap
  21. 21. 21 http://lxr.free-electrons.com/source/include/linux/fs.h (Linux Version 3.14)
  22. 22. 22 http://lxr.free-electrons.com/source/include/linux/fs.h (Linux Version 3.14) include/linux/types.h#L18 short: at least 16 bits
  23. 23. Unix File Mode Permission Bits 23execute write read execute write read execute write read owner group others + 7 bits for other stuff: file/directory symbolic link etc. 666 644 000 755
  24. 24. 24 bash-3.2$ ps aux | grep httpd dave 20926 0.0 0.0 2423356 208 p0 R+ 10:15PM 0:00.00 grep httpd _www 20923 0.0 0.0 2437400 700 ?? S 10:15PM 0:00.00 httpd root 20922 0.0 0.0 2437400 2376 ?? Ss 10:15PM 0:00.05 httpd # after one request bash-3.2$ ps aux | grep httpd dave 20934 0.0 0.0 2432768 620 p0 S+ 10:16PM 0:00.00 grep httpd _www 20932 0.0 0.0 2437400 700 ?? S 10:16PM 0:00.00 httpd _www 20931 0.0 0.0 2437400 700 ?? S 10:16PM 0:00.00 httpd _www 20930 0.0 0.0 2437400 896 ?? S 10:16PM 0:00.00 httpd _www 20923 0.0 0.0 2437400 1800 ?? S 10:15PM 0:00.01 httpd root 20922 0.0 0.0 2437400 2376 ?? Ss 10:15PM 0:00.05 httpd How does Apache create processes running as different users?
  25. 25. Changing Users 25 int setuid(uid_t uid); real user id (ruid) = owner of the process effective user id (euid) = ID used in access control decisions saved user id (suid) = previous user ID that may be restored
  26. 26. Using setuid 26 httpd euid: 0 (root) HTTPGET./../../../user/dave/secrets.txt handler pid_t handler = fork(); if (handler == 0) { setuid(-1); … } fopen(pathname, ‘r’) Error: secrets.txt not readable to user nobody
  27. 27. Using setuid 27 httpd euid: 0 (root) handler pid_t handler = fork(); if (handler == 0) { setuid(-1); … } fopen(pathname, ‘r’) Error: secrets.txt not readable to user nobody Principle of Least Privilege Running code should have as little power as possible to get the job done. HTTPGET./../../../user/dave/secrets.txt
  28. 28. 28 SOSP 1973
  29. 29. POSIX Spec for setuid 29
  30. 30. 30 Hao Chen, David Wagner, Drew Dean. Setuid Deymystified USENIX Security 2002
  31. 31. Where should Apache httpd call setuid? 31
  32. 32. 32 gash> curl http://apache.mirrors.tds.net//httpd/httpd-2.4.9.tar.gz | tar xz gash> cd httpd-2.4.9/ gash> find . -name "*.c" -print | xargs grep "setuid(" ./modules/arch/unix/mod_privileges.c: if (cfg->uid && (setuid(ap_unixd_config.user_id) == -1)) { ./modules/arch/unix/mod_privileges.c: if (cfg->uid && (setuid(cfg->uid) == -1)) { ./modules/arch/unix/mod_unixd.c: setuid(ap_unixd_config.user_id) == -1)) { ./modules/arch/unix/mod_unixd.c: setuid(ap_unixd_config.user_id) == -1)) { ./os/bs2000/os.c:/* This routine complements the setuid() call: it causes the BS2000 job ./os/bs2000/os.c:/* BS2000 requires a "special" version of fork() before a setuid() call */ ./os/unix/unixd.c:/* This routine complements the setuid() call: it causes the BS2000 job ./os/unix/unixd.c:/* BS2000 requires a "special" version of fork() before a setuid() call */ ./server/mpm/prefork/prefork.c: /* BS2000 requires a "special" version of fork() before a setuid() call */ ./support/suexec.c: * before we setuid(). ./support/suexec.c: * setuid() to the target user. Error out on fail. ./support/suexec.c: if ((setuid(uid)) != 0) {
  33. 33. 33 in mod_privileges.c: /* if either user or group are not the default, restore them */ if (cfg->uid || cfg->gid) { if (setppriv(PRIV_ON, PRIV_EFFECTIVE, priv_setid) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02136) "PRIV_ON failed restoring default user/group"); } if (cfg->uid && (setuid(ap_unixd_config.user_id) == -1)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02137) "Error restoring default userid"); } if (cfg->gid && (setgid(ap_unixd_config.group_id) == -1)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02138) "Error restoring default group"); } }
  34. 34. Apache’s (Further) Solution 34 User #-1 Apache starts running as root (uid = 0) to be able to listen on port 80, which is default web port. By default, switches to run as uid = -1 (“nobody”) when processing requests. in httpd.conf: A few minutes ago…
  35. 35. 35 static int unixd_drop_privileges(apr_pool_t *pool, server_rec *s) { … /* Only try to switch if we're running as root */ if (!geteuid() && (setuid(ap_unixd_config.user_id) == -1)) { rv = errno; ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL, APLOGNO(02162) "setuid: unable to change to uid: %ld", (long) ap_unixd_config.user_id); return rv; } in mod_unixd.c:
  36. 36. 36 in support/suexec.c: … copyright and license /* * 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. * *********************************************************************** * * */
  37. 37. 37 /* * 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); }
  38. 38. 38 /* * 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); } … /* * 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); } …
  39. 39. 39 /* * Error out if cwd is writable by others. */ if ((dir_info.st_mode & S_IWOTH) || … { 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) || …) { 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) || …) { 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) || …) { … 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); }
  40. 40. 40 /* * Execute the command, replacing our image with its own. */ ... execv(cmd, &argv[3]); /* * (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); }
  41. 41. 41 /* * 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. */ … if ((setuid(uid)) != 0) { log_err("failed to setuid (%lu: %s)n", (unsigned long)uid, cmd); exit(110); } … /* * Error out if the program is writable by others. */ if ((prg_info.st_mode & S_IWOTH) || …) { log_err("file is writable by others: (%s/%s)n", cwd, cmd); exit(118); } … /* * 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); } … execv(cmd, &argv[3]); log_err("(%d)%s: exec failed (%s)n", errno, strerror(errno), cmd); exit(255); }
  42. 42. /* * 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. */ … if ((setuid(uid)) != 0) { log_err("failed to setuid (%lu: %s)n", (unsigned long)uid, cmd); exit(110); } … /* * Error out if the program is writable by others. */ if ((prg_info.st_mode & S_IWOTH) || …) { log_err("file is writable by others: (%s/%s)n", cwd, cmd); exit(118); } … /* * 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); } … execv(cmd, &argv[3]); log_err("(%d)%s: exec failed (%s)n", errno, strerror(errno), cmd); exit(255); } 42 Well done Apache!
  43. 43. How is setuid implemented? 43 if ((setuid(uid)) != 0) { log_err("failed to setuid (%lu: %s)n", …); exit(110); }
  44. 44. libc 44
  45. 45. 45 glibc/sysdeps/unix/sysv/linux/setuid.c: int __setuid (uid_t uid) { return INLINE_SETXID_SYSCALL (setuid, 1, uid); } #ifndef __setuid weak_alias (__setuid, setuid) #endif
  46. 46. 46 #define DO_CALL(syscall_name, args) lea SYS_ify (syscall_name), %rax; syscall glibc/sysdeps/unix/x86_64/sysdep.h int $0x80 #define PSEUDO(name, syscall_name, args) lose: jmp JUMPTARGET(syscall_error) .globl syscall_error; ENTRY (name) DO_CALL (syscall_name, args); jb lose glibc/sysdeps/x86_64/sysdep.h
  47. 47. Why can’t libc call directly into the kernel? 47
  48. 48. Getting to the Kernel 48 setuid(uid) httpd libc: setuid() linux kernel: syscall int 0x80 jumps into kernel code sets supervisor mode
  49. 49. Traditional PC Design 49 CPU Programmable Interrupt Controller (PIC) TimerKeyboard
  50. 50. 50 Page 2213 of Intel x86 Manual: http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf Modern x86 Design: “APIC” = “Advanced PIC”
  51. 51. 51 Page 2213 of Intel x86 Manual: http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf What should generate an “External Interrupt”? What should generate a “Local Interrupt”?
  52. 52. 52
  53. 53. 53
  54. 54. 54 IronKernel: arch/arm/cpu/interrupt.rs
  55. 55. Handling Syscall Interrupts 55 … lea SYS_setuid,%rax int $0x80 CPU Programmable Interrupt Controller (PIC)
  56. 56. 56 Intel manual, p. 146:
  57. 57. 57
  58. 58. Context Switch! 58 setuid(uid) httpd libc: setuid() linux kernel: syscall int 0x80 jumps into kernel code sets supervisor mode
  59. 59. 59 linux-3.2.0/arch/x86/kernel/traps.c void __init trap_init(void) { … set_intr_gate(X86_TRAP_DE, &divide_error); set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK); … set_intr_gate(X86_TRAP_BR, &bounds); set_intr_gate(X86_TRAP_UD, &invalid_op); … /* Reserve all the builtin and the syscall vector: */ for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) set_bit(i, used_vectors); set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall); set_bit(IA32_SYSCALL_VECTOR, used_vectors); … cpu_init();
  60. 60. 60 linux-3.2.0/arch/x86/kernel/traps.c void __init trap_init(void) { … set_intr_gate(X86_TRAP_DE, &divide_error); set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK); … set_intr_gate(X86_TRAP_BR, &bounds); set_intr_gate(X86_TRAP_UD, &invalid_op); … /* Reserve all the builtin and the syscall vector: */ for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) set_bit(i, used_vectors); set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall); set_bit(IA32_SYSCALL_VECTOR, used_vectors); … cpu_init(); gash> find . -name "*.h" -print | xargs grep "IA32_SYSCALL_VECTOR" ./arch/x86/include/asm/irq_vectors.h:#define IA32_SYSCALL_VECTOR 0x80
  61. 61. 61 linux-3.2.0/kernel/sys.c SYSCALL_DEFINE1(setuid, uid_t, uid) { const struct cred *old; struct cred *new; int retval; new = prepare_creds(); if (!new) return -ENOMEM; old = current_cred(); retval = -EPERM;
  62. 62. 62 … if (nsown_capable(CAP_SETUID)) { new->suid = new->uid = uid; if (uid != old->uid) { retval = set_user(new); if (retval < 0) goto error; } } else if (uid != old->uid && uid != new->suid) { goto error; } ... new->fsuid = new->euid = uid; retval = security_task_fix_setuid(new, old, LSM_SETID_ID); if (retval < 0) goto error; return commit_creds(new); error: abort_creds(new); return retval; }
  63. 63. 63 /** * commit_creds - Install new credentials upon the current task * @new: The credentials to be assigned * * Install a new set of credentials to the current task, using RCU to replace * the old set. Both the objective and the subjective credentials pointers are * updated. This function may not be called if the subjective credentials are * in an overridden state. * * This function eats the caller's reference to the new credentials. * * Always returns 0 thus allowing this function to be tail-called at the end * of, say, sys_setgid(). */ int commit_creds(struct cred *new) { …
  64. 64. 64 int commit_creds(struct cred *new) { struct task_struct *task = current; /* do it * RLIMIT_NPROC limits on user->processes have already been checked * in set_user(). */ alter_cred_subscribers(new, 2); if (new->user != old->user) atomic_inc(&new->user->processes); rcu_assign_pointer(task->real_cred, new); rcu_assign_pointer(task->cred, new); if (new->user != old->user) atomic_dec(&old->user->processes); alter_cred_subscribers(old, -2); …
  65. 65. Back to Apache 65 setuid(uid) httpd libc: setuid() linux kernel: syscall int 0x80 jumps into kernel code sets supervisor mode
  66. 66. Project Idea? 66 Make system calls work in IronKernel
  67. 67. Charge 67 Sign up for PS4 demos today! PS4 is due 11:59pm Sunday, 6 April When writing security-sensitive code, emulate Apache’s suEXEC, not glibc or the Linux kernel. (Note: any code that runs on the Internet is “security-sensitive”.)

×