Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <CAGXu5j+6ObHXB7E_Ynb3uB36EPtSnM7C3aZ2xLjqgBfVpxVp4Q@mail.gmail.com>
Date: Tue, 12 Jul 2016 19:04:52 -0400
From: Kees Cook <keescook@...omium.org>
To: PaX Team <pageexec@...email.hu>
Cc: Brad Spengler <spender@...ecurity.net>, Casey Schaufler <casey.schaufler@...el.com>, 
	Rik van Riel <riel@...hat.com>, Christoph Lameter <cl@...ux.com>, Pekka Enberg <penberg@...nel.org>, 
	David Rientjes <rientjes@...gle.com>, Joonsoo Kim <iamjoonsoo.kim@....com>, 
	Andrew Morton <akpm@...ux-foundation.org>, 
	"kernel-hardening@...ts.openwall.com" <kernel-hardening@...ts.openwall.com>
Subject: Re: [PATCH v2 1/4] mm: Hardened usercopy

On Wed, Jun 8, 2016 at 5:11 PM, Kees Cook <keescook@...omium.org> wrote:
> This is an attempt at porting PAX_USERCOPY into the mainline kernel,
> calling it CONFIG_HARDENED_USERCOPY. The work is based on code by Brad
> Spengler and PaX Team, and an earlier port from Casey Schaufler.
>
> This patch contains the logic for validating several conditions when
> performing copy_to_user() and copy_from_user() on the kernel object
> being copied to/from:
> - if on the heap:
>   - the size of copy must be less than or equal to the size of the object
> - if on the stack (and we have architecture/build support for frames):
>   - object must be contained by the current stack frame
> - object must not be contained in the kernel text
>
> Additional restrictions are in following patches.
>
> This implements the checks on many architectures, but I have only tested
> x86_64 so far. I would love to see an arm64 port added as well.
>
> Signed-off-by: Kees Cook <keescook@...omium.org>
> [...]
> +/*
> + * Checks if a given pointer and length is contained by the current
> + * stack frame (if possible).
> + *
> + *     0: not at all on the stack
> + *     1: fully on the stack (when can't do frame-checking)
> + *     2: fully inside the current stack frame
> + *     -1: error condition (invalid stack position or bad stack frame)
> + */
> +static noinline int check_stack_object(const void *obj, unsigned long len)
> +{
> +       const void * const stack = task_stack_page(current);
> +       const void * const stackend = stack + THREAD_SIZE;
> +
> +#if defined(CONFIG_FRAME_POINTER) && defined(CONFIG_X86)
> +       const void *frame = NULL;
> +       const void *oldframe;
> +#endif
> +
> +       /* Reject: object wraps past end of memory. */
> +       if (obj + len < obj)
> +               return -1;
> +
> +       /* Object is not on the stack at all. */
> +       if (obj + len <= stack || stackend <= obj)
> +               return 0;
> +
> +       /*
> +        * Reject: object partially overlaps the stack (passing the
> +        * the check above means at least one end is within the stack,
> +        * so if this check fails, the other end is outside the stack).
> +        */
> +       if (obj < stack || stackend < obj + len)
> +               return -1;
> +
> +#if defined(CONFIG_FRAME_POINTER) && defined(CONFIG_X86)
> +       oldframe = __builtin_frame_address(1);
> +       if (oldframe)
> +               frame = __builtin_frame_address(2);
> +       /*
> +        * low ----------------------------------------------> high
> +        * [saved bp][saved ip][args][local vars][saved bp][saved ip]
> +        *                   ^----------------^
> +        *             allow copies only within here
> +        */
> +       while (stack <= frame && frame < stackend) {
> +               /*
> +                * If obj + len extends past the last frame, this
> +                * check won't pass and the next frame will be 0,
> +                * causing us to bail out and correctly report
> +                * the copy as invalid.
> +                */
> +               if (obj + len <= frame)
> +                       return obj >= oldframe + 2 * sizeof(void *) ? 2 : -1;
> +               oldframe = frame;
> +               frame = *(const void * const *)frame;
> +       }
> +       return -1;
> +#else
> +       return 1;
> +#endif
> +}

PaX Team,

Doesn't this checking leave (possible) stack canaries exposed to being
copied to userspace? I'm at a loss for a way to reliably determine if
they're present or not, though...

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.