Technology is evil.


The _ATPsndrsp function is vulnerable to a heap-based buffer overflow condition, due to insufficient checking of user input. This leads to a denial of service condition and potential arbitrary code execution by unprivileged users.

Remote exploitation might be possible (being verified, updates will be done as necessary) due to the exposure of the AppleTalk stack via different services in the system and the presence of similar issues in other functions, which will be detailed in forthcoming MoAB releases.

Affected versions

This issue has been verified on Mac OS X 10.4.8 (8L2127) x86. Previous versions might be affected.

Proof of concept, exploit or instructions to reproduce

The provided proof of concept will cause heap corruption, leading to a kernel panic on a call to m_free():

$ gcc MOAB-14-01-2007.c -o MOAB-14-01-2007
$ sudo appletalk -u en0 (or via Sharing -> Personal File Sharing)
$ ./MOAB-14-01-2007

Note: The AppleTalk stack can be started by different methods, either command-line based or through the GUI in the preference panels.

Debugging information

The following information corresponds to an up-to-date Mac OS X 10.4.8 (8L2127) system, and the provided proof of concept. It wasn't possible to dump a core file over network, as data structures related to the Yukon driver got corrupted, thus causing a second panic and preventing the dump functionality from working properly.

Sun Jan 14 22:15:18 2007
panic(cpu 0 caller 0x0035A8A3): freeing free mbuf
Backtrace, Format - Frame : Return Address (4 potential args on stack) 
0x13eabe48 : 0x128d1f (0x3c9540 0x13eabe6c 0x131df4 0x0) 
0x13eabe88 : 0x35a8a3 (0x3e9c7c 0x1 0x0 0x2e11848) 
0x13eabea8 : 0x2867b9 (0x25c37500 0xffffffff 0x0 0x0) 
0x13eabf28 : 0x29a0ce (0x3 0x1800400 0xffffffff 0x1770) 
0x13eabf68 : 0x378337 (0x2e80bb8 0x2e11848 0x2e1188c 0x0) 
0x13eabfc8 : 0x19acae (0x2e5b724 0x0 0x19d0b5 0x2767c80) No mapping exists for frame pointer
Backtrace terminated-invalid frame pointer 0xbffffb58

Kernel version:
Darwin Kernel Version 8.8.1: Mon Sep 25 19:42:00 PDT 2006;

(gdb) x/1i 0x19acae
0x19acae <lo_unix_scall+158>:   mov    %edi,%esp
(gdb) x/1i 0x378337
0x378337 <unix_syscall+755>:    mov    %eax,%esi
(gdb) x/1i 0x29a0ce
0x29a0ce <ATPsndrsp+96>:        mov    16(%ebp),%edx
(gdb) x/1i 0x2867b9
0x2867b9 <_ATPsndrsp+205>:      mov    8(%ebp),%edx
(gdb) x/1i 0x35a8a3
0x35a8a3 <m_free+80>:   mov    0x4cd6b0,%eax
(gdb) x/1i 0x128d1f
0x128d1f <panic+382>:   mov    4317808,%ecx

The source code below (coming from the original xnu-792 file) illustrates how the values are supplied by the user and used without validation of any type, for allocating a buffer and copying data over it. Both resplen and datalen are used with no bounds checking at all and the respbuf pointer is supplied by the user as well.

---------- bsd/netat/atp_write.c
1672 int
1673 _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
1674         int fd;
1675         unsigned char *respbuff;          <---- (!)
1676         int resplen;                      <---- (!)
1677         int datalen;                      <---- (!)
1678         int *err;
1679         void *proc;
1680 {
1681         gref_t          *gref;
1682         int             s, rc;
1683         long            bufaddr;
1684         gbuf_t          *m, *mdata;
1685         short           space;
1686         int             size;
1687         struct atp_state *atp;
1688         struct atpBDS *bdsp;
1689         u_int16_t       *bufsz;
1690         char            *buf;
1691         int             bds_cnt, count, len; <---- (!)
1692         caddr_t         dataptr;
1694         if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
1695                 return -1;
1707         /*
1708          * allocate buffer and copy in the response info
1709          */
1710         if ((m = gbuf_alloc_wait(resplen, TRUE)) == 0) { <---- (no resplen check...)
1711                 *err = ENOMEM;
1712                 file_drop(fd);
1713                 return -1;
1714         }
1715         if ((*err = copyin(CAST_USER_ADDR_T(respbuff), (caddr_t)gbuf_rptr(m),
	              resplen)) != 0) {
1716                 gbuf_freeb(m);
1717                 file_drop(fd);
1718                 return -1;
         gbuf_cont(m) = mdata;
1756         dataptr = mtod(mdata, caddr_t);
1757         for (count = 0; count < bds_cnt; bdsp++, count++) {
1758                 if ((bufaddr = UAL_VALUE(bdsp->bdsBuffAddr)) != 0 && 
1759                                 (len = UAS_VALUE(bdsp->bdsBuffSz)) != 0) {
------------- [note: these are the original comments...]

1760  if (len > space) {      /* enough room ? */
1761             gbuf_wset(mdata, dataptr - mtod(mdata, caddr_t));
	             /* set len of last mbuf */
1762                                 /* allocate the next mbuf */
1763                                 if ((gbuf_cont(mdata) = m_get((M_WAIT),
                                        MSG_DATA)) == 0) {
1764                                         gbuf_freem(m);
1765                                         file_drop(fd);
1766                                         *err = ENOMEM;
1767                                         return -1;
1768                                 }
1769                                 mdata = gbuf_cont(mdata);       
1770                                 MCLGET(mdata, M_WAIT);
1771                                 if (!(mdata->m_flags & M_EXT)) {
1772                                         m_freem(m);
1773                                         file_drop(fd);
1774                                         return(NULL);
1775                                 }
1776                                 dataptr = mtod(mdata, caddr_t);
1777                                 space = MCLBYTES;
1778                         }
------------- bsd/netat/atp_write.c

There's available documentation about double free() issues and previous heap based buffer overflows in the Mac OS X kernel. The interesting point about these issues is that AppleTalk is considered a legacy feature, and the code style and general quality is really poor. I would like to thank Ilja Van Sprundel for commenting about it as a potential area for new issues.


Workaround or temporary solution

Disable the AppleTalk stack, and any associated service:

$ sudo appletalk -d
"...found absurd, and a panic is induced." Rosyna "Absurdly induced" Keller (on integer overflows and allocation of negative size buffers).