xorl %eax, %eax

GRKERNSEC_IO Disable Privileged I/O

leave a comment »

This is a great feature since iopl(2)/ioperm(2) have been used in the wild for run-time kernel patching mainly in rootkits. However, this breaks some software as you can read in its description below.

config GRKERNSEC_IO
	bool "Disable privileged I/O"
	depends on X86
	select RTC_CLASS
	select RTC_INTF_DEV
	select RTC_DRV_CMOS

	help
	  If you say Y here, all ioperm and iopl calls will return an error.
	  Ioperm and iopl can be used to modify the running kernel.
	  Unfortunately, some programs need this access to operate properly,
	  the most notable of which are XFree86 and hwclock.  hwclock can be
	  remedied by having RTC support in the kernel, so real-time 
	  clock support is enabled if this option is enabled, to ensure 
	  that hwclock operates correctly.  XFree86 still will not 
	  operate correctly with this option enabled, so DO NOT CHOOSE Y 
	  IF YOU USE XFree86.  If you use XFree86 and you still want to 
	  protect your kernel against modification, use the RBAC system.

Let’s have a look at arch/x86/kernel/ioport.c file now…

/*
 * this changes the io permissions bitmap in the current task.
 */
asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
{
        struct thread_struct *t = &current->thread;
        struct tss_struct *tss;
        unsigned int i, max_long, bytes, bytes_updated;

        if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
                return -EINVAL;
#ifdef CONFIG_GRKERNSEC_IO
	if (turn_on && grsec_disable_privio) {
		gr_handle_ioperm();
		return -EPERM;
	}
#endif
        if (turn_on && !capable(CAP_SYS_RAWIO))
                return -EPERM;
   ...
        /* Update the TSS: */
        memcpy(tss->io_bitmap, t->io_bitmap_ptr, bytes_updated);

        put_cpu();

        return 0;
}

This system call provides an integer named ‘turn_on’ which is used to turn on or off the I/O permissions by setting or clearing the requested bit. As you can see, if the discussed option is enabled, grsecurity will check that ‘grsec_disable_privio’ as well as ‘turn_on’ are set and if this is the case, it will invoke gr_handle_ioperm() and return with “Permission Denied”.
Of course, similar code is also placed in iopl(2) system call which resides in the same file.

/*
 * sys_iopl has to be used when you want to access the IO ports
 * beyond the 0x3ff range: to get the full 65536 ports bitmapped
 * you'd need 8kB of bitmaps/process, which is a bit excessive.
 *
 * Here we just change the flags value on the stack: we allow
 * only the super-user to do it. This depends on the stack-layout
 * on system-call entry - see also fork() and the signal handling
 * code.
 */
long sys_iopl(unsigned int level, struct pt_regs *regs)
{
        unsigned int old = (regs->flags >> 12) & 3;
        struct thread_struct *t = &current->thread;

        if (level > 3)
                return -EINVAL;
        /* Trying to gain more privileges? */
        if (level > old) {
#ifdef CONFIG_GRKERNSEC_IO
		if (grsec_disable_privio) {
			gr_handle_iopl();
			return -EPERM;
		}
#endif
                if (!capable(CAP_SYS_RAWIO))
                        return -EPERM;
        }
        regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12);
        t->iopl = level << 12;
        set_iopl_mask(t->iopl);

        return 0;
}

The value that is taken into account here which is the ‘grsec_disable_privio’ is initialized at grsecurity/grsec_init.c file of grsecurity as shown below.

#ifdef CONFIG_GRKERNSEC_IO
#if !defined(CONFIG_GRKERNSEC_SYSCTL_DISTRO)
	grsec_disable_privio = 1;
#elif defined(CONFIG_GRKERNSEC_SYSCTL_ON)
	grsec_disable_privio = 1;
#else
	grsec_disable_privio = 0;
#endif
#endif

So, if ‘GRKERNSEC_SYSCTL_DISTRO’ is disabled it will statically initialize it to be ‘1’ (aka enabled). Otherwise, it will either set to true or false depending on ‘GRKERNSEC_SYSCTL_ON’ option. If the sysctl interface is available for grsecurity options it will also add the following sysctl entry.


In order to let administrators manage that feature at will through 'disable_priv_io' sysctl.
At last, the two gr_handle_ioperm() and gr_handle_iopl() routines can be found at grsecurity/grsec_mem.c and are simple logging functions.


#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/grinternal.h>

void
gr_handle_ioperm(void)
{
	gr_log_noargs(GR_DONT_AUDIT, GR_IOPERM_MSG);
	return;
}

void
gr_handle_iopl(void)
{
	gr_log_noargs(GR_DONT_AUDIT, GR_IOPL_MSG);
	return;
}

Written by xorl

November 20, 2010 at 14:37

Posted in grsecurity, linux, security

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