xorl %eax, %eax

CVE-2009-1185: Linux udev Path Encoding

leave a comment »

This is one of the two really interesting vulnerabilities on udev discovered and disclosed by stealth. The popular implementation for managing hotplug devices is vulnerable on releases prior to 1.4.1. Here is the code from udev/lib/libudev-util.c of the 1.4.0 release:

112 size_t util_path_encode(char *s, size_t len)
113 {
114         char t[(len * 3)+1];
115         size_t i, j;
116
117         for (i = 0, j = 0; s[i] != ''; i++) {
118                 if (s[i] == '/') {
119                         memcpy(&t[j], "\\x2f", 4);
120                         j += 4;
121                 } else if (s[i] == '\\') {
122                         memcpy(&t[j], "\\x5c", 4);
123                         j += 4;
124                 } else {
125                         t[j] = s[i];
126                         j++;
127                 }
128         }
129         if (len == 0)
130                 return j;
131         i = (j < len - 1) ? j : len - 1;
132         memcpy(s, t, i);
133         s[i] = '';
134         return j;
135 }


This function is used to encode the path. For example, here is  how it is being called by udev/udevd.c:

99         char filename_failed[UTIL_PATH_SIZE];
100         size_t start;
      ...
107         util_strlcpy(filename_failed, udev_get_dev_path(event->udev), sizeof(filename_failed));
108         util_strlcat(filename_failed, "/", sizeof(filename_failed));
109         start = util_strlcat(filename_failed, ".udev/failed/", sizeof(filename_failed));
110         util_strlcat(filename_failed, udev_device_get_devpath(event->dev), sizeof(filename_failed));
111         util_path_encode(&filename_failed[start], sizeof(filename_failed) - start);


Meaning that filename_failed[] is passed into util_path_encode() containing: PATH/.udev/failed/DEV_PATH and start is index to the returned string at line 110. Now, we can review util_path_encode(). Have a look at line 114, it declares a local buffer on the stack with size of (len * 3) + 1. Next, the for loop at line 117 iterates as long as filename[] is not NULL. If this contains a ‘/’ character, it copies 4 times the character ‘/’ (hex. 0x2F) to the newly allocated buffer t[] and increments j by 4 (line 120). Then, if filename[] has character ‘\’ it copies four of these characters (hex. 0x5C) at line 122 and at last, in any other case it performs a byte per byte copy on t[] from filename[] (line 125). Now, if for example we have a length of 100 passed to this function, t[] will be: (100 * 3) + 1 meaning 301 bytes long. Let’s say that it has 100 ‘/’ characters in there. This will copy 400 0x5C bytes and at line 132 there is another copy which copies this overflowed t[] buffer back to filename[]. This can be exploited either as a common buffer overflow vulnerability or in a more clever way as stealth did.
The patch to this was of course:

{
-       char t[(len * 3)+1];
+       char t[(len * 4)+1];
size_t i, j;

This function is called by udev/udev-node.c and udev/lib/libudev-device.c as well.

Written by xorl

April 17, 2009 at 16:19

Posted in bugs, linux

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s