TUCoPS :: Linux :: General :: automo~1.txt

linux 2.0.36+ automount allows normal user to gain root access via a kernel buffer overflow.


[ http://www.rootshell.com/ ]

Date: Fri, 19 Feb 1999 00:09:29 -0500
From: Brian Jones <balif@SHELL.NACS.NET>
Subject: Linux autofs overflow in 2.0.36+

-----BEGIN PGP SIGNED MESSAGE-----

                      Overflow in Autofs - Feb 18 1999
_____________________________________________________________________________
Affected: Linux autofs kernel module in linux-2.0.36 to 2.2.1
Type of Problem: Buffer overflow in kernel module.
Effects: Denial of Service, potential root exploit

By:           Brian Jones <balif@nacs.net>
Contributors: Patrick Lewis <patrick@apk.net>,
              phazer <phazer@battlemech.nws.net>
_____________________________________________________________________________

                                  Summary


    The autofs kernel module does not check the size of the directory names
it receives. It is passed the name and the names length through
dentry->d_name.name and dentry->d_name.len respectively. Later on it
memcpy()'s the name into a 256 byte buffer, using dentry->d_name.len as the
number of bytes to copy, without checking its size. A nonprivilaged user may
attempt to cd to a directory name exceeding 255 characters. This overwrites
memory, probably the kernel stack and anything beyond it, and causes kernel
errors or makes the machine reboot.


                            Overview of Automount


drwxr-xr-x   3 root     root            0 Feb 18 17:40 misc

    The autofs module provides support for the automount filesystem, as
well as the interface between the kernel and the automountd daemon, which is
responsible for the actual mounting. Calls such as chdir() executed in the
automount directory are handled by the module, and if the desired directory
is defined in the configuration files, automountd then mounts that
directory/device.


                                   Details


    When a chdir() or similar function is called in the autofs directory,
by a user doing something along the lines of "cd xxxx", the function
fs/autofs/root.c:autofs_root_lookup() is called.

    autofs_root_lookup() receives the name of the directory through
"dentry->d_name.name", and it's length through "dentry->d_name.len". The
dentry structure is passed via pointer through two functions, each performing
various operations along the way.

    It eventually reaches waitq:autofs_wait(). The name, length, and other
bits of information are copied into a 'wq' structure, which stands for
waiting queue. "wq.name" is "char *name", a pointer to the dentry pointer
that refers back to the filename somewhere in the kernel.

    autofs_wait() then passes 'wq' to autofs_notify_daemon(), which copies
the information into a structure called 'pkt'. This is passed to
autofs_write(), which write()'s the packet down the pipe connecting the
module with automountd.


                                The Overflow


    The problem occurs when 'wq' is copied to 'pkt'. Before this point,
the path name was shuffled around via pointers. 'pkt' is defined as:

        struct autofs_packet_missing pkt;

        struct autofs_packet_missing {
                struct autofs_packet_hdr hdr;
                autofs_wqt_t wait_queue_token;
                int len;
                char name[NAME_MAX+1];  
        };

        NAME_MAX is 255, making pkt.name a 256 byte buffer.

    pkt.name is copied using this method:

        pkt.len = wq->len;
        memcpy(pkt.name, wq->name, pkt.len);
        pkt.name[pkt.len] = '\0';
        
    Remember that wq->len and wq->name are directly copied from the dentry
structure. The len and name were never checked to ensure they would fit
inside pkt's buffer. If you attempt to cd to a directory name over 255
characters, you will overflow this buffer.

    Because this is running in the kernel, a large enough value can
overwrite as much memory as you want, over top any process you want. No
bounds checking is done, and the code makes no check to see if
dentry->d_name.len is under 255.


                                  Examples


[balif@localhost misc]# cd `perl -e 'print "x" x 255'`
bash: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:
No such file or directory

[balif@localhost misc]# cd `perl -e 'print "x" x 256'`
invalid operand: 0000
CPU:    0
EIP:    0010:[<c0155b00>]
EFLAGS: 00010282
eax: 00000000   ebx: c2a90c20   ecx: c265904c   edx: c0000000
esi: c29d3b00   edi: c2928000   ebp: c260d940   esp: c26c5ee8
ds: 0018   es: 0018   ss: 0018
Process bash (pid: 360, process nr: 21, stackpage=c26c5000)
Stack: 00000000 00000000 c260d940 c260d900 00000286 c0154c58 c0154ca8
c2928000 c260d940 c2928000 c260d900 c2659d50 c26cd3a0 00000286 c0154def
c260d900 c029c000 c2928000 c2659d9c c260d900 c2659d50 c0154ef7 c260d900
c260d900 c029c000 c2928000 c2659d9c c260d900 c2659d50 c0154ef7 c260d900
c260d900
Call Trace: [<c0154c58>] [<c0154ca8>] [<c0154def>] [<c0154ef7>] [<c0128759>]
[<c0128912>] [<c01289e9>] [<c012126e>] [<c0107a40>]
Code: fe ff ff 83 c4 08 eb 03 ff 43 1c 8b 7c 24 1c 83 7f 0c 00 74
- -{Shell dies}-

/var/log/messages
Feb 16 23:09:13 localhost automount[1361]: attempting to mount entry
/misc/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxq%^D^HH#

                                  ^_ buffer has been exceeded

Very large numbers will cause various kernel errors, or a reboot as giant
chunks of memory are being clobbered.

        
                                   The Fix


        This quick fix limits the length of a directory name to 255
characters, and patches /usr/src/linux-2.2.1/fs/autofs/root.c. I contacted
the author, who said he was going to fix this at a different point in the
code. This seems to work for the time being.

[---cut here---]
- --- root.c.orig Thu Feb 18 20:26:23 1999
+++ root.c      Thu Feb 18 20:26:17 1999
@@ -217,6 +217,11 @@
        DPRINTK(("autofs_root_lookup: name = "));
        autofs_say(dentry->d_name.name,dentry->d_name.len);

+     /* quick patch by balif@nacs.net 2-18-99 */
+     /* Prevents overflow of pkt.name in waitq.c:autofs_notify_daemon() */
+        if (dentry->d_name.len > 255)
+               return -ENAMETOOLONG;
+
        if (!S_ISDIR(dir->i_mode))
                return -ENOTDIR;
[---cut here---]


-----BEGIN PGP SIGNATURE-----
Version: 2.6.3a
Charset: noconv

iQB1AwUBNszxXSMC9wnJPLr1AQEvOQMAgeWVliqaW0CrM0NMsybSmw/a4yKdEJ4V
QkzVY+E9bb7wwMGxmC4nxJyhiUn9f9I4f0S19LMON0g7rBRQqlUi3rfgVOsBa18g
wBfY1bF3iwV7zYph08Tqd7So31j/ux7S
=88Co
-----END PGP SIGNATURE-----

---
Balif@Nacs.Net - http://setiathome.ssl.berkeley.edu/ - Get ready in April
                          N = N* fp ne fl fi fc fL

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH