Scribe notes for Week1, Lecture2
Main objective: Discussing Interfaces:
Recall from last lecture, we were discussing:
Mouse button example: (Continued)
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.
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.
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:
User level programs cannot:
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.
In order to run in supervisor mode, we need a Kernel. The kernel is that O.S. software that runs at supervisor mode.
User level programs are processes. A process is a running instance of a program, it features:
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?
UNIX is one big idea, it express all system resource interrupts of FILES. data file: a stream of bytes. (often w/length)
Usually stored in directories, and directories can be hierarchical. See picture below:
Example: UNIX file and directory structure.
Time-Of-Check-To-Time-Of-Use bug.(TOCTTOU)
Let us define the following file interface. (not real)
Example:
The following picture shows how unlinking file A, and renaming file B to A cause the TOCTTOU error in the result.
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:
So how are the garbage removed?
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.
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
<<END OF LECTURE TWO>>
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;