Hi,

this is of interest for amd64 and i386 only:

The bootarg code is a code collection to manage a bootarg_list, which
can be assembled into contiguous code with makebootargs().

makebootargs takes two arguments: pointer and available space.  Upon
return, the available space variable will be overriden with actually
consumed space.

consumed space = previously added bootargs + size for terminating bootarg
of type BOOTARG_END.

If there are too many bootargs, they will be truncated.  If DEBUG has
been defined, a warning will give information about this situation.

Unfortunately the code allows an overrun upon truncation.  If
truncation occurs, the for-loop of available bootargs will add as
many bootargs as possible _ignoring the additional BOOTARG_END_, which
will be added at the end.

Therefore the fix is simple:  consider space for additional bootarg.


Additionally to this, bootarg_list can be static again, that was
changed back in OpenBSD 2.3 times.  Also, return the actually consumed
space if truncation occurred, not simply available space.


I wrote an example code + Makefile that triggers this overflow in userland:
http://stoeckmann.org/openbsd/bootarg.tar.gz

Two programs get created from main.c:
- crash adds a bootarg in "perfect size" to let BOOTARG_END overflow
  into guard page on i386
- nocrash adds the largest allowed bootarg -- not crashing.


Tobias

Index: bootarg.c
===================================================================
RCS file: /cvs/src/sys/stand/boot/bootarg.c,v
retrieving revision 1.10
diff -u -p -u -p -r1.10 bootarg.c
--- bootarg.c   11 Aug 2003 06:23:07 -0000      1.10
+++ bootarg.c   26 Jun 2014 21:22:18 -0000
@@ -30,7 +30,7 @@
 #include <lib/libsa/stand.h>
 #include <stand/boot/bootarg.h>
 
-bootarg_t *bootarg_list;
+static bootarg_t *bootarg_list;
 
 void
 addbootarg(int t, size_t l, void *p)
@@ -53,18 +53,20 @@ makebootargs(caddr_t v, size_t *lenp)
 
        /* get total size */
        l = sizeof(*p);
-       for (p = bootarg_list; p != NULL; p = p->ba_next)
+       for (p = bootarg_list; p != NULL; p = p->ba_next) {
                l += p->ba_size;
-       if (*lenp < l) {
+               if (*lenp < l) {
 #ifdef DEBUG
-               printf("makebootargs: too many args\n");
+                       printf("makebootargs: too many args\n");
 #endif
-               l = *lenp;
+                       l -= p->ba_size;
+                       break;
+               }
        }
        *lenp = l;
        /* copy them out */
        for (p = bootarg_list, q = v;
-            p != NULL && ((q + p->ba_size) - (u_char *)v) < l;
+            p != NULL && ((q + p->ba_size) - (u_char *)v) <= l - sizeof(*p);
             q += p->ba_size, p = p->ba_next) {
 #ifdef DEBUG
                printf("%d,%d ", p->ba_type, p->ba_size);

Reply via email to