CS155: Computer and Network Security

CS155: Homework #1

Spring 2015

Due: Thursday, Apr. 30


Problem 1: Control hijacking

A proposal for preventing stack buffer overflow attacks is based on making a backup copy of the return address when a function starts. The backup copy is written to a shadow stack located at some random location L on the heap. In the function epilog, just before the function is about to return, the backup copy of the return address is compared to the return address on the stack and if they differ the program exits. Otherwise, the return instruction is executed normally.

(a) Explain why this mechanism can make it harder to mount a stack buffer overflow attack.

(b) Give sample C code that is vulnerable to a stack buffer overflow attack even if this mechanism is used. For example, consider the case of function pointers stored on the stack.


Problem 2: Return oriented programming

Suppose an attacker finds the following code fragments in the libc library once it is loaded in memory:

0x40002000:
  pop eax
  ret

0x40002700:
  pop ebx
  ret

0x40002948:
  move [ebx], eax  // write the value of eax to location ebx
  ret

Moreover, the attacker discovers a stack buffer overflow in some vulnerable application where a string buffer can overflow. Explain how in an environment where the stack is marked non-execute the attacker can nevertheless cause the vulnerable application to write the value 0x40000000 to memory address 0x41000000 and then jump to address 0x40044444. Your answer need only show the contents of the stack in the table below right after the buffer overflow takes place.


Problem 3: Memory management

The iOS   _MALLOC(size_t size, int type, int flags) function allocates size bytes on the heap. Internally blocks are represented as a length field followed by a data field:

    struct _mhead {
      size_t  mlen;
      char    dat[0];  }
The mlen field is used by the free() function to determine how much space needs to be freed. In iOS 4.x the _MALLOC function was implemented as follows:
1   void * _MALLOC(size_t size, int type, int flags)  {
2     struct _mhead  *hdr;
3     size_t memsize = sizeof (*hdr) + size;
4     hdr = (void *)kalloc(memsize);  // allocate memory
5     hdr->mlen = memsize;
6     return  (hdr->dat);
7   }
In iOS 5.x the following two lines were added after line 3:
    int o = memsize < size ? 1 : 0;
    if (o)  return (NULL);
Why were these lines added in iOS5.x? Briefly describe an attack that may be possible without these lines.

Problem 4: Soundness and completeness for static code analysis

In lecture 4, we discussed these two terms briefly:

Soundness: If the program contain an error (of the kind the analysis tool is intended to detect), the analysis tool will report an error.

Completeness: If the program does not contain an error, the analysis tool will not report any errors.

  1. A false alarm occurs when a tool reports an error, but the program the tool is analyzing does not contain an error. Can a tool that reports a false alarm be sound? Complete?
  2. Suppose a company sets up an Android app marketplace for its employees. The company is going to use an analysis tool to check apps for security vulnerabilities before it promotes them to its employees. Which tool property is critical to the company for this purpose: soundness or completeness?
  3. Theoretically, suppose a tool is both sound and complete. When the tool is used to analyze the following code that may contain a vulnerability, what property of the loop determines whether the tool will report an error?
          int main()
          {
            int x = 0;
            while ( x < 10 ) { /* loop while x is less than 10 */
                 ...  /* do some stuff that is secure but might change the value of x  */
            }
            ... /* do something insecure */;
          }
    

Problem 5: Taint analysis and security vulnerabilities

The following diagram outlines the states used to track whether a variable v is tainted or clean.

The diagram omits some intermediate states. More specifically, suppose that source code is analyzed using an algorithm as described in Lecture 4. This algorithm gives each variable an abstract value from a finite set. Two of the abstract values are shown in the diagram: tainted and clean. Two additional values that are implied but not shown are lower_check and upper_check.

  1. Assume d.idx has abstract value tainted at the beginning of the following code. What value will it have when the second line of code is reached? Explain. (Hint: Either lower_check or upper_check could be a correct answer, if you give a correct explanation consistent with your choice.)
    if(d.idx > dma->buf_count) return –EINVAL;
    buf = dma->buflist[d.idx];
    Copy_from_user(buf_priv->virtual, d.address, d.used);
    
  2. In the code above, what error should this analysis produce when the second line is analyzed? (Hint: Explain why the abstract value of d.idx should be clean if the code does not have a security error.)
  3. What error will this analysis will find in the following code? Explain.
    /* 2.4.9/drivers/isdn/act2000/capi.c:actcapi_dispatch */
    
    isdn_ctrl cmd;
    ...
    while ((skb = skb_dequeue(&card->rcvq))) {
       msg = skb->data;
       ...
       memcpy(cmd.parm.setup.phone,
              msg->msg.connect_ind.addr.num,
              msg->msg.connect_ind.addr.len - 1);
       ...
    }
    

Problem 6: Unix access control

In Unix, every process has a real user id (ruid), an effective user id (euid), and a saved user id (suid). Processes with an euid of 0 have special root privileges.
  1. If a process with user id n forks to create another process, what user id does the new process have? (Hint: it's the same answer for euid, ruid, and suid.)
  2. If a process with euid n makes a setuid system call, what possible euids can the process run with after the call, in each of the following situations:
    1. Before: euid = n > 0, saved user id suid=m and real user id ruid = m. After:?
    2. Before: n=0 After:?
  3. In qmail, most modules run under separate user ids. Similarly, each Android application runs in a separate process using a separate user id. From a security standpoint, what is the advantage of assigning separate uids instead of using the same uid for all? Explain.
  4. Why should the separate uids be non-zero?
  5. The Android zygote process that creates new processes runs as root. After forking to create a new process, setuid is normally called. Explain why it is important to call setuid? What security purpose does this serve?
  6. When a user wishes to change her password, she uses the passwd program. The Unix password file is usually public readable but (for obvious reasons) can only be written by processes with root privileges.
    1. How should the setuid bit be set on this passwd program? Explain how this lets a user change her password.
    2. Why does this make it important to write the passwd program source code carefully?