COMMAND
autofs
SYSTEMS AFFECTED
Linux 2.0.36...2.2.1
PROBLEM
Brian Jones found following. 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.
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.
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 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. Example:
[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#
Very large numbers will cause various kernel errors, or a reboot
as giant chunks of memory are being clobbered.
SOLUTION
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.
Author was contacted and said he was going to fix this at
a different point in the code. This seems to work for the time
being.
--- 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;