xorl %eax, %eax

FreeBSD kenv(2) Local DoS

with 5 comments

This is a less interesting vulnerability which was also released on 23 March 2009 and affects FreeBSD 7.0 and 7.1. Kenv is a great utility provided by the FreeBSD Project. This nice little tool uses a FreeBSD’s system call, kenv(2) to achieve its goals. First read the previous man pages of kenv(1) and kenv(2) and then let’s have a quick look at the FreeBSD 7.0 release source code (kern/kern_environment.c) to understand the vulnerability.

79 int
80 kenv(td, uap)
81         struct thread *td;
82         struct kenv_args /* {
83                 int what;
84                 const char *name;
85                 char *value;
86                 int len;
87         } */ *uap;
88 {
89         char *name, *value, *buffer = NULL;
90         size_t len, done, needed;
91         int error, i;
      ...
96         if (uap->what == KENV_DUMP) {
      ...
103                 if (uap->len > 0 && uap->value != NULL)
104                         buffer = malloc(uap->len, M_TEMP, M_WAITOK|M_ZERO);
105                 mtx_lock(&kenv_lock);
106                 for (i = 0; kenvp[i] != NULL; i++) {
107                         len = strlen(kenvp[i]) + 1;
108                         needed += len;
109                         len = min(len, uap->len - done);
110                         /*
111                          * If called with a NULL or insufficiently large
112                          * buffer, just keep computing the required size.
113                          */
114                         if (uap->value != NULL && buffer != NULL && len > 0) {
115                                 bcopy(kenvp[i], buffer + done, len);
116                                 done += len;
117                         }
118                 }


In order to understand the vulnerability, we have to understand the for loop between lines 106-118. This loop is used to calculate the length of the kernel environment variables, iteratively in line 107 it goes through every environment variable. Finally, at lines 114-117 it attempts to copy len bytes of the kenv[i] into buffer+done. However, the above code leaves the allocation size of line 104 completely on the user controlled uap->len. Using this, an attacker could request a huge buffer and thus trigger the kernel attempting to allocate it at once and hopefully resulting in a kernel panic. A quick look at the above code implies that we can use kenv(2) with KENV_DUMP option (look at line 96) and this would almost certainly lead to a huge allocation. Here is the patch:

     char *name, *value, *buffer = NULL;
-    size_t len, done, needed;
+    size_t len, done, needed, buflen;
     int error, i;

     KASSERT(dynamic_kenv, ("kenv: dynamic_kenv = 0"));
@@ -100,13 +100,17 @@
             return (error);
 #endif
         done = needed = 0;
+        buflen = uap->len;
+        if (buflen > KENV_SIZE * (KENV_MNAMELEN + KENV_MVALLEN + 2))
+            buflen = KENV_SIZE * (KENV_MNAMELEN +
+                KENV_MVALLEN + 2);
         if (uap->len > 0 && uap->value != NULL)
-            buffer = malloc(uap->len, M_TEMP, M_WAITOK|M_ZERO);
+            buffer = malloc(buflen, M_TEMP, M_WAITOK|M_ZERO);
         mtx_lock(&kenv_lock);
         for (i = 0; kenvp[i] != NULL; i++) {
             len = strlen(kenvp[i]) + 1;
             needed += len;
-            len = min(len, uap->len - done);
+            len = min(len, buflen - done);
             /*
              * If called with a NULL or insufficiently large

Using this, it limits the maximum allocation size to:

KENV_SIZE * (KENV_MNAMELEN + KENV_MVALLEN + 2)

Which is:

kern/kern_environment.c:
1 #define KENV_SIZE       512     /* Maximum number of environment strings */
sys/kenv.h:
40 #define KENV_MNAMELEN   128     /* Maximum name length (for the syscall) */
41 #define KENV_MVALLEN    128     /* Maximum value length (for the syscall) */

And this translates into:

512 * (128 + 128 + 2) = 132096 Bytes

Not such a cool vulnerability but anyway…

Update:

This vulnerability was discovered by kingcope (see the comment below for details). My apologies to everyone.

Written by xorl

March 23, 2009 at 15:14

Posted in bugs, freebsd

5 Responses

Subscribe to comments with RSS.

  1. thanks, i accidentally bumped on your blog while looking for some more info about that bug [ i loe learning about security stuffs, and it really helps when people like you write detailed stuffs like that.

    $3|v3n

    March 23, 2009 at 18:22

  2. and yeah, that color theme is great to help reading!

    $3|v3n

    March 23, 2009 at 18:27

  3. […] March 2009 The FreeBSD kernel recently had a issue in the kenv(2) kernel call, and this article describes very well what it is – and why it is bad. The vulnerability itself is not terribly bad, […]

  4. kcope

    January 23, 2010 at 20:23

  5. @kcope: thanks for that and my apologies. I’ll update the post immediately.

    xorl

    January 24, 2010 at 01:36


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