290 likes | 367 Views
System Programming. Chapter 8.11. Fun Stuff. Touch-based Communication. Changing User/Group ID ’ s. This part is confusing … (when I read it) Why changes user id in the middle of a program execution?
E N D
System Programming Chapter 8.11
Fun Stuff • Touch-based Communication
Changing User/Group ID’s • This part is confusing … (when I read it) • Why changes user id in the middle of a program execution? • Least-privilege model: a program should use the least privilege necessary to accomplish any task. • Reduce window of security vulnerability • Example: a process needs to gain a privilege to access a privileged file
Recall … • A process can have more than one ID. • Real user/group ID: who you really are • Effective user/group ID: determine file access permission • Supplementary group IDs • Saved set-user/group-ID = owner of the program with set-user-id bit set • Why do you need saved set-user-id? • cannot give up privilege temporarily (and get it back)
Recall … #include <sys/types.h> #include <unistd.h> int setuid(uid_t uid); • The process == superuser set real/effective/saved-suid = uid • Otherwise, euid=uid if uid == ruid or uid == saved-suid (suid = set-uid) • Return 0 upon success • Return -1 otherwise; errno=EPERM (_POSIX_SAVED_IDS) int setgid(gid_t gid); • The same as setuid
User/Group ID’s • Only superuser process can change the real uid – normally done by the login program. • The euid is set by exec only if the setuid bit is set for the program file. euid can only be set as its saved-suid or ruid. • exec copies the euid to the saved-suid (after the setting of euid if setuid bit is on).
User/Group ID’s • Example man program • man is used for displaying manual pages • The setuid bit is on for man (owner=man). • For file locking • man calls setuid(ruid) for privileged file access on some configuration file • Correct uid • Switch the euid back to man after it is done with them
Example of using setuid() • Step 1: exec tip program: • Step 2: access the required locks • Step 3: setuid(getuid()) to return to normal permission • Step 4: calling setuid(uucpuid) to change the effective user ID • Step 5: release the lock.
User/Group ID’s #include <sys/types.h> #include <unistd.h> int setreuid(uid_t ruid, uid_t euid); int setregid(uid_t rgid, uid_t egid); • Change both ruid/rgid and euid/egid. • Swapping of real and effective uids. • Good for even unprivileged users. • BSD only or BSD-compatibility library
User/Group ID’s #include <sys/types.h> #include <unistd.h> int seteuid(uid_t uid); int setegid(uid_t gid); • Change only euid/egid. • Non-superusers can only set euid=ruid or saved-setuid. • A privileged user only sets euid = uid. • It is different from setuid(uid)
User/Group ID’s superuser setreuid(ruid, euid) superuser setuid(uid) superuser seteuid(uid) • The supplementary guid’s are not affected by the setgid function. uid euid uid uid uid ruid nonsuperuser setreuid real uid effective uid saved suid nonsuperuser setreuid exec of suid nonsuperuser setuid or seteuid nonsuperuser setuid or seteuid
Interpreter Files • What is an interpreter? • A program that executes other programs, e.g., java, lisp, python, etc. • Def: a file begins with a line of the form: #! pathname [optional-argument] • E.g., “#! /bin/sh” • Implementation: • Recognition is done within the kernel • Interpreter (normally an absolute pathname) vs the interpreter files • Line-limit of the first line, e.g., 32 chars. • Program 8.10 – Page 218 • Argument list, arg pathname of execl()
#include "apue.h" #include <sys/wait.h> int main(void) { pid_t pid; if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* child */ if (execl("/home/professor/hchu/sys_prog_06/test/testinterp", "testinterp", "myarg1", "MY ARG2", (char *)0) < 0) err_sys("execl error"); } if (waitpid(pid, NULL, 0) < 0) /* parent */ err_sys("waitpid error"); exit(0); } linux1:~/sys_prog_06/test> cat testinterp #!/home/professor/hchu/sys_prog_06/test/echoarg foo linux1:~/sys_prog_06/test> fig8.20.exe argv[0]: /mnt/professor/hchu/sys_prog_06/test/echoarg argv[1]: foo argv[2]: /home/professor/hchu/sys_prog_06/test/testinterp argv[3]: myarg1 argv[4]: MY ARG2 what is the pathname of the interpreter? shifting off the argument list Examples of Interpreter & Interprted file
“awk –f myfile” lets awk read an awk program from “myfile”. Argument list: awkexample file1 FILE2 f3 (at /usr/local/bin/) #! /bin/awk –f BEGIN { for (i = 0; i < ARGC; i++) printf “ARGV[%d] = %s\n”, i, ARGV[i] exit } linux1:~/sys_prog_06/test> awkexample file1 FILENAME2 f3 ARGV[0] = awk ARGV[1] = file1 ARGV[2] = FILENAME2 ARGV[3] = f3 mapped to awk -f /home/professor/../awkexample file1 FILENAME2 f3 what if awk is replaced by echoarg? Interpreter Files
Interpreter Files • Example: Removing of “-f” $su Passwd: # mv /bin/awk /bin/awk.save # cp /home/stevens/bin/echoarg /bin/awk # suspend [1] + Stopped su $arkexample file1 FILE2 f3 argv[0]: /bin/awk argv[1]: -f argv[2]: /usr/local/bin/awkexample argv[3]: file1 argv[4]: FILE2 argv[5]: f3
Interpreter Files • Why interpreter files? • Pro: • Hide the fact that certain programs are scripts in other languages. • awkexample optional-arguments • Provide efficiency gain (shell vs. awk scripts) • What if awk script is turned into a shell script? exec twice • awk ‘BEGIN { for (i=0); i<ARGC; i++) …. }’ $* • Choices of shells -> specify in #! /bin/tcsh • Against: • Efficiency for users but at the cost of the kernel • Executable files? /bin/sh? /bin/awk?
system execute a command string from within a program #include <stdlib.h> int system(const char *cmdstring); • If cmdstring = null, return nonzero only if a command interpreter is available. • Objective: • Convenient in usage • system(“date > file; ls”); • Or write a program: call time, localtime, strftime, write, etc. • ANSI C definition system-dependent • An interface to shells
system • Implementation: fork-exec-waitpid int system(const char *cmdstring) /* version without signal handling */ { pid_t pid; int status; if (cmdstring == NULL) return(1); /* always a command processor with UNIX */ if ((pid = fork()) < 0) { status = -1; /* probably out of processes */ } else if (pid == 0) { /* child */ execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); // Why not execute the command directly? _exit(127); /* execl error */ } else { /* parent */ while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) { status = -1; /* error other than EINTR from waitpid() */ break; } } } return(status); }
system • Program 8.23 – Page 224 • Calling system() • Advantage • system() does all the error handling & signal handling. • Q: what will happen if you hits CTRL-C during the execution? • A security hole • Call system from a setuid program • Programs 8.14 & 8.15 – Page 225 • A set[ug]id program should change its uid’s back to the normal after call fork. • Not in current Linux distribution.
#include "apue.h" #include <sys/wait.h> int main(void) { int status; if ((status = system("date")) < 0) err_sys("system() error"); pr_exit(status); if ((status = system("nosuchcommand")) < 0) err_sys("system() error"); pr_exit(status); if ((status = system("who; exit 44")) < 0) err_sys("system() error"); pr_exit(status); exit(0); } linux1:~/sys_prog_06/test> fig8.23.exe ¤G 5¤ë 23 16:12:23 CST 2006 normal termination, exit status = 0 sh: nosuchcommand: command not found normal termination, exit status = 127 p92007 pts/0 2006-05-23 14:22 (epson5.epson.com.tw) r93007 pts/1 2006-05-22 17:30 (linux11.csie.ntu.edu.tw) r93007 pts/2 2006-05-22 17:30 (linux11.csie.ntu.edu.tw) normal termination, exit status = 44
system • A security hole • Call system from a setuid program • Programs 8.24 & 8.25 • A set[ug]id program should change its uid’s back to the normal after call fork. • Not in current Linux distribution.
// tsys #include "apue.h" int main(int argc, char *argv[]) { int status; if (argc < 2) err_quit("command-line argument required"); if ((status = system(argv[1])) < 0) err_sys("system() error"); pr_exit(status); exit(0); } // printuids #include "apue.h" int main(void) { printf("real uid = %d, effective uid = %d\n", getuid(), geteuid()); exit(0); } what happens if you execute the following command $ tsys printuids real uid = ? effective uid = ? $ su $ chmod u+s tsys $ tsys printuids real uid = ? effective uid = ?
Process Accounting • Accounting Information • Kept in the process table whenever a process terminates. • No records for • crashed processes and • abnormal terminated processes • Each accounting record is written into the accounting file in the order of the termination order of processes. • Q: Can we find the starting order from the accounting file?
Process Accounting • Non-POSIX standards • SVR4 & 4.3+BSD supported • accton [filename] • /var/adm/pacct or /usr/adm/acct • Linux • #include <unistd.h> int acct(const char *filename); • typedef u_short comp_t; • struct acct { • char ac_flag; /* Figure 8.26 – Page 251 */ • char ac_stat; /* termination status (core flag + signal #) */ • uid_t ac_uid; gid_t ac_gid; /* real [ug]id */ • dev_t ac_tty; /* controlling terminal */ • time_t ac_btime; /* staring calendar time (seconds) */ • comp_t ac_utime; /* user CPU time (ticks) */ • comp_t ac_stime; /* system CPU time (ticks) */ • comp_t ac_etime; /* elapsed time (ticks) */ • comp_t ac_mem; /* average memory usage */ • comp_t ac_io; /* bytes transferred (by r/w) */ • comp_t ac_rw; /* blocks read or written */ • char ac_comm[8]; /* command name: [8] for SVR4, [10] for 4.3 BSD */ • };
Process Accounting • A new record for each process (not each exec) • E.g., A execs B, then B execs C • ac_flag: AFORK is cleared. (cmd=C) • Programs 8.28 & 8.29 – Page 253-254 first child second child third child fourth child parent sleep(2) exit(2) sleep(4) abort() sleep(8) exit(0) sleep(6) kill() fork fork fork fork etime=128 execl etime=360 etime=274 stat=9 /usr/bin/dd stat=128+6 Remark: 60 ticks/sec flag=AFORK
F = result of a fork, X = killed by a signal, D = process dumped core
User Identification • How to know the login name of the user who’s running the process? #include <unistd.h> char *getlogin(void); • Fail if the process is not attached to a terminal – daemons • init, … • A user could have a multiple login names – login’s user name with the same user ID. • getpwuid, getpwnam • Function ttyname – utmp • Environment var LOGNAME (set by the login process in 4.3+BSD) – user-space data
Process Times #include <sys/times.h> clock_t times(struct tms *buf); • Timestamps: returned value from some arbitrary point in the past. • Subtract two timestamps to compute elapsed time struct tms { clock_t tms_utime; /* user CPU time */ clock_t tms_stime; /* system CPU time */ clock_t tms_cutime; /* user CPU time, terminated child */ clock_t tms_cstime; /* system CPU time terminated child */ • Program 8.30 – Page 234 • clock_t: measurement in seconds or defined in _SC_CLK_TCK
int main(int argc, char *argv[]) { int i; setbuf(stdout, NULL); for (i = 1; i < argc; i++) do_cmd(argv[i]); /* once for each command-line arg */ exit(0); } static void do_cmd(char *cmd) /* execute and time the "cmd" */ { struct tms tmsstart, tmsend; clock_t start, end; int status; printf("\ncommand: %s\n", cmd); if ((start = times(&tmsstart)) == -1) /* starting values */ err_sys("times error"); if ((status = system(cmd)) < 0) /* execute command */ err_sys("system() error"); if ((end = times(&tmsend)) == -1) /* ending values */ err_sys("times error"); pr_times(end-start, &tmsstart, &tmsend); pr_exit(status); } static void pr_times(clock_t real, struct tms *tmsstart, struct tms *tmsend) { static long clktck = 0; if (clktck == 0) /* fetch clock ticks per second first time */ if ((clktck = sysconf(_SC_CLK_TCK)) < 0) err_sys("sysconf error"); printf(" real: %7.2f\n", real / (double) clktck); printf(" user: %7.2f\n", (tmsend->tms_utime - tmsstart->tms_utime) / (double) clktck); printf(" sys: %7.2f\n", (tmsend->tms_stime - tmsstart->tms_stime) / (double) clktck); printf(" child user: %7.2f\n", (tmsend->tms_cutime - tmsstart->tms_cutime) / (double) clktck); printf(" child sys: %7.2f\n", (tmsend->tms_cstime - tmsstart->tms_cstime) / (double) clktck); } linux1:~/sys_prog_06/test> fig8.30.exe "sleep 5" "date" command: sleep 5 real: 5.01 user: 0.00 sys: 0.00 child user: 0.00 child sys: 0.00 normal termination, exit status = 0 command: date ¤G 5¤ë 23 18:37:08 CST 2006 real: 0.01 user: 0.00 sys: 0.00 child user: 0.01 child sys: 0.00 normal termination, exit status = 0