Linux autofs overflow in 2.0.36+

Brian Jones (balif@SHELL.NACS.NET)
Fri, 19 Feb 1999 00:09:29 -0500


-- Start of PGP signed section.
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---]

-- End of PGP signed section.

----- End of forwarded message from Brian Jones -----

-- 
 Michael H. Warfield    |  (770) 985-6132   |  mhw@WittsEnd.com
  (The Mad Wizard)      |  (770) 925-8248   |  http://www.wittsend.com/mhw/
  NIC whois:  MHW9      |  An optimist believes we live in the best of all
 PGP Key: 0xDF1DD471    |  possible worlds.  A pessimist is sure of it!

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/