On Sat, Feb, 2001, Florian Weimer wrote:
> Chris Evans <[EMAIL PROTECTED]> 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.
>
> 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. ;-)

The attached kernel module should sanitise input to the sysctl sycall to
prevent the problem without forcing a kernel recompile or upgrade.  I
assume the vulnerability can't be exploited via the /proc sysctl
interface.

Unfortunately the module does nothing for the ptrace race condition,
though a module to disable ptrace would be trivial it would disable
strace and some features of gdb and so on.

--
Stephen White              \    OU Compsoc System Administration Team
PGP Key ID: 0xC79E5B6A      \      System Administration Co-ordinator
<[EMAIL PROTECTED]>      \         http://ox.compsoc.net/~swhite/
/* Stephen White 10/2/2001
   [EMAIL PROTECTED]

   sysctl_fix.c, compile:
   gcc -Wall -DMODULE -D__KERNEL__ -c sysctl_fix.c

   (on Redhat/UltraSparc with
        sparc64-linux-gcc -m64 -mno-fpu -mcmodel=medlow -mcpu=ultrasparc
        -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wall -DMODULE -D__KERNEL__
        -c sysctl_fix.c )

   Prevent sysctl exploit discovered by Chris Evans by properly validating
        input against negative numbers,
        
*/

#include <linux/kernel.h>
#include <linux/config.h>

#include <linux/module.h>
#include <linux/version.h>

#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <sys/syscall.h>
#include <linux/linkage.h>

#include <asm/uaccess.h>

#include <linux/sysctl.h>

extern void *sys_call_table[];

int (*old_sysctl)(struct __sysctl_args *args);

asmlinkage int validate_sysctl(struct __sysctl_args *args)
{
        struct __sysctl_args tmp;

        if(copy_from_user(&tmp, args, sizeof(tmp)))
                return -EFAULT;

        if (tmp.nlen < 0) goto bad;

        if (tmp.oldval) {
                int old_len;
                if (copy_from_user(&old_len, tmp.oldlenp, sizeof(old_len)))
                        return -EFAULT;
                if (old_len < 0) goto bad;
        }

        if (tmp.newval)
                if (tmp.newlen < 0) goto bad;

        return (*old_sysctl)(args);

bad:
        printk("sysctl: arguments failed sanity check for user %i\n",current->uid);
        return  -EINVAL;
}

int init_module()
{
  old_sysctl = sys_call_table[__NR__sysctl];
  sys_call_table[__NR__sysctl] = validate_sysctl;

  return 0;
}

void cleanup_module()
{
  sys_call_table[__NR__sysctl] = old_sysctl;
}

Reply via email to