Exercise 1 ========== Q1. The scanf function does not check the length of the destination buffer. Hence, o1->buf and o2->buf may overflow, overwritting o1->func and o2->func with arbitrary values. An attacker may then replace these function addresses by addresses of his own, leading to arbitrary code execution when these functions will be called. Q2. Compiling with -fstack-protector to add stack canaries would not prevent this exploit for (at least) two reasons: 1. structures o1 and o2 are allocated in the heap, and not in the stack ... 2. canaries are purposed to prevent return address overwriting, and here the return address is not concerned by this exploit ... Examples of protections that could be used are: - compilation with dynamic verifiers (like AdSan or Valgrind) - use of more secure functions than scanf - CFI protections, that may prevent unexpected function calls Q3. With PointGuard protection, when an encrypted pointer is overwritten by an attacker then there's no chance that it refers to a valid address after decryption. Then, calls to o1->func and o2->func would likely lead to a crash. Q4. Assuming that Pointguard only ciphers base addresses of buffers (and not each cell address), it would nor prevent against classical buffer overflow attacks (to overwrite a return address, or like in the WinLoose example seen during the lab). Simiarly, Pointguards does not protect at all against use-after-free. In addition the attacker could be able to retrieve the key, since it is somewhere in the code. Finally, this protection may slow down too much the execution time for some applications. Exercise 2 ========== Q1. Function enablePerm() and disablePerm() are used to allow/disallow other threads to execute some restricted parts of the code belonging to specific protection domains (based on the stack-walking authorization policy). If enablePerm() is not called, then, when function buildKey is called, all the functions on the execution stack should be allowed to execute it, according to the default Java authorization policy. After it is called, even potentially untrusted threads are allowed to do so (which makes sense since their trustworthyness is checked at line 12). Q2. disablePerm() is called inside a try-catch block. Consequently, if an exception is raised inside this block (before it is called) then it will not be executed at all (leaving the permissions enabled). Q3. Fuction buildKey is not constant-time in the sense that its (public) return value (nbSpecials) depends on the content of confidential data passphrase (e.g., the number of non-Ascii chars it contains). In addition timing attacks may also reveal the positions of these characters. Exercise 3 ========== - variant 1: it is a (simple) off-by-one error, the canary is not overwritten, no error is detected ... - variant 2: the BoF leads here directly to a segmentation fault, without leaving a chance to the canary check to detect the error ... We could assume that this (large) overflow does reach a non valid address in the stack (since it contains only the main function), which crashes the program before the end of the loop execution (and hence before the stack protection mechanism operates). - variant 3: this is the normal functionning mode of the stack protector: the canary has been overwritten, and this detected by the check performed before the function returns.