secretsquirrel / google-security-research

Automatically exported from code.google.com/p/google-security-research
3 stars 0 forks source link

launchd heap overflow in log_forward #14

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
The log_forward MIG method is used for per-user launchd processes to send log 
messages to the root launchd (pid 1 running as root.)

job.defs:

routine
log_forward(
        j     : job_t;
        inval   : pointer_t
);

The log_forward implementation checks that the sender was a per-user launchd 
process before calling launchd_log_forward:

core.c:

kern_return_t
job_mig_log_forward(job_t j, vm_offset_t inval, mach_msg_type_number_t invalCnt)
{
  ...
  if (!job_assumes(j, j->per_user)) {
    return BOOTSTRAP_NOT_PRIVILEGED;
  }

  return launchd_log_forward(ldc->euid, ldc->egid, inval, invalCnt);
  ...

This means that this vulnerability can only be exploited by a per-user launchd 
process. This still represents a privilege escalation 
however as per-user launchds processes run with the user's uid. Exploitation is 
therefore predicated on being able to inject code into a process
running as the same user.

The vulnerability is in the code which deserializes the array of log messages 
(inval points to the controlled buffer:)

log.c:

launchd_log_forward(uid_t forward_uid, gid_t forward_gid, vm_offset_t inval, 
mach_msg_type_number_t invalCnt)
{
  struct logmsg_s *lm, *lm_walk;
  mach_msg_type_number_t data_left = invalCnt;
  ...
  for (lm_walk = (struct logmsg_s *)inval; (data_left > 0) && (lm_walk->obj_sz <= data_left); lm_walk = ((void *)lm_walk + lm_walk->obj_sz)) {
    ...
    if (lm_walk->obj_sz == 0) {
      ...
      break;
    }

    if (!(lm = malloc(lm_walk->obj_sz))) {         <-- (a)
      ...
      break;
    }

    memcpy(lm, lm_walk, lm_walk->obj_sz);
    lm->sender_uid = forward_uid;                  <-- (b)
    lm->sender_gid = forward_gid;

    lm->from_name += (size_t)lm;
    lm->about_name += (size_t)lm;
    lm->msg += (size_t)lm;
    lm->session_name += (size_t)lm;
  ...

There is no check on the obj_sz field at (a). By passing in a crafted data 
structure with an obj_sz field smaller than sizeof(struct logmsg_s)
lm will point to an undersized allocation and the assignments at (b) will point 
outside the allocated memory.

Original issue reported on code.google.com by ianb...@google.com on 3 Apr 2014 at 7:05

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 4 Apr 2014 at 3:35

GoogleCodeExporter commented 9 years ago
Apple follow up id: 605056557

Original comment by ianb...@google.com on 4 Apr 2014 at 3:39

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 4 Apr 2014 at 3:43

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 12 May 2014 at 8:34

GoogleCodeExporter commented 9 years ago

Original comment by ianb...@google.com on 23 May 2014 at 4:35

GoogleCodeExporter commented 9 years ago
Advisory: http://support.apple.com/kb/HT6296

Original comment by ianb...@google.com on 3 Jul 2014 at 1:15

GoogleCodeExporter commented 9 years ago

Original comment by cev...@google.com on 31 Jul 2014 at 12:17