Copyright©Chi-Sheng Shih
Final for SP Spring 2011
Copyright©Chi-Sheng Shih
Final Exam
Date: June 22nd, 2011 Time: 9:10AM ~ 12:00PM Location: Rm. 102 and 104
Coverage: Ch (6), 7, 8, 10, 15.1~15.5, (15.6~7)
Copyright©Chi-Sheng Shih
Chapter 6
The purpose of having passwd and shadow The returned records are static variables, which impose certain constraint of using the related functions.
How to know the users in the systems?
Process time vs. Calendar time
Copyright©Chi-Sheng Shih
Chapter 7
How a C program is started and terminated?
C start-up routine
kernel main
function user functions
exit function
exit handler
exit handler
…
standard I/O cleanup
exec
user process
callreturn call
return
exit
(doe s not
return)
exit
(does not return)
exit
(doe s not
return)
call
return call return call return _exit
or
_Exit _exit or _Exit
_exit or _Exit
Typical Memory Arrangement
Stack
Heap
un-initialized data (bss)
initialized data text
Initialized to 0 by exec.
Read from program file by exec.
command-line arguments and environment variables.
High address
Low address
Stack
Heap
un-initialized data (bss)
initialized data
text
Frame for main() Line 9
Frame for first_function() Space for an int Space for an char Space for an void * Line 22
Frame for second_function() Space for an int
Line 29
1. #include <stdio.h>
2. void first_function(void);
3. void second_function(int);
4.5.
6. int main(void) 7. {
8. printf("hello world\n");
9. first_function();
10. printf("goodbye goodbye\n");
11.12. return 0;
13. } 14.15.
16. void first_function(void) 17. {
18. int imidate = 3;
19. char broiled = 'c';
20. void *where_prohibited = NULL;
21.22. second_function(imidate);
23. imidate = 10;
24. } 25.26.
27. void second_function(int a) 28. {
29. int b = a;
30. }
Shared Library
Why a shared library?
Remove common library routines from executable files.
Have an easy way for upgrading
Problems
More overheads: dynamic linking
Gcc:
Searches for shared libraries first.
Static linking can be forced with the -static option to gcc to avoid the use of shared libraries.
Supported by many Unix systems
Side effect for double free
Following malloc() may return the same address twice and trigger a segmentation fault.
B->fw or the first 4 bytes of B will be set to the address of A
When B is the address of a function pointer and B is evaluated to retrieve the stored function pointer, A will be returned.
Consequently, it may cause memory (buffer/heap) overflow attack.
setjmp and longjmp
#include <setjmp.h>
int setjmp(jmp_buf env);
Return 0 if called directly; otherwise, it could return a value val from longjmp().
env tends to be a global variable.
int longjmp(jmp_buf env, int val);
longjmp() unwinds the stack and affect some variables.
Program 7.4 – Page 198
setjmp and longjmp
Automatic, Register, and Volatile Variables
The compilation system tries to reduce code size and execution time on all machines, by optimizing code.
Registers in processors can be used to store variable values.
A register variable is stored in register to reduce the access time.
A volatile variable is ALWAYS read from memory.
A variable should be declared volatile whenever its value can be changed by something beyond the control of the program in which it appears, such as
a concurrently executing thread,
a variable can be modified by ISR, etc.
setjmp and longjmp
• Automatic, Register, and Volatile Variables
•
Compiler optimization•
Register variables could be in memory.•
Values are often indeterminate•
Normally no roll back on automatic and register variables•
Shown in Program 7.5 later•
Global and static variables are left alone when longjmp is executed.•
Portability Issues!setjmp and longjmp
[cshih@oris environ]$ ./testjmp in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99 after longjmp:
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99 [cshih@oris environ]$ ./testjmp.opt
in f1():
globval = 95, autoval = 96, regival = 97, volaval = 98, statval = 99 after longjmp:
globval = 95, autoval = 2, regival = 3, volaval = 98, statval = 99
Program 7.5 – Page 200
Effects of longjmp
Variables stored in memory have their values unchanged – no optimization…
Copyright©Chi-Sheng Shih
Chapter 8
Multi-processes in modern systems
Image that you are now a system architect to design a new multi-process systems.
Q1: How does the system create a new process and terminate a process?
Q2: What processes you need when the system starts?
Q3: Should you impose a communist or democratic system on your system?
Memory Management
Virtual Memory – Demand paging
File System
Swap Space Run
Swap-Out/In
Logical Memory
Memory Map (Page Table)
Physical Memory
CPU
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())
Program 8.1 – Page 212
fork
fork(), race conditions on shared files, write vs standard I/
O functions
The order of execution is in-determinate.
File sharing
Sharing of file offsets (including stdin, stdout, stderr)
Tables of Opened Files (per process)
System Open File Table
In-core i-node list
Write vs. Standard IO
[cshih@oris proc]$ ./fork1 a write to stdout
before fork
pid = 17194, glob = 7, var = 89 pid = 17193, glob = 6, var = 88
[cshih@oris proc]$ ./fork1 > temp.out [cshih@oris proc]$ cat temp.out
a write to stdout before fork
pid = 17188, glob = 7, var = 89 before fork
pid = 17187, glob = 6, var = 88
Data in output buffer are copied to child process.
Forked processes and their properties
Normal cases for handling file descriptors after 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 (exec)
Differences on properties:
Returned value from fork, process ID, parent pid, tms_[us]time, tms_c[us]time, file locks, pending alarms, pending signals
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.
Program 8.2 – Page 217
vfork,
_exit vs exit (flushing/closing of stdout)
exit() may close the file descriptors, causing printf() to fail.
A possibility of deadlock if the child waits for the parent to do something before calling exec().
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.
SIGCHLD from the kernel if a child terminates
Default action is ignoring.
main() { ...
wait();
wait();
...
return 0;
}
Parent process
Parent process is suspended.
main() { ...
return 0;
}
Child process
A signal, SIGCHILD, to wake up the parent
process.
Discussion
wait() and waitpid() are called by the parent process to retrieve the termination status of its child process.
When a parent terminates before its child process terminated?
What are the impacts to the system?
Let it be? or ask someone to adopt it?
When a child process terminates before its parent process waits for its termination status?
What are the impacts to the system?
Let it be? or keep the address space until the parent needs it?
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.
The kernel won’t be able to correctly track which return code goes with which process (unless it uses additional, complex logic.)
Trouble for Zombie
It is a good practice to wait for child and to have zombie processes.
However, when the system is creating a large number of background process, i.e., daemon process, we would like to fork a new child process but
not asking the parent process to wait for the child AND
not generating zombie process?
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.
Example: Program 8.5 – Page 225
Who is the parent of the 2nd child?
Program 8.6 – Page 229
Mixture of output by putc + setting of unbuffering for stdout
exec
#include <unistd.h>
int execlp(const char *filename, const char *arg0, … /*
(char *) 0 */);
int execvp(const char *filename, char *const argv[]);
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 file.
Example usage: login, ARG_MAX (4096) Figure 8.14 – Page 209 (6 exec functions)
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
(Inherited properties for forked process.) FD_CLOEXEC flag
Requirements & Changes
Closing of open dir streams,
Effective user/group ID: depends on the set-user-ID bit
exec
In many Unix implementations, execve is a system call.
Program 8.8 – Page 235 Program 8.9 – Page 236
The prompt bet the printing of argv[0] and argv[1].
execvp execlp
execv execl
execve execle
build argv build argv build
argv
try each PATH prefix
use environ
Use of setuid/setgid
To allow other users to access certain file when conducting certain operations.
Access passwd/shadow when a user logs in You can find it, using ‘ls’ with ‘-l’ options
An executable file can be a setuid program by adding
‘u+s’ or ‘g+s’ permission.
Examples of setuid program: passwd, login, etc.
However, executing the setuid program for a long time could cause many security problems.
During the execution, the privilege should be removed and given back only when necessary.
Copyright©Chi-Sheng Shih
Chapter 10
Handling Fresh Signals
Hardware Exception!!
User
Process P1 Set the signal flag for the target process
Check bottom_half queue
Blocked signal?
Ignored signal?
Insert the signal to pending queue
No
No
Handle signal
Software condition: kill()
Checkup at clock tick
Clear the flag
ISR()
Time
User Space Kernel Space
Handling Signals by Signal Handler
User Process P1
Signal handler
Deliver Signal
cleanup
User Space Kernel Space
interrupt!!
User Process P2
Interrupted System Calls
Traditional Approach
“Slow” system calls could be interrupted -> errno = EINTR
“Slow” System Calls (not disk I/O):
Reads from or writes to files that can block the caller
forever (e.g., pipes, terminal devices, and network devices) Opens of files (e.g., terminal device) that block until some conditions occurs.
pause, wait, certain ioctl operations Some IPC functions
Reentrant Functions
When interrupts occur, a function could be called twice and causes problems.
(Program 10.5 – Page 307) Potential Problem:
In the signal handler, we can’t tell where the process was executing when the signal was caught!
Examples: malloc, getpwnam
Occurrence Time: Anytime, e.g., by timer…
Unreliable Signals
Unreliable Signals: Signals could get lost!
Why?
The action for a signal was reset to its default each time the signal occurred.
The process could only ignore signals, instead of turning off the signals when the process is busy.
int sig_int();
…
signal(SIGINT, sig_int);
…sig_int() {
signal(SIGINT, sig_int);
… }
39 main(void) {
unsigned int unslept;
if (signal(SIGINT, sig_int) == SIG_ERR) err_sys("signal(SIGINT) error");
unslept = sleep2(5);
unsigned int
sleep2(unsigned int nsecs) {
if (signal(SIGALRM, sig_alrm) == SIG_ERR) return(nsecs);
if (setjmp(env_alrm) == 0) {
alarm(nsecs); /* start the timer */
pause();
static void
sig_alrm(int signo) {
// Do nothing }
SIGINT
static void sig_int(int signo) {
printf("\nsig_int starting\n");
for (i = 0; i < 300000; i++) for (j = 0; j < 4000; j++)
k += i * j;
SIGALRM
if (setjmp(env_alrm) == 0) {
alarm(nsecs); /* start the timer */
pause();
}
return(alarm(0));
}
i=20000
static void sig_int(int signo) {
printf("\nsig_int starting\n");
i=20001 Correct nested
signal handling
Signal Mask
Signal mask is a per process property.
Under certain circumstance, we may desire the process not to be interrupted.
For example, in the process for changing handlers, in the process for handling a delivered signal, etc.
It defines the set of signals for being blocked.
Blocked signal vs. Ignored signal:
An ignored signal will NOT be delivered to the receiving process.
A blocked signal will be queued until the receiving process is ready to process the signal or the signal is ignored.
40
sigaction
#include <signal.h>
int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
sa_mask: sigemptyset(), etc.
Figure 10.16 – sa_flags No queuing of signals
Unlike signal(), signal handlers remain!
struct sigaction {
void (*sa_handler)();
sigset_t sa_mask;
int sa_flags;
};
(including the delivered signal)
41
Changes of signal mask for sigaction
42
mask
sigpromask (SIG_SETMASK, emptyset, NULL)
sigpromask (SIG_BLOCK,
set1, NULL)
sigaction(SIGINT, act, oact) act.sa_mask=set2
SIGINT End of SIGINT handler emptyset
set1 set2 + SIGINT
SIGINT is not in set2
sigsetjmp & siglongjmp
#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int savemask);
void siglongjmp(sigjmp_buf env, int val);
sigsetjmp() saves the current signal mask of the process in env if savemask !=0.
setjmp & longjmp save/restore the signal mask:
4.3+BSD and Mac OS X, but not SVR4, Linux 2.4, and Solaris 9.
43
main() signal() signal() pr_mask() sigsetjmp()
pause()
sig_usr1 pr_mask()
alarm() time() time() time()
sig_alrm pr_mask()
return()
SIGUSR1 delivered
SIGALARM delivered
Return from signal hander
pr_mask() siglongjmp() sigsetjmp()
pr_mask() exit()
SIGUSR1
SIGUSR1 SIGARM
SIGUSR1
44
Revisit Race Condition by non-atomic functions
Recall that, race condition between alarm() and pause() may block a process forever if there is no other signals.
Similar race condition may occur between sigprocmask() and pause(), which leads to missed signals.
45 sigset_t newmask, oldmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
/* block SIGINT and save current signal mask */
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) err_sys("SIG_BLOCK error");
/* critical region of code */
/* reset signal mask, which unblocks SIGINT */
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error");
/* window is open */
pause(); /* wait for signal to occur */
/* continue processing */
A delivered signal could be
lost.
sigsuspend
#include <signal.h>
int sigsuspend(const sigset_t
*sigmask);
Set the signal mask to sigmsk and suspend until a signal is caught or until a signal occurs that terminates the process.
Return –1. errno = EINTR
The mask is restored when the function returns.
if (sigprocmask(…) < 0) err_sys(…);
pause();
CPU Scheduling could occur!
46
Changes of signal mask for sigaction
47
mask
sigpromask (SIG_BLOCK,
&newmask,
&oldmask)
SIGSUSPEND org. set
org. set + SIGINT
SIGUSR1
Critical Section
SIGUSR2 SIGUSR1 +
SIGUSR2
sigprocmask (SIG_SETMASK,
&oldmask, ..) return of
SIGSUSPEND
Copyright©Chi-Sheng Shih
Chapter 15
Pipes
Pipes have two limitations:
They are half-duplex.
They can be used between processes that have a common ancestor.
Stream pipes are duplex and named stream pipes can be used between processes not having the same ancestor.
pipe function
! #include <unistd.h>
! int pipe( int filedes[2] );
FIFOs
FIFOs – named pipes for (un-)related processes to exchange data.
A file type – st_mode (S_ISFIFO macro)
Data in a FIFO removed when the last referencing process terminates.
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
mode and usr/grp ownership = those of a file Op’s: open, close, read, write, unlink, etc.
Message Queues
Message Queue or Queue
A linked list of messages stored within the kernel and with a queue ID
struct msqid_ds {
struct ipc_perm msg_perm;
ulong msg_qnum; /* # of msgs */
ulong msg_qbytes; /* max # of bytes */
pid_t msg_lspid; /* pid of the last msgsnd() */
pid_t msg_lrpid; /* pid of the last msgrcv() */
time_t msg_stime; /* the last msgsnd() time */
time_t msg_rtime; /* the last msgrcv() time */
time_t msg_ctime; /* last change time */
}
• Msgs could be fetched based on their type field.