系統程式 朱浩華教授/施吉昇教授 臺灣大學資訊工程系 Tei-Wei Kuo, Chi-Sheng Shih, and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Contents 1. Preface/Introduction 2. Standardization and Implementation 3. File I/O 4. Standard I/O Library 5. Files and Directories 6. System Data Files and Information 7. Environment of a Unix Process 8. Process Control 9. Signals 10. Inter-process Communication Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Multi-processes in modern systems Image that you are now a system architect to design a new multi-process systems. Q1: How does the systems create a new process and terminate a process? Q2: What processes you need when the system starts? Q2: Should you impose a communist or democratic system on your system? Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Process Control Special Processes PID 0 – Swapper (I.e., the scheduler) Kernel process No program on disks correspond to this process PID 1 – init responsible for bringing up a Unix system after the kernel has been bootstrapped. (/etc/rc* & init or /sbin/rc* & init) User process with superuser privileges PID 2 - pagedaemon responsible for paging Kernel process Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Memory Management Virtual Memory – Demand paging Logical Memory Memory Map (Page Table) Physical Memory File System Run CPU Swap-Out/In Swap Space Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Memory Management Virtual Memory – Demand paging Memory TLB File System Run CPU MMU Logical Address Physical Address Swap-Out Swap Space Page Table Swap-In Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Memory Management Demand Paging Page fault -> disk I/O -> modify the page table -> rerun the instruction! Logical Address P Physical Address D F P Memory D F Page Table page fault disk I/O File System / Swap Space Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Process Control #include <sys/types.h> #include <unistd.h> pid_t getpid(void); pid_t getppid(void); uid_t getuid(void); uid_t geteuid(void); gid_t getgid(void); gid_t getegid(void); None of them has an error return. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Discussion How can your systems have multiple processes? Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University What’s a Fork() Parent If ((pid=fork()) == 0){ { … } else { } exit(0); Child fork() if ((pid=fork() == 0){ { … } else { } exit(0); Child is an exact copy of the parent process. They have their own memory space. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University fork #include <sys/types.h> #include <unistd.h> pid_t fork(void); The only way beside the bootstrap process to create a new process. Call once but return twice 0 for the child process (getppid) Child pid for the parent (1:n) Copies of almost everything but no sharing of memory, except text Copy-on-write (fork() – exec()) Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University fork Program 8.1 – Page 212 fork(), race conditions, write vs standard I/O functions File sharing Sharing of file offesets (including stdin, stdout, stderr) Tables of Opened Files (per process) System Open File Table In-core i-node list Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University fork Normal cases in fork: The parent waits for the child to complete. The parent and child each go their own way (e.g., network servers). Inherited properties: Real/effective [ug]id, supplementary gid, process group ID, session ID, controlling terminal, set[ug]id flag, current working dir, root dir, file-mode creation mask, signal mask & dispositions, FD_CLOEXEC flags, environment, attached shared memory segments, resource limits Differences on properties: Returned value from fork, process ID, parent pid, tms_[us]time, tms_c[us]time, file locks, pending alarms, pending signals Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University fork Reasons for fork to fail Too many processes in the system The total number of processes for the real uid exceeds the limit CHILD_MAX Usages of fork Duplicate a process to run different sections of code Network servers Want to run a different program shells (spawn = fork+exec) Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University vfork Design Objective An optimization on performance Execute exec right after returns from fork. Mechanism – SVR4 & 4.3+BSD Since 4BSD <vfork.h> in some systems No fully copying of the parent’s address space into the child. Sharing of address space Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University vfork vfork() is as the same as fork() except The child runs in the address space of its parent. The parent waits until the child calls exit or exec. Child process always executes first. A possibility of deadlock if the child waits for the parent to do something before calling exec(). Program 8.2 – Page 217 vfork, _exit vs exit (flushing/closing of stdout) exit() may close the file descriptors, causing printf() to fail. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Deadlock – One Example Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Process Termination Eight ways to terminate: Normal termination Return from main() exit(main(argc, argv)); Call exit() Call _exit() or _Exit() Return of the last thread from its start routine Calling pthread_exit from the last thread. Abnormal termination (Chapter 10) Call abort() Be terminated by a signal Response of the last thread to a cancellation request. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University exit Termination The same code in the kernel is finally executed. Close all open descriptors, release memory, and the like. Exit status vs. termination status Exit status (arg from exit, _exit, or return) termination status In abnormal case, the kernel generates it. wait & waitpid to retrieve the termination status. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Restarting point Tei-Wei Kuo, Chi-Sheng Shih, and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Annoucements Midterm exam scores are out Average: 68.1 Std. Dev: 20.35 MP3 is out today Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Fun project #1 Hyperdragging (1999) Dragging into the physical space Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Fun project #2 Diamond touch (2005) Lay display flat on the table, and interactions get interesting … Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Discussion wait() and waitpid() are called by the parent process to retrieve the termination status of its child process. Questions: How to use these functions? What if the child processes terminate before wait() and waitpid() are called? Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University wait & waitpid #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *statloc); pid_t waitpid(pid_t pid, int *statloc, int op); wait will block until one child terminates or an error could be returned. waitpid could wait for a specific one and has an option not to be blocked. SIGCHILD from the kernel if a child terminates Default action is ignoring. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University wait & waitpid Three situations in calling wait/waitpid Block Return with the termination status of a child Return with an error. Termination Status <sys/wait.h> – Figure 8.4 Access termination status through the following MACROs Exit status (WIFEXITED, WEXITSTATUS) WIFEXITED(status): if successfully exited (true/false) WEXITSTATUS(status): exit code Signal # (WIFSIGNALED, WTERMSIG) Core dump (WCOREDUMP) Others (WIFSTOPPED, WSTOPSIG) Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Program 8.5 – Page 222 void pr_exit(int status) { if (WIFEXITED(status)) printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) printf("abnormal termination, signal number = %d%s\n", WTERMSIG(status), #ifdef WCOREDUMP WCOREDUMP(status) ? " (core file generated)" : ""); #else ""); #endif else if (WIFSTOPPED(status)) printf("child stopped, signal number = %d\n", WSTOPSIG(status)); } linux1:~/sys_prog_06/test> fig.8.6.exe normal termination, exit status = 7 abnormal termination, signal number = 6 abnormal termination, signal number = 8 if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) exit(7); if (wait(&status) != pid) err_sys("wait error"); pr_exit(status); if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) abort(); */ if (wait(&status) != pid) err_sys("wait error"); pr_exit(status); if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) status /= 0; SIGFPE */ if (wait(&status) != pid) err_sys("wait error"); pr_exit(status); /* child */ /* wait for child */ /* and print its status */ /* child */ /* generates SIGABRT /* wait for child */ /* and print its status */ /* child */ /* divide by 0 generates /* wait for child */ /* and print its status */ Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Zombie process zombie The process has terminated, but its parent has not yet waited for it. It keeps the minimal information for the parent process. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University How is a Zombie process created? Parent If (pid=fork() == 0){ { … Child fork() If (pid=fork() == 0){ { … exit(0); } else { // parent’s code exit(0); } else { // parent’s code } } We get a zombie!! Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Cleaning up Zombies What if the parent process terminates before the child process? Inherited by init When a parent terminates, it is done by the kernel. Clean up of the zombies by the init – wait whenever needed! Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Discussion: why do we need zombie? A parent process can end up with two different children that share the same PID. A parent process can end up trying to wait for the return code of another process’s child. If child process completely disappear, its parent process won’t be able to wait on & fetch its termination status. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University wait & waitpid pid_t waitpid(pid_t pid, int *statloc, int op); pid pid == -1 wait for any child pid > 0 wait for the child with pid pid == 0 wait for any child with the same group id pid < -1 wait for any child with the group ID = |pid| return pid of the child 0 if WNOHANG flag is set & the specified pid does not exit -1 an error is returned -> how can an error occur? Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University wait & waitpid Errors No such child or wrong parent Option for waitpid WNOHANG, WUNTRACED WNOWAIT, WCONTINUED (SVR4) Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Troubles from Zombie Although Zombie processes do not occupy any memory space in the system, it consumes process IDs, which are limited resources too. You may not be able to fork new child processes when there are too many zombie processes in the systems. CHILD_MAX: max number of simultaneous processes per real user ID How to fork a new child process but not asking the parent process to wait for the child AND not generating zombie process? Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University How to create a background process without making a zombie? Parent if (pid1=fork() == 0){ { if (pid2=fork() == 0) { } else exit(0); } else waitpid(pid1, NULL, 0) exit(0); Child if (pid1=fork() == 0){ { if (pid2=fork() == 0) { } else exit(0); } else exit(0); Grandchild if (pid1=fork() == 0){ { if (pid2=fork() == 0) { sleep(2); // grandchild exec } else exit(0); } else exit(0); Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University waitid #include <sys/wait.h> pid_t waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); Defined in XSI extension Similar to waitpid() but provide extra info. idtype: P_PID: wait for a particular process P_PGID: wait for a group of process P_ALL: wait for any child process options: WCONTINUED WNOHANG WSTOPPED WNOWAIT: the exit status will be kept for other wait() functions. WEXITED Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University wait3 & wait4 – resource usage info #include <sys/types.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> pid_t wait3(int *statloc, int op, struct rusage *rusage); pid_t wait4(pid_t pid, int *statloc, int op, struct rusage *rusage); 4.3+BSD – Figure 8.4, Page 203 User/system CPU time, # of page faults, # of signals received, the like. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Race Conditions Def: When multiple processes are trying to do something with shared data, the final outcome depends on the order in which the processes run. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Race condition example A is the number of available copies of a book = 1. Two processes (transactions) running concurrently. Race between T1 & T2! T1 wants to buy one copy. T2 wants to buy one copy. T1 gets an error. T1 R(A=1) Check if (A>0) The result is different from any serial schedule T1,T2 or T2,T1 W(A=0) Error! How to solve this? T2 R(A=1) Check if (A>0) W(A=0) Locking mechanism Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Another race condition example Situation: T2 reads an object that has been modified by T1, but T1 has not committed. T1 transfers $100 from A to B. T2 adds 6% interests to A and B. A nonserializable schedule is: T1 R(A) W(A-100) R(A) W(A+6%) Step 1: deduct $100 from A. Step 2: add 6% interest to A & B. Step 3: credit $100 in B. R(B) W(B+6%) Why is the problem? The result differs based on different order of execution The result differs from any serial schedule > Bank adds $6 less interest. T2 Commit R(B) W(B+100) Commit Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Race Conditions Example: Program 8.8 – Page 225 Who is the parent of the 2nd child? Program 8.12 – Page 229 Mixture of output by putc + setting of unbuffering for stdout Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Can you spot the potential race condition? (avoid zombie processes by calling fork twice) if (waitpid(pid, NULL, 0) != pid) /* wait for first child */ err_sys("waitpid error"); int main(void) { pid_t pid; /* * We're the parent (the original process); we continue executing, * knowing that we're not the parent of the second child. */ exit(0); if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* first child */ if ((pid = fork()) < 0) err_sys("fork error"); else if (pid > 0) exit(0); /* parent from second fork == first child */ } /* * We're the second child; our parent becomes init as soon * as our real parent calls exit() in the statement above. * Here's where we'd continue executing, knowing that when * we're done, init will reap our status. */ sleep(2); printf("second child, parent pid = %d\n", getppid()); exit(0); } What if the 2nd child exit before the 1st child called exit(0)? - parent of 2nd child is not init by the 1st child. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Race Conditions How to synchronize parent and child processes? Busy wait? while (getppid() != 1) sleep(1); Waste CPU time, other means possible: InterProcess Communication facility, such as pipe fifo, semaphore, shared memory, etc. Program 8.13 on Page 206 WAIT_PARENT(), TELL_CHILD(), WAIT_CHILD(), TELL_PARENT() Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Can you spot the potential race condition? (avoid zombie processes by calling fork twice) if (waitpid(pid, NULL, 0) != pid) /* wait for first child */ err_sys("waitpid error"); int main(void) { pid_t pid; /* * We're the parent (the original process); we continue executing, * knowing that we're not the parent of the second child. */ exit(0); if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* first child */ if ((pid = fork()) < 0) err_sys("fork error"); else if (pid > 0) exit(0); /* parent from second fork == first child */ } /* * We're the second child; our parent becomes init as soon * as our real parent calls exit() in the statement above. * Here's where we'd continue executing, knowing that when * we're done, init will reap our status. */ sleep(2); printf("second child, parent pid = %d\n", getppid()); while (getppid() != 1) sleep(1); exit(0); What if the 2nd child exit before the 1st child called exit(0)? - parent of 2nd child is not init by the 1st child. } Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Can you spot the potential race condition? Program 8.12 on page 229 $ ./a.out ooutput from child utput from parent static void charatatime(char *); int main(void) { pid_t pid; if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { charatatime("output from child\n"); } else { charatatime("output from parent\n"); } exit(0); $ ./a.out output from child output from parent } static void charatatime(char *str) { char *ptr; int c; setbuf(stdout, NULL); for (ptr = str; (c = *ptr++) != 0; ) putc(c, stdout); /* set unbuffered */ } Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Avoid race condition #include <sys/types.h> #include "ourhdr.h" static void charatatime(char *); int main(void) { pid_t pid; TELL_WAIT(); if ( (pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) { WAIT_PARENT(); // parent goes first charatatime("output from child\n"); } else { charatatime("output from parent\n"); TELL_CHILD(pid); } exit(0); } static void charatatime(char *str) { … … Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering } Graduate institute of Multimedia and Networking, National Taiwan University exec (6 variations) Replace the text, data, heap, and stack segments of a process with a program! Specify: new program, command line args, environment #include <unistd.h> int execl(const char *pathname, const char *arg0, … /* (char *) 0 */); int execv(const char *pathname, char *const argv[]); int execle(const char *pathname, const char *arg0, … /* (char *) 0, char *const envp[] */); int execve(const char *pathname, char *const argv[], char *const envp[]); int execlp(const char *filename, const char *arg0, … /* (char *) 0 */); int execvp(const char *filename, char *const argv[]); What do l, v, e, and p stand for? What one is the most general one? Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University exec l, v, and e stands for list, vector, and environment, respectively. command-line arg must end with null pointer Limit on # of command line args: ARG_MAX With p, a filename is specified unless it contains ‘/’. PATH=/bin:/usr/bin:. /bin/sh is invoked with “filename” if the file is not a machine executable. When do you want to change environ parameters? login process Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University exec Inherited from the calling process: pid, ppid, real [ug]id, supplementary gid, proc gid, session id, controlling terminal, time left until alarm clock, current working dir, root dir, file mode creation mask, file locks, proc signal mask, pending signals, resource limits, tms_[us]time, tms_cutime, tms_ustime FD_CLOEXEC flag Requirement Closing of open dir streams May change: effective user/group ID if new program has set-uidID bit set Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University exec execlp execl build argv build argv execvp execle try each PATH prefix execv use environ build argv execve In many Unix implementations, execve() is a system call, other exec are library functions calling execve(). Program 8.8 – Page 235 Program 8.9 – Page 236 The prompt bet the printing of argv[0] and argv[1]. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University exec example char *env_init[] = { "USER=unknown", "PATH=/tmp", NULL }; int main(void) { pid_t pid; if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* specify pathname, specify environment */ if (execle("/mnt/professor/hchu/sys_p rog_06/test/fig8.17.exe", "echoall", "myarg1", "MY ARG2", (char *)0, env_init) < 0) err_sys("execle error"); } if (waitpid(pid, NULL, 0) < 0) err_sys("wait error"); if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* specify filename, inherit environment */ if (execlp("fig8.17.exe", "echoall", "only 1 arg", (char *)0) < 0) err_sys("execlp error"); linux1:~/sys_prog_06/test> fig8.16.exe argv[0]: echoall argv[1]: myarg1 argv[2]: MY ARG2 USER=unknown PATH=/tmp linux1:~/sys_prog_06/test> argv[0]: echoall argv[1]: only 1 arg USER=hchu LOGNAME=hchu HOME=/home/professor/hchu PATH=/usr/bin:/bin:/usr/X11R6/bin:/opt/kde/bin:. MAIL=/var/mail/hchu SHELL=/bin/tcsh SSH_CLIENT=140.112.30.82 46314 22 SSH_CONNECTION=140.112.30.82 46314 140.112.30.32 22 SSH_TTY=/dev/pts/5 TERM=xterm DISPLAY=localhost:10.0 LANG=zh_TW.Big5 HOSTTYPE=i486-linux VENDOR=intel OSTYPE=linux MACHTYPE=i486 SHLVL=1 PWD=/home/professor/hchu/sys_prog_06/test GROUP=users HOST=linux1 REMOTEHOST=dhcp1.csie.ntu.edu.tw LC_ALL=zh_TW.Big5 } exit(0); } Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University program 8.17 #include "apue.h" int main(int argc, char *argv[]) { int i; char **ptr; extern char **environ; for (i = 0; i < argc; i++) /* echo all command-line args */ printf("argv[%d]: %s\n", i, argv[i]); for (ptr = environ; *ptr != 0; ptr++) /* and all env strings */ printf("%s\n", *ptr); exit(0); } Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University 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 Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University 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) Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University 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 Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University 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). Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University 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 Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University Example of using setuid() Real user ID = Our user ID Step 1: exec tip program: Effective user ID = man Saved-set-user ID = man 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 Real user ID = Our user ID Effective user ID = Our user ID Saved-set-user ID = man Real user ID = Our user ID Effective user ID = Man Saved-set-user ID = man Step 5: release the lock. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University 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 Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University 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 savedsetuid. A privileged user only sets euid = uid. It is different from setuid(uid) Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University User/Group ID’s superuser setreuid(ruid, euid) euid ruid real uid superuser setuid(uid) uid nonsuperuser setreuid nonsuperuser setuid or seteuid superuser seteuid(uid) uid uid effective uid nonsuperuser setreuid uid saved suid exec of suid nonsuperuser setuid or seteuid The supplementary guid’s are not affected by the setgid function. Tei-Wei Kuo, Chi-Sheng Shih and Hao-Hua Chu©2006 Department of Computer Science and Information Engineering Graduate institute of Multimedia and Networking, National Taiwan University