Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security Exercise 2: Process-, Memory- and IO-Management Introduction In order to manage the system resources of a computer the control structure of an operating system (OS) is based on four entities: memory, processes, files and I/O. For managing these entities the OS constructs and maintains tables of information about each of them. In the following we provide an introduction, which should help to solve the tasks given below. The most requirements an OS has to fulfill are related to processes. Hence the management of processes is the fundamental task of OSs. The OS is responsible for scheduling and dispatching processes for execution by the processor, allocating resources to processes and responding to requests of user processes. The aim of process management is the efficient management of programs that are executed at the same time. Since a processor can only execute one process at a time, this is achieved by switching the CPU between multiple processes that are interrupted and resumed according to their priority. A process is definded as a ’program in execution’ or in other words ’a unit of activity characterized by the execution of a sequence of instruction, a current state, and an associated set of system resources’. There are three elements characterizing a process: program code, associated data and a process control block (PCB). The process control block is a data structure storing information that allows to uniquely characterize a process. This includes a unique identifier, state, priority, a program counter, memory pointers, context data, I/O status information and accounting information. The data structure of PCBs is the key tool that enables the OS to provide multiprocessing, because it covers all necessary information to interrupt a running process and later resume execution as if the interruption did not occurr. Since the information in a PCB is critical for the security of an OS, they must be kept in an area of memory that is protected from normal user access. However, usually each process has its own memory address space that is protected from the access of other processes. Between processes exists a parent/child relationship. A process can have multiple child processes but points to only one parent process. The very first process, called init in UNIX, is started by the kernel at boot time and never terminates. As the creation of a process is usually caused by the user or an application, it can also be useful to let one process (parent process) create another (child process) that runs in parallel. This action is referred to as process spawning. Here, communication and cooperation of processes become important. Enabling processes to share and exchange information, protecting resources of each process from other processes and enabling syn- 1 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security chronization among processes represent difficult, security-related activities. Many OS support threads as a further concept for managing task execution. By introducing threads, processes become more complex as presented so far. In general, a process contains at least one but may also contain multiple threads, that can be executed independently but share the process’ resources. Operating systems which support multiple threads within a single process are referred to as multithreaded environments. In these systems the processor does not only switch between different processes, but also between different threads. Processes are typically independent, have separate address spaces (at least if no explicit methods are used, which require the intervention of the kernel) and only interact through system-provided inter-process communication mechanisms (IPC). Instead, threads within the same process share memory and files and can communicate with each other without invoking the kernel. Thus, threads are able to access the same datastructures without the need of further IPC. But the main advantage over processes is the better performance of threads. Creation and termination of threads takes less time and also switching between two threads within the same process. Thus, the concept of threads is not only beneficial for multiprocessor systems. This comes with the cost of more complex code1 which is much more difficult to debug and hence more vulnerable to race-conditions and other security-related bugs. 0.1. Brief Introduction into the Python Programming Language As the practical assignment requires coding work in python, this subsection aims to give a very short introducing into the necessary parts of Python. (For a complete reference, see the Python language reference [3].) Wikipedia [1] describes pythons design philosophy as: it “emphasizes programmer productivity and code readability. Python’s core syntax and semantics are minimalistic, while the standard library is large and comprehensive” and as the syntax is minimalistic, it should be easy enough to learn even if you don’t have any experiences before. For a more complete introduction into the python programming language, see the Python tutorial [2]. 0.1.1. Python-syntax Preamble Every python file should let the system know which interpreter should be used to execute this script. While on Windows (and DOS), this is traditionally done by the file extension, on UNIX systems it is done by the first row of the file. If it contains a “she-bang” (the combination #!) followed by a path to the interpreter and is executable, the operating system will try to start the interpreter with the script as a parameter. A typical python preamble would be: 1 #! / u s r / b i n / python 1 a programmer has to care about locking/unlocking of each part another thread may access 2 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security Statements: Python code usually has one statement per line. A statement may be followed by a semicolon, but a simple newline is sufficient, so the semicolon may (and in most cases is) omitted. Comments: In Python, everything in a line following a # is treated as a comment. Thus, the preamble in the last paragraph is interpreted as a comment by the interpreter, too. As described before, it is not ignored by the system. Example: 1 #! / u s r / b i n / python 2 3 #t h i s i s a comment 4 5 print ”huhu” # t h i s i s a comment too , b u t not t h e p r i n t ! print: The built in command print can be used, to print something to the standardoutput (stdout) followed by a newline. It is used in the previous section, thus the script in the previous section would print out “huhu” onto the standard-console. formatted print: Python’s print offers functionality similar to printf. The format string is followed by a %-character and a tuple of parameters. An example should illustrate this: 1 #! / u s r / b i n / python 2 3 t e m p e r a t u r e = 10 4 conditions = ” fine ” 5 6 print ” Weather today : i t i s %d d e g r e e s c e l s i u s , t h e c o n d i t i o n s a r e %s ” % ( temperature , c o n d i t i o n s ) import: The import statement is used to include other “modules”, comparable to library. Functions of the module can be accessed after importing by the <modulename>.prefix. Library-functions important for the assignments are described in section 0.1.2. An example for import is this: 1 #! / u s r / b i n / python 2 3 import s y s #t h i s i m p o r t s t h e ‘ ‘ s y s ’ ’ − module 4 5 s y s . s t d o u t . w r i t e ( ”huhu\n” ) 6 #d o e s t h e same as t h e p r i n t s t a t e m e n t a bo ve 3 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security Variables and Data Types: Though python is a strong typed language, it uses dynamic typing. Variables must not be declared, but can directly be assigned and take the type of the assignment. Assignments are done by the = operator. Example: 1 #! / u s r / b i n / python 2 3 var = ” have you mooed today ? ” #t h i s i s a s t r i n g o b j e c t 4 var2 = 42 #i n t e g e r o b j e c t 5 var3 = E x c e p t i o n ( ) #new o b j e c t o f t y p e ” E x c e p t i o n ” 6 var2 = var #v ar2 i s now a s t r i n g o b j e c t , t o o Operators on Variables: In python, every data type is a class, thus every variable (and even static values) represents an object. The operators are defined by special functions of that object, for example: var = 1 + 2 is the same as var = 1. add (2). As you can see, the meaning of the operator can be different depending on the object type you use it with. For standard number objects, this works as expected, for string-types (and arrays, tuples, etc) the + operator does concatenation. You can redefine the meaning of the operator (“operator overloading”) by creating a new class for example with another add function. This could be useful if you want to implement matrix classes and + should be the matrix addition, * should be the matrixmultiplication and / should be the matrix inversion. It is obvious that the types of the classes must be compatible. It does not make sense to add a string to an integer. However, sometimes you want to concatenate the string representation of an integer to a string. This isn’t possible directly (as the object types aren’t compatible), the non-string object must be converted to its string representation first. This can be done by the str function. Consider this example: 1 #! / u s r / b i n / python 2 3 var = ” have you mooed today ?\ nyes , ” 4 var2 = ” t i m e s ” 5 var3 = 5 6 7 print var + var3 . s t r ( ) + var2 8 print var + 7 . s t r ( ) + var2 Standard Classes: Integer An integer number. Float A floating-point number. String The purpose of string is obvious. It can be accessed as string or as an array of characters. Single characters can be accessed with st[5], substrings with st[5:8]. 4 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security Tuple A tuple is a set of objects (components), bound to a single name. The set is enclosed by parenthesis and its components are separated by comma. The components can be accessed by brackets. Example: 1 #! / u s r / b i n / python 2 3 i = 5 4 s t = ” t h e l a z y dog jumps o v e r t h e . . . ” 5 pi = 3.1415947 6 7 tuple = ( i , st , pi ) 8 9 print t u p l e [ 2 ] #p r i n t s o u t p i Once assigned, it is not longer possible to change components. This is a major restriction but gives a serious performance-boost. Array An array is a set of objects (components) bound to a single name. The set is enclosed by brackets and its components are separated by comma. Components can be accessed like tuple-components. Example: 1 #! / u s r / b i n / python 2 3 i = 5 4 s t = ” t h e l a z y dog jumps o v e r t h e . . . ” 5 pi = 3.1415947 6 roundpi = 3 7 8 array = [ i , st , pi ] 9 10 print a r r a y [ 2 ] 11 a r r a y [ 2 ] = r o u n d p i 12 print a r r a y [ 2 ] Dictionary A dictionary is a set of key-value pairs. It manages relations between key and value of a set of objects (components). The set is defined in the format: key: value,... and is enclosed by brackets. Components are accessed by their designated key. Example: #!/ u s r / b i n / python d i c t i o n a r y = {” p i ” : 3 . 1 4 1 5 9 4 7 , ” s t ” : ” t h e l a z y dog jumps over the . . . ” , ” i ”:5} 5 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security print dictionary [” pi ”] Defining and Calling Functions: Functions are defined by two parts: a signature and a function block. The signature consists of the def keyword, followed by a bracket, a list of parameter names (possible with default values), a bracket and a colon. It is followed by the function block which is a set of statements. A function is called by function name, argument list separated by commas. If no arguments are given, the brackets are still required! Blocks: Unlike most other languages, python does not use parentheses to define block starts and block ends. Blocks are entirely defined by indention2 , thus indention is very important in python. Consider the following example: 1 #! / u s r / b i n / python 2 3 parameter = ” oink , o i n k ” 4 5 def f u n c ( parameter , parameter2 = ” t e s t ” ) : 6 print parameter2 7 print parameter 8 9 f u n c ( ” o p e r a t i n g system s e c u r i t y r o c k s ! ” ) It gives the output: test o p e r a t i n g system s e c u r i t y r o c k s ! While this: 1 #! / u s r / b i n / python 2 3 parameter = ” oink , o i n k ” 4 5 def f u n c ( parameter , parameter2 = ” t e s t ” ) : 6 print parameter2 7 print parameter #n o t e t h a t t h i s s t a t e m e n t i s not l o n g e r indented . 8 9 f u n c ( ” o p e r a t i n g system s e c u r i t y r o c k s ! ” ) gives: 2 usual coding-convention defines 4 spaces for indention 6 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security test oink , o i n k Returning Values from Functions: A function can return an object. This is done by the return-statement. After the return-statement, the program-flow leaves the function and returns to the calling statement. Example: 1 2 3 4 5 6 7 8 #! / u s r / b i n / python def f u n c ( ) : print ” i am a f u n c t i o n ! ” return ”Have you mooed today ? ” x = func ( ) print x gives i am a f u n c t i o n ! Have you mooed today ? Conditional Code Sometimes you need conditional codes. The most important example of conditional code in python is the if statement, possibly followed by an elif (shorthand for else if) and/or an else-statement. The exact syntax is best shown in an example: 1 #! / u s r / b i n / python 2 3 x = 1 4 5 i f x == 1 : 6 print ” f i r s t b l o c k : ” 7 print ”x = 1 ” 8 elif x > 1: 9 print ” s e c o n d b l o c k : ” 10 print ”x > 1 ” 11 e l s e : 12 print ” t h i r d b l o c k : ” 13 print ”x < 1 ” Loops: Python has two different types of loops: 7 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security for-in-loop: The for in loop is a loop that iterates through objects. Important iterable objects are strings, arrays, tuples and dictionaries. An example of a for in loop is: 1 #! / u s r / b i n / python 2 3 x = ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ) # t u p l e w i t h 10 numbers 4 5 for i in x : # i t e r a t e s o v e r e v e r y component o f t h e t u p l e . . . 6 print ” l o o p i n g . . . ” 7 print i while-loop: The Python while loop is a classical while-loop. It works as the following: 1 #! / u s r / b i n / python 2 3 x = 100 4 5 while x > 0 : 6 print x 7 print x −= 1 # e q u a l t o x = x − 1 range([start], stop, [step]), xrange([start], stop, [range]): The range/xrange-function is a built in function, that generates iterable objects containing integer-ranges of numbers. Calling is quite obvious. Start is the start value (the first number in the range) (0 if omitted), stop (the first number not in the range) is the stop value (cannot be omitted), step defines the interval between the numbers (1 if omitted, must be an integer value). The difference between range and xrange is that range returns a tuple, while xrange returns an iterable function. Thus, if you do range(10000000000), your tuple takes quite some time to generate and uses large amounts of memory, while xrange(10000000000) just returns an iterable object. While this is different, both works equivalent in for-loops. Example: 1 #! / u s r / b i n / python 2 3 x = range ( 0 , 4 , 2 ) 4 for i in x : 5 print i gives 0 2 8 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security 0.1.2. Python Modules This part introduces some additional functions that should enable you to complete your assignment. Additional informations of these functions are given in the appendix. A complete documentation of the standard library of modules is the Python library reference [4]. os: The os-module provides the interface to the operating-system. It provides wrappers to syscalls (like fork) and other advanced operating system functions (like directory working). os.fork: This is the python-implementation of the fork syscall. It creates a new process clone and runs it independently. It returns 0 to the child process, and the pid of the child to the parent process. It is called via the os. prefix of the module and the name of the function + brackets (i.e. os.fork()). It takes no arguments! os.wait: This is the python implementation of the wait syscall. It waits for a child process to exit and retrieves it’s exit status. It takes no arguments! os.getpid: This function retrieves the current process-id of the process calling from the system. Example: 1 #! / u s r / b i n / python 2 import o s 3 4 pid = os . getpid ( ) 5 print p i d os.system: - system(param-string): The system call starts the default shell and lets it execute the parameter-string. An example should make this clear: 1 #! / u s r / b i n / python 2 3 import o s 4 5 o s . system ( ” echo t h i s i s a t e s t > f i l e ” ) 6 o s . system ( ” c a t f i l e ” ) 7 o s . system ( ”rm f i l e ” ) It does the following: First creates a “file” named “file” and echos “this is a test” in it, then prints out the contents of the “file” using the cat command and finally removes the “file” with the rm command. time: The time module provides an interface to all time-related functions of the system. For instance it converts different time formats. 9 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security time.sleep: This function is the only function of the time module relevant for this assignment. The signature is: sleep(secs). It stops the program flow for secs seconds. 0.1.3. How to Write and Execute Python Scripts Python scripts can either be written in any texteditor or directly tested in the python shell. Write scripts with a text-editor: Open your favorite texteditor (for example kate [5]) and write the script. Make sure not to forget the preamble 0.1.1. After saving the script, you must mark it executable by executing chmod +x <filename>. Now you can execute it with ./<filename> in the directory you saved the script. Test in the Python-shell: Type python on the shell. It should give you something like: Python 2 . 5 . 2 ( r 2 5 2 : 6 0 9 1 1 , Oct 7 2 0 0 8 , 1 2 : 4 5 : 4 9 ) [GCC 4 . 3 . 1 ] on l i n u x 2 Type ” h e l p ” , ” c o p y r i g h t ” , ” c r e d i t s ” o r ” l i c e n s e ” f o r more information . >>> You can type your statements into the console. Single statements are evaluated after typing enter, blocks are evaluated after finishing the statement. You can exit the shell with the exit() statement. Example: immo@wok ˜ $ python Python 2 . 5 . 2 ( r 2 5 2 : 6 0 9 1 1 , Oct 7 2 0 0 8 , 1 2 : 4 5 : 4 9 ) [GCC 4 . 3 . 1 ] on l i n u x 2 Type ” h e l p ” , ” c o p y r i g h t ” , ” c r e d i t s ” o r ” l i c e n s e ” f o r more information . >>> f o r i i n r a n g e ( 1 , 5 ) : #range−f u n c t i o n r e t u r n s t u p l e (1 ,2 ,3 ,4 ,5) ... print i ... 1 2 3 4 >>> e x i t ( ) immo@wok ˜ $ 10 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security 1. Theoretical assignments: 1.1. Python-Questions ( π1 Points) You should be able to answer all of these questions before starting the practical exercises. Use to disambiguate the indention! 1. How do you define a tuple? 2. Whats the difference between an array and a dictionary? 3. Implement (on paper) a small Python-script, that prints out your name! 4. Implement (on paper) a small Python-script, that counts from 0 to 10. Use a forloop, conditional code and the range-function! The output should be the following: 0 is 1 2 3 is 4 5 6 is 7 8 9 is 10 0 mod 3 0 mod 3 0 mod 3 0 mod 3 5. You have an integer-variable r, containing a random number. Give two possible print-statements to print “our random number is -insert content of the random number here-” 1.2. Process-Management (1/2 Point) 1. What is a process? 2. Why does someone want multiple processes? Give examples! 3. What information about processes are necessary for the OS to manage them? 4. What is the difference between processes and threads? 5. Consider the following python-code: 1 #! / u s r / b i n / python 2 3 import os , time 11 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security 4 n=5 5 6 fo r i in xrange ( n ) : 7 os . f o r k ( ) 8 9 time . s l e e p ( 1 0 0 ) a) How many processes will sleep in line 9? b) How many processes will sleep in line 9 if n would be 10? c) Develop a formula for calculating the number of processes for all n ∈ N. Explain the formula! 1.3. Memory Management (1 Point) 1. What is swapping and what is its purpose? 2. Explain the paging-mechanism. 3. Explain why it is a security-problem if some user has read-access to the swapfile! 4. Why can it also be a problem if some user has write-access? 5. Why do OS use virtual addressing? 6. Describe the process-memory-layout on a general x86-system. 7. Where is the stack and what is the stack used for? 8. What is the heap, what does the heap? 9. Consider the following source-code: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <s t r i n g . h> #include <s t d i n t . h> #include < s t d l i b . h> int f u n c ( char∗ s , u i n t 1 6 t i ) { return ∗ s + i ; } int main ( void ) { char f o o [ 1 0 ] , ∗ bar = m a l l o c ( 1 5 ) ; uint16 t foobar ; u i n t 3 2 t blah ; 12 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security 15 16 17 18 19 20 21 22 } s t r c p y ( foo , ” 01234567 ” ) ; foobar = 65532; b l a h = f u n c ( foo , f o o b a r ) ; /∗ THIS IS THE INTERESTING POSITION ∗/ return 0 ; Let the start-address of the stack of the virtual memory for the process be 0x000f0000. Assume that it is an IA-32 (x86)-architecture and sizeof(void*) is 4 (which means that the size of a pointer is 4 bytes). Assume further the variables are pushed on the stack in the same order as they are declared and assume no padding!3 a) In which direction does the stack grow? b) Where points bar? What is the address of the first byte of bar (==&bar)? c) How does the address of foo change in strcpy? d) What is the address of the first byte of blah (== &blah)? 10. On Linux, if a process tries to access memory it does not belong to it, the kernel sends signal 11 - SIGSEGV and the access fails. The standard behaviour on receiving SIGSEGV is to print out “segmentation fault” and exit the process. Explain why this is done and what effects it would have if it have not been implemented. Points) 1.4. I/O Management ( π−2 2π 1. Distinguish the tree techniques for performing I/O from each other: Programmed I/O, Interrupt-driven I/O and DMA. 2. Why is I/O buffering important? Mention the different buffering-schemes that are supported by OSs and point out their differences. 3. What is the difference between block-oriented devices and stream-oriented devices? Give 1 examples of each. 2. Practical Assignments ( P 1 Point) 2.1. Linux 2.1.1. Process Management 1. Read the process table, find out the process id of a running python shell. 3 Note that usual compiler will do padding and possible reorganize, so calculate the solution, do not try it out! 13 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security 2. Write a basic python-script that creates a child-process. Both processes (the parent and the child) shall print out its process-id. The parent-process shall wait for its child to exit and then print something extra. 3. Check whether this program really starts a new process using the ps4 command. 4. Now let the child do some work! Copy the big buck bunny Video from the server /insert/the/path/here to other/path/here. This can be done by using konqueror (doubleclick the link on the desktop). The Username is labor and the password labor1. Let the child execute mencoder to recode the video “big buck bunny.mkv” to the h264 codec 5 . This task requires a lot of computations. Check that the parent process is still usable while the child does lots of work. Explain why it isn’t blocked! 5. Change the script, so that one “global” variable is used in both processes, alter this variable in one process! Has it changed in the other? explain Why/why-not! 2.1.2. Memory Management 1. Use python to place some string in the memory. (start the python shell and assign a string to some variable) 2. Find out the memory-address using hex(id(str)). 3. Use the hexeditor hexedit to find it in /dev/mem. With the “return”-key, you can jump to the address. Do you find the expected string? Explain! 2.2. Windows 2.2.1. Process Management 1. Run the Process Explorer utility on the desktop. (Process Explorer is a Windows Sysinternals Tool free for download.) 2. Find out which processes are currently running on your system. (No notes needed.) 3. Now click on the System Information button to see details of CPU activity. How many processes and how many threads are running? 4. Start multiple notepad sessions in the different ways listed below. Use the Process Explorer to observe the differences. Are there differences with respect to the priviledges? • Start\All Programs\Accessories\Notepad • start notepad using Command Prompt 4 5 prints out the current process-list, for further information see man ps os.system("mencoder -ovc x264 -o -oac pcm -x264encopts bitrate=1000 big buck bunny.h264 big buck bunny.mkv") 14 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security • run Command Prompt as administrator (right click Command Promp on the start menu and select ”run as administrator”) and execute s c h t a s k s / C r e a t e /SC e i n m a l /ST 1 0 : 4 1 /TN Test /TR notepad (Replace the time 10:41 with the time of your system adding two or three minutes.) 5. How does the number of threads and the assigned virtual space changes, during entering some code, saving or opening a notepad document? (Just note the general trends.) 6. Start notepad as administrator and try to open C:\Test\security-log.txt. 7. Create a new file ”malware.bat” in C:\Test using notepad and insert the following code. @ECHO OFF C: CD \TEST ECHO 1 >> s e c u r i t y −l o g . t x t PAUSE 8. Open Command Prompt as administrator and check if the size of the file securitylog.txt changes by entering: a t 1 0 : 4 1 ”C: \ Test \ malware . bat ” (Don’t forget to replace the time!) 9. Why does this work? What does this mean for the security of Windows Vista? 2.3. Bonus assignment (+1 Point) We gathered the contents of a machines memory using DMA and firewire. There was no time to check on the machine directly, so the only thing we have is the memorydump. Analyse the memory dump of this machine provided in Desktop/Exercise Data/Exercise 2/memory.dump. 1. Which operating system was this machine running? 2. Search for the processes that have been running at the time when the image was made. 3. Reconstruct the users and their passwords. 15 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security Appendix The following information is not mandatory for the assignment. It is meant as background knowledge, if you are interested in one particular detail or have difficulties understand the things above. Many of the details included in the appendix are not comprehensible given only the information given in the lecture and in the introducion. A. Syscalls This is the (complete) documentation of selected syscalls for the linux operating system. Since it is real world documentation, it is quite not easy to understand. A.1. fork - create a child process description: fork creates a new process by duplicating the calling process. The new process, referred to as the child, is an exact duplicate of the calling process, referred to as the parent, except for the following points: • The child has its own unique process ID, and this PID does not match the ID of any existing process group (see man setpgid). • The child’s parent process ID is the same as the parent’s process ID. • The child does not inherit its parent’s memory locks (mlock, mlockall). • Process resource utilizations (getrusage) and CPU time counters (times) are reset to zero in the child. • The child’s set of pending signals is initially empty • The child does not inherit semaphore adjustments from its parent • The child does not inherit record locks from its parent • The child does not inherit timers from its parent • The child does not inherit outstanding asynchronous I/O operations from its parent The process attributes in the preceding list are all specified in POSIX.1-2001. The parent and child also differ with respect to the following Linux-specific process attributes: • The child does not inherit directory change notifications (dnotify) from its parent (see the description of F NOTIFY in the man-page of fcntl). • The prctl PR SET PDEATHSIG setting is reset so that the child does not receive a signal when its parent terminates. • Memory mappings that have been marked with the madvise MADV DONTFORK flag are not inherited across a fork. 16 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security • The termination signal of the child is always SIGCHLD (see the manpage of clone). Note the following further points: • The child process is created with a single thread – the one that called fork. The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects; the use of pthread atfork may be helpful for dealing with problems that this can cause. • The child inherits copies of the parent’s set of open file descriptors. Each file descriptor in the child refers to the same open file description (see man open) as the corresponding file descriptor in the parent. This means that the two descriptors share open file status flags, current file offset, and signal-driven I/O attributes (see the description of F SETOWN and F SETSIG in man fcntl). • The child inherits copies of the parent’s set of open message queue descriptors (see man mq overview). Each descriptor in the child refers to the same open message queue description as the corresponding descriptor in the parent. This means that the two descriptors share the same flags (mq flags). • The child inherits copies of the parent’s set of open directory streams (see man opendir). POSIX.1-2001 says that the corresponding directory streams in the parent and child may share the directory stream positioning; on Linux/glibc they do not. return value: On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately. errors: EAGAIN fork cannot allocate sufficient memory to copy the parent’s page tables and allocate a task structure for the child. EAGAIN It was not possible to create a new process because the caller’s RLIMIT NPROC resource limit was encountered. To exceed this limit, the process must have either the CAP SYS ADMIN or the CAP SYS RESOURCE capability. ENOMEM fork failed to allocate the necessary kernel structures because memory is tight. conforming to: SVr4, 4.3BSD, POSIX.1-2001. 17 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security notes: Under Linux, fork is implemented using copy-on-write pages, so the only penalty that it incurs is the time and memory required to duplicate the parent’s page tables, and to create a unique task structure for the child. Since version 2.3.3, rather than invoking the kernel’s fork system call, the glibc fork wrapper that is provided as part of the NPTL threading implementation invokes clone with flags that provide the same effect as the traditional system call. The glibc wrapper invokes any fork handlers that have been established using pthread atfork. A.2. exit - terminate the calling process description: The function exit terminates the calling process ”immediately”. Any open file descriptors belonging to the process are closed; any children of the process are inherited by process 1, init, and the process’s parent is sent a SIGCHLD signal. The value status is returned to the parent process as the process’s exit status, and can be collected using one of the wait family of calls. return value: This function does not return. conforming to: SVr4, POSIX.1-2001, 4.3BSD. notes: For a discussion on the effects of an exit, the transmission of exit status, zombie processes, signals sent, etc., see the manpage of exit. The function exit is like exit, but does not call any functions registered with atexit or on exit. Whether it flushes standard I/O buffers and removes temporary files created with tmpfile is implementation-dependent. On the other hand, exit does close open file descriptors, and this may cause an unknown delay, waiting for pending output to finish. If the delay is undesired, it may be useful to call functions like tcflush before calling exit. Whether any pending I/O is canceled, and which pending I/O may be canceled upon exit() is implementation-dependent. A.3. wait, waitpid, waitid - wait for process to change state description: All of these system calls are used to wait for state changes in a child of the calling process, and obtain information about the child whose state has changed. A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal. In the case of a terminated child, performing a wait allows the system to release the resources associated with the child; if a wait is not performed, then the terminated child remains in a “zombie” state (see NOTES below). 18 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security If a child has already changed state, then these calls return immediately. Otherwise they block until either a child changes state or a signal handler interrupts the call (assuming that system calls are not automatically restarted using the SA RESTART flag of sigaction). In the remainder of this page, a child whose state has changed and which has not yet been waited upon by one of these system calls is termed waitable. wait and waitpid The wait system call suspends execution of the calling process until one of its children terminates. The call wait(&status); is equivalent to: w a i t p i d ( −1 , &s t a t u s , 0 ) ; The waitpid system call suspends execution of the calling process until a child specified by pid argument has changed state. By default, waitpid waits only for terminated children, but this behavior is modifiable via the options argument, as described below. The value of pid can be: < -1 meaning wait for any child process whose process group ID is equal to the absolute value of pid. -1 meaning wait for any child process. 0 meaning wait for any child process whose process group ID is equal to that of the calling process. > 0 meaning wait for the child whose process ID is equal to the value of pid. The value of options is an OR of zero or more of the following constants: WNOHANG return immediately if no child has exited. WUNTRACED also return if a child has stopped (but not traced via ptrace). Status for traced children which have stopped is provided even if this option is not specified. WCONTINUED (since Linux 2.6.10) also return if a stopped child has been resumed by delivery of SIGCONT. (For Linux-only options, see below.) The WUNTRACED and WCONTINUED options are only effective if the SA NOCLDSTOP flag has not been set for the SIGCHLD signal (see sigaction). 19 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security If status is not NULL, wait and waitpid store status information in the int to which it points. This integer can be inspected with the following macros (which take the integer itself as an argument, not a pointer to it, as is done in wait and waitpid!): WIFEXITED(status) returns true if the child terminated normally, that is, by calling exit or exit, or by returning from main(). WEXITSTATUS(status) returns the exit status of the child. This consists of the least significant 8 bits of the status argument that the child specified in a call to exit or exit or as the argument for a return statement in main(). This macro should only be employed if WIFEXITED returned true. WIFSIGNALED(status) returns true if the child process was terminated by a signal. WTERMSIG(status) returns the number of the signal that caused the child process to terminate. This macro should only be employed if WIFSIGNALED returned true. WCOREDUMP(status) returns true if the child produced a core dump. This macro should only be employed if WIFSIGNALED returned true. This macro is not specified in POSIX.1-2001 and is not available on some Unix implementations (e.g., AIX, SunOS). Only use this enclosed in #ifdef WCOREDUMP ... #endif. WIFSTOPPED(status) returns true if the child process was stopped by delivery of a signal; this is only possible if the call was done using WUNTRACED or when the child is being traced (see manpage of ptrace). WSTOPSIG(status) returns the number of the signal which caused the child to stop. This macro should only be employed if WIFSTOPPED returned true. WIFCONTINUED(status) (since Linux 2.6.10) returns true if the child process was resumed by delivery of SIGCONT. The waitid() system call (available since Linux 2.6.9) provides more precise control over which child state changes to wait for. The idtype and id arguments select the child(ren) to wait for, as follows: idtype == P PID Wait for the child whose process ID matches id. idtype == P PGID Wait for any child whose process group ID matches id. idtype == P ALL Wait for any child; id is ignored. The child state changes to wait for are specified by ORing one or more of the following flags in options: 20 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security WEXITED Wait for children that have terminated. WSTOPPED Wait for children that have been stopped by delivery of a signal. WCONTINUED Wait for (previously stopped) children that have been resumed by delivery of SIGCONT. The following flags may additionally be ORed in options: WNOHANG As for waitpid. WNOWAIT Leave the child in a waitable state; a later wait call can be used to again retrieve the child status information. Upon successful return, waitid fills in the following fields of the siginfo t structure pointed to by infop: si pid The process ID of the child. si uid The real user ID of the child. (This field is not set on most other implementations.) si signo Always set to SIGCHLD. si status Either the exit status of the child, as given to exit (or exit), or the signal that caused the child to terminate, stop, or continue. The si code field can be used to determine how to interpret this field. si code Set to one of: CLD EXITED (child called exit); CLD KILLED (child killed by signal); CLD STOPPED (child stopped by signal); or CLD CONTINUED (child continued by SIGCONT). If WNOHANG was specified in options and there were no children in a waitable state, then waitid returns 0 immediately and the state of the siginfo t structure pointed to by infop is unspecified. To distinguish this case from that where a child was in a waitable state, zero out the si pid field before the call and check for a non-zero value in this field after the call returns. return value: wait on success, returns the process ID of the terminated child; on error, -1 is returned. waitpid on success, returns the process ID of the child whose state has changed; if WNOHANG was specified and one or more child(ren) specified by pid exist, but have not yet changed state, then 0 is returned. On error, -1 is returned. waitid returns 0 on success or if WNOHANG was specified and no child(ren) specified by id has yet changed state; on error, -1 is returned. Each of these calls sets errno to an appropriate value in the case of an error. 21 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security errors: ECHILD (for wait) The calling process does not have any unwaited-for children. ECHILD (for waitpid or waitid) The process specified by pid (waitpid) or idtype and id (waitid) does not exist or is not a child of the calling process. (This can happen for one’s own child if the action for SIGCHLD is set to SIG IGN. See also the Linux Notes section about threads.) EINTR WNOHANG was not set and an unblocked signal or a SIGCHLD was caught. EINVAL The options argument was invalid. conforming to: SVr4, 4.3BSD, POSIX.1-2001. notes: A child that terminates, but has not been waited for becomes a “zombie”. The kernel maintains a minimal set of information about the zombie process (PID, termination status, resource usage information) in order to allow the parent to later perform a wait to obtain information about the child. As long as a zombie is not removed from the system via a wait, it will consume a slot in the kernel process table, and if this table fills, it will not be possible to create further pro- cesses. If a parent process terminates, then its “zombie” children (if any) are adopted by init, which automatically performs a wait to remove the zombies. POSIX.1-2001 specifies that if the disposition of SIGCHLD is set to SIG IGN or the SA NOCLDWAIT flag is set for SIGCHLD (see manpage of sigaction), then children that terminate do not become zombies and a call to wait or waitpid will block until all children have terminated, and then fail with errno set to ECHILD. (The original POSIX standard left the behavior of setting SIGCHLD to SIG IGN unspecified. Note that even though the default disposition of SIGCHLD is ”ignore”, explicitly setting the disposition to SIG IGN results in different treatment of zombie process children.) Linux 2.6 conforms to this specification. However, Linux 2.4 (and earlier) does not: if a wait or waitpid call is made while SIGCHLD is being ignored, the call behaves just as though SIGCHLD were not being ignored, that is, the call blocks until the next child terminates and then returns the process ID and status of that child. linux notes: In the Linux kernel, a kernel-scheduled thread is not a distinct construct from a process. Instead, a thread is simply a process that is created using the Linuxunique clone system call; other routines such as the portable pthread create call are implemented using clone. Before Linux 2.4, a thread was just a special case of a process, and as a consequence one thread could not wait on the children of another thread, even when the latter belongs to the same thread group. However, POSIX prescribes such functionality, and since Linux 2.4 a thread can, and by default will, wait on children of other threads in the same thread group. 22 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security The following Linux-specific options are for use with children created using clone; they can- not be used with waitid: WCLONE Wait for “clone” children only. If omitted then wait for “non-clone” children only. (A ”clone” child is one which delivers no signal, or a signal other than SIGCHLD to its parent upon termination.) This option is ignored if WALL is also specified. WALL (since Linux 2.4) Wait for all children, regardless of type (“clone” or “nonclone”). WNOTHREAD (since Linux 2.4) Do not wait for children of other threads in the same thread group. This was the default before Linux 2.4. example: The following program demonstrates the use of fork and waitpid. The program creates a child process. If no command-line argument is supplied to the program, then the child suspends its execution using pause, to allow the user to send signals to the child. Otherwise, if a command-line argument is supplied, then the child exits immediately, using the integer supplied on the command line as the exit status. The parent process executes a loop that monitors the child using waitpid, and uses the W*() macros described above to analyze the wait status value. The following shell session demonstrates the use of the program: $ . / a . out & C h i l d PID i s 32360 [ 1 ] 32359 $ k i l l −STOP 32360 s to p pe d by s i g n a l 19 $ k i l l −CONT 32360 continued $ k i l l −TERM 32360 k i l l e d by s i g n a l 15 [ 1 ] + Done $ 1 2 3 4 5 6 #include #include #include #include . / a . out <s y s / w a i t . h> < s t d l i b . h> <u n i s t d . h> <s t d i o . h> int main ( int argc , char ∗ argv [ ] ) 23 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security 7 { 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 } p i d t cpid , w ; int s t a t u s ; cpid = fork () ; i f ( c p i d == −1) { perror (” fork ”) ; e x i t (EXIT FAILURE) ; } i f ( c p i d == 0 ) { /∗ Code e x e c u t e d by c h i l d ∗/ p r i n t f ( ” C h i l d PID i s %l d \n” , ( long ) g e t p i d ( ) ) ; i f ( a r g c == 1 ) pause ( ) ; /∗ Wait f o r s i g n a l s ∗/ e x i t ( a t o i ( argv [ 1 ] ) ) ; } else { /∗ Code e x e c u t e d by p a r e n t ∗/ do { w = w a i t p i d ( cpid , &s t a t u s , WUNTRACED | WCONTINUED) ; i f (w == −1) { perror ( ” waitpid ” ) ; e x i t (EXIT FAILURE) ; } i f (WIFEXITED( s t a t u s ) ) { p r i n t f ( ” e x i t e d , s t a t u s=%d\n” , WEXITSTATUS( s t a t u s ) ) ; } e l s e i f (WIFSIGNALED( s t a t u s ) ) { p r i n t f ( ” k i l l e d by s i g n a l %d\n” , WTERMSIG( s t a t u s ) ) ; } e l s e i f (WIFSTOPPED( s t a t u s ) ) { p r i n t f ( ” s t o p p e d by s i g n a l %d\n” , WSTOPSIG( s t a t u s ) ) ; } e l s e i f (WIFCONTINUED( s t a t u s ) ) { p r i n t f ( ” c o n t i n u e d \n” ) ; } } while ( ! WIFEXITED( s t a t u s ) && ! WIFSIGNALED( s t a t u s ) ) ; e x i t (EXIT SUCCESS) ; } A.4. getpid, getppid - get process identification description: getpid returns the process ID of the calling process. (This is often used by routines that generate unique temporary filenames.) 24 RUHR-UNIVERSITY BOCHUM Exercises Operating System Security WS2008/09 Chair for System Security getppid returns the process ID of the parent of the calling process. errors: These functions are always successful. confirming to: POSIX.1-2001, 4.3BSD, SVr4 References [1] Python (programming language) (programming_language) http://en.wikipedia.org/wiki/Python_ [2] Python Tutorial http://docs.python.org/tutorial/ [3] Python Language Reference http://docs.python.org/reference/ [4] Python Standard Library http://docs.python.org/library/ [5] The Kate Text Editor http://kate-editor.org/ [6] The wikipedia malloc-page http://en.wikipedia.org/wiki/Malloc 25