===CS111=== Scribe notes for Week1, Lecture2 Main objective: Discussing Interfaces: Recall from last lecture, we were discussing: * OS Kernels * Processes * File Interface **Mouse button example: (Continued)** {{.:mouse-example.jpg|.:mouse-example.jpg}} ==SOLUTION:== When the mouse button is pressed down, we write '1' into memory address 0x00, otherwise we write '0'. This solution uses a method called __//Direct Memory Access//__ (DMA), which means the application continuously polls for changes on the inputs. ==PROBLEM WITH ABOVE SOLUTION== The problem with using DMA is __//busy waiting//__. Busy waiting is when the cpu is busy waiting doing nothing because it cannot do anything else while waiting for inputs. ==ALTERNATE SOLUTION== We see that we need some mechanism that allows the cpu to be notified when an event happens. We need "Interrupts", or we need to use "Interrupt Driven I/O" Solution to polling: Use Interrupts -> Save process's status, jump to interrupt handler. On Interrupt: During the following steps, interrupts are disabled, but **WHY**?. fetch mouse position with program I/O if (mouse position is on start button) wake_up_kitty(); Re-enable interrupts and return to previouse program. **WHY IS INTERRUPT DISABLED?** Interupts are disbled to avoid __//denial of service//__, or __//livelock//__ when many interrupt handlers must be priviledged. Processors provide 2 modes: - Supervisor Mode: All instructions are available. - User Mode: Not all instructions are available. Some dangerouse instructions can cause protection fault. User level programs __cannot__: * Install interupt handlers * Disable interrupts * This is to ensure __**robustness**__. Recap: //To avoid the problem of busy waiting associated with polling, we make use of interrupts. In order to have the most control over our interrupt, our interrupt handler must run in supervisor mode. Which leads to the following.// ==KERNEL== In order to run in supervisor mode, we need a __//Kernel//__. The kernel is that O.S. software that runs at supervisor mode. * It always runs underneath applications. * It provides abstractions for programs (defines abstract machine) * Device drivers connect applications to hardware. * Multitasking/Time sharing meant running many applications at once. User level programs are processes. A __//process//__ is a running instance of a program, it features: * Program * Memory state * O.S. resources * Security attributes, which includes: * User ID of process owner * Processor registers * State * Process ID Note: The kernel keep track of the processor registers because we want each of the processes to think that it has its own machine. Question: How can a process communicate with a kernel? Answer: Through system call interface. A system call interface is an user level process that communicates with the kernel. It is implemented with __//traps//__ (software interrupts), they look like function calls. Example: pid_t getpid(); // get process id Let us write a function that waits until the mouse is clicked. wait_until_mouse_clicked (int * pos) systemcall current process goes to sleep kernel runs other processes until mouse button clicked mouse position is stored in *pos, pos[1] Problem: This is not a __**neutral**__ solution because it is only for one application; it needs to let the process to wait for more things. Solution: Let us come up with a more general interface for mouse and move. First solution: wait(); /*process sleeps until some event happens.*/ event(event description, function pointer); /*registers in kernel when event description(ed) happens, if process is in wait(), call f(). ed - event description. fd - function pointer. */ Second solution: wait(bitmask);// process sleeps until event named in bitmask. How do we name events? * Random numbers * Fixed numbers (for mouse) * Strings * File names UNIX is one big idea, it express all system resource interrupts of FILES. data file: a stream of bytes. (often w/length) * operations: - read. - write - rename - remove Usually stored in directories, and directories can be hierarchical. See picture below: Example: UNIX file and directory structure. {{.:linuxdirectory.jpg|.:linuxdirectory.jpg}} Time-Of-Check-To-Time-Of-Use bug.(TOCTTOU) Let us define the following file interface. (not real) * read(filename, buffer, position, length); * rename(oldname, newname) * unlink(name) Example: The following picture shows how unlinking file A, and renaming file B to A cause the TOCTTOU error in the result. {{.:scribe-fixed.jpg|.:scribe-fixed.jpg}} //The problem//: After process A has read(1) from file a, process B unlinks file a and renames file b to file a. When process A reads from file a again(2), it is actually reading from file b. A real life example that exploits the TOCTTOU: Let /tmp be the folder that contains temporary files, and it has the following attribute and property: * world writable * gradually collects garbage So how are the garbage removed? * let us have a "cleaner" process that removes garbage periodically. The following steps demonstrate that TOCTTOU can allow the cleaner process to remove system files. Let us have /tmp/evil/passwd, which is garbage in /tmp that needs to be removed. - (CLEANER STEP1) Cleaner process check if /tmp/evil is a directory. - (EVIL STEP1) Remove /tmp/evil - (EVIL STEP2) Make a link from /tmp/evil to /etc - (CLEANER STEP2) Remove files in /tmp/evil, particularly, it removes /tmp/evil/passwd. We see that while the cleaner thinks it has removed /tmp/evil/passwd, but it has actually removed /etc/passwd.(BAD!!) One solution for the TOCTTOU bug is as follows: In UNIX, what really happens is before reading from a file, we need to open it. This results in a file descriptor being returned. file_descriptor open(filename, flags); /*The file descriptor identifies with the file named "filename" after the call. This gives a resource handle for that file.*/ Thus we have the following file interface: fd = open(name, flags, [mode]) read(fd, buffer, length) write(fd, buffer, length) close(fd); We see how the TOCTTOU bug is avoided by handling files with file descriptors instead of file names. /dev/mouse * kernel "write" to /dev/mouse when: - mouse clicks - user moves the mouse <> ---- Notes on notation: whenever a type's name is followed by "_t", it simply means that it is a kind of int. typedef int foo_t; foo_t money = 2; which is same as: int money; money = 2;