2012-11-20 21:51:05

by Kees Cook

[permalink] [raw]
Subject: [PATCH v3] devtmpfs: mount with noexec and nosuid

Since devtmpfs is writable, make the default noexec,nosuid as well. This
protects from the case of a privileged process having an arbitrary file
write flaw and an argumentless arbitrary execution (i.e. it would lack
the ability to run "mount -o remount,exec,suid /dev").

Rather than relying on userspace "mount -o remount,noexec,nosuid /dev",
accomplish this from the kernel. This means no additional exec during
(potentially time-sensitive) boot is needed. The kernel is responsible
for this mount, so the mount flags should be configurable.

Cc: [email protected]
Cc: Kay Sievers <[email protected]>
Cc: Roland Eggner <[email protected]>
Signed-off-by: Kees Cook <[email protected]>

---
v3:
- use a single define for the mount flags, suggested by Greg K.H.
v2:
- use CONFIG_DEVTMPFS_SAFE to wrap the logic.
---
drivers/base/Kconfig | 12 ++++++++++++
drivers/base/devtmpfs.c | 11 +++++++++--
2 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index b34b5cd..a37fcf2 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -56,6 +56,18 @@ config DEVTMPFS_MOUNT
rescue mode with init=/bin/sh, even when the /dev directory
on the rootfs is completely empty.

+config DEVTMPFS_SAFE
+ bool "Use nosuid,noexec mount options on devtmpfs"
+ depends on DEVTMPFS
+ help
+ This instructs the kernel to include the MS_NOEXEC and
+ MS_NOSUID mount flags when mounting devtmpfs. This prevents
+ certain kinds of code-execution attacks on embedded platforms.
+
+ Notice: If enabled, things like /dev/mem cannot be mmapped
+ with the PROT_EXEC flag. This can break, for example, non-KMS
+ video drivers.
+
config STANDALONE
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
default y
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 147d1a4..e44ca1d 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -25,6 +25,12 @@
#include <linux/slab.h>
#include <linux/kthread.h>

+#ifdef CONFIG_DEVTMPFS_SAFE
+# define DEVTMPFS_MFLAGS (MS_SILENT | MS_NOEXEC | MS_NOSUID)
+#else
+# define DEVTMPFS_MFLAGS MS_SILENT
+#endif
+
static struct task_struct *thread;

#if defined CONFIG_DEVTMPFS_MOUNT
@@ -347,7 +353,8 @@ int devtmpfs_mount(const char *mntdir)
if (!thread)
return 0;

- err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
+ err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs",
+ DEVTMPFS_MFLAGS, NULL);
if (err)
printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
else
@@ -372,7 +379,7 @@ static int devtmpfsd(void *p)
*err = sys_unshare(CLONE_NEWNS);
if (*err)
goto out;
- *err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
+ *err = sys_mount("devtmpfs", "/", "devtmpfs", DEVTMPFS_MFLAGS, options);
if (*err)
goto out;
sys_chdir("/.."); /* will traverse into overmounted root */
--
1.7.9.5


--
Kees Cook
Chrome OS Security


2012-11-20 23:59:56

by Alan

[permalink] [raw]
Subject: Re: [PATCH v3] devtmpfs: mount with noexec and nosuid

> +config DEVTMPFS_SAFE
> + bool "Use nosuid,noexec mount options on devtmpfs"
> + depends on DEVTMPFS
> + help
> + This instructs the kernel to include the MS_NOEXEC and
> + MS_NOSUID mount flags when mounting devtmpfs. This prevents
> + certain kinds of code-execution attacks on embedded platforms.

This description appears to be wrong as well as the code being pointless.
It doesn't prevent any meaningful code execution attacks and the config
entry might give people the delusion its useful or a security feature.

Please provide a valid and meaningful example.

2012-11-21 00:17:59

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v3] devtmpfs: mount with noexec and nosuid

On Tue, Nov 20, 2012 at 4:05 PM, Alan Cox <[email protected]> wrote:
>> +config DEVTMPFS_SAFE
>> + bool "Use nosuid,noexec mount options on devtmpfs"
>> + depends on DEVTMPFS
>> + help
>> + This instructs the kernel to include the MS_NOEXEC and
>> + MS_NOSUID mount flags when mounting devtmpfs. This prevents
>> + certain kinds of code-execution attacks on embedded platforms.
>
> This description appears to be wrong as well as the code being pointless.
> It doesn't prevent any meaningful code execution attacks and the config
> entry might give people the delusion its useful or a security feature.

I'm not trying to say it's a magic cure-all. This feature is just for
trying to build a system that follows security best-practices: nothing
should be writable and executable, and that includes mount points.
Since the devtmpfs is mounted by the kernel, that's the logical place
to fix it. All the other mounts are triggered by userspace and pass
flags, so that's where those get fixed.

> Please provide a valid and meaningful example.

I don't need a specific example to follow best practices. Any example
I try to invent will appear far-fetched, but those are exactly the
kind of things that happen. Chaining a series of far-fetched
vulnerabilities is a reality, and trying to defend against those
things via simple best practices can be effective.

If you want an invented example, how about a uid-0 service (let's say
listening on dbus) that takes arguments for some command (say "df")
and let's say it's really badly written, and filters all shell metas
except ";" so it'll run "df -- $arg" where $arg can't contain any $IFS
characters, but can lead with a semi-colon, meaning it can run a
single command but can't control arguments. Let's say there's nothing
else on the system that just running it will cause a problem, and so a
second flaw in some other service (or maybe the same one) can write
files to arbitrary locations, and the only writable and executable
location in the filesystem tree is /dev (e.g. all other locations are
either read-only or noexec). So an attacker writes a file to /dev/evil
and then uses the other flaw to run it.

-Kees

--
Kees Cook
Chrome OS Security

2012-11-21 00:24:41

by Alan

[permalink] [raw]
Subject: Re: [PATCH v3] devtmpfs: mount with noexec and nosuid

> I'm not trying to say it's a magic cure-all. This feature is just for
> trying to build a system that follows security best-practices: nothing

If you want to talk about security practices then please do so rather
than using it as a magic label for cluelessness.

> I don't need a specific example to follow best practices. Any example

Yes you do. You should be able to accurately describe the attack vector,
the bounding constraints and the breach of those constraints.. so your
example will do fine.

> If you want an invented example, how about a uid-0 service (let's say
> listening on dbus) that takes arguments for some command (say "df")
> and let's say it's really badly written, and filters all shell metas
> except ";" so it'll run "df -- $arg" where $arg can't contain any $IFS
> characters, but can lead with a semi-colon, meaning it can run a
> single command but can't control arguments. Let's say there's nothing
> else on the system that just running it will cause a problem, and so a
> second flaw in some other service (or maybe the same one) can write
> files to arbitrary locations, and the only writable and executable
> location in the filesystem tree is /dev (e.g. all other locations are
> either read-only or noexec). So an attacker writes a file to /dev/evil
> and then uses the other flaw to run it.

Which is fixed by using a mount syscall in userspace. Even better that
can be done and deployed on existing systems without a kernel change and
without having to move to a new kernel. From a good practice point of
view you are arguing for the wrong thing - poorer comaptibility, riskier
deployment, more code executed at higher privilege levels.

The *only* case I can see where the feature is useful is enforcing no
exec on /dev/ except for (potentially specific) device nodes. I can do
that today with AppArmour, Smack or SELinux but having a lighter way to
do it might be useful.

Alan

2012-11-21 06:44:54

by Roland Eggner

[permalink] [raw]
Subject: Re: [PATCH v3] devtmpfs: mount with noexec and nosuid

On 2012-11-20 Tuesday at 13:50 -0800 Kees Cook wrote:
> Since devtmpfs is writable, make the default noexec,nosuid as well. This
> protects from the case of a privileged process having an arbitrary file
> write flaw and an argumentless arbitrary execution (i.e. it would lack
> the ability to run "mount -o remount,exec,suid /dev").
>
> Rather than relying on userspace "mount -o remount,noexec,nosuid /dev",
> accomplish this from the kernel. This means no additional exec during
> (potentially time-sensitive) boot is needed. The kernel is responsible
> for this mount, so the mount flags should be configurable.
>
> Cc: [email protected]
> Cc: Kay Sievers <[email protected]>
> Cc: Roland Eggner <[email protected]>
> Signed-off-by: Kees Cook <[email protected]>
>
> ---
> v3:
> - use a single define for the mount flags, suggested by Greg K.H.
> v2:
> - use CONFIG_DEVTMPFS_SAFE to wrap the logic.
> ---
> drivers/base/Kconfig | 12 ++++++++++++
> drivers/base/devtmpfs.c | 11 +++++++++--
> 2 files changed, 21 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
> index b34b5cd..a37fcf2 100644
> --- a/drivers/base/Kconfig
> +++ b/drivers/base/Kconfig
> @@ -56,6 +56,18 @@ config DEVTMPFS_MOUNT
> rescue mode with init=/bin/sh, even when the /dev directory
> on the rootfs is completely empty.
>
> +config DEVTMPFS_SAFE

Can we afford 2 additional characters and name it “DEVTMPFS_NOEXEC”?

> + bool "Use nosuid,noexec mount options on devtmpfs"
> + depends on DEVTMPFS
> + help
> + This instructs the kernel to include the MS_NOEXEC and
> + MS_NOSUID mount flags when mounting devtmpfs. This prevents
> + certain kinds of code-execution attacks on embedded platforms.
> +
> + Notice: If enabled, things like /dev/mem cannot be mmapped
> + with the PROT_EXEC flag. This can break, for example, non-KMS
> + video drivers.
Proposal:
help
This instructs the kernel to include the MS_NOEXEC and MS_NOSUID mount
flags when mounting devtmpfs.
In-kernel separation of executable and non-executable code combined
with a proper executability policy is a basic technique to protect
against exploits by buggy or malicious code or hardware errors. In
terms of overhead it is a low-cost-high-effect technique especially on
platforms with dedicated hardware support, e.g. x86_64 (look for "NX"
feature in BIOS settings). Mounting devtmpfs with MS_NOEXEC flag is
an essential building-block for this security technique.

Notice: If enabled, software which depends on execution of
runtime-generated code can only be used with restricted feature set or
not at all, e.g. proprietary video drivers, JIT-compilers, most modern
web browsers. The grsecurity-patchset provides exception mechanisms to
solve this problem for e.g. desktop systems.

For server and embedded systems with HA-requirements consider Y.
For desktop systems say N unless you know what you do.

Apart from that …
Acked-by: Roland Eggner

> +
> config STANDALONE
> bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
> default y
> diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
> index 147d1a4..e44ca1d 100644
> --- a/drivers/base/devtmpfs.c
> +++ b/drivers/base/devtmpfs.c
> @@ -25,6 +25,12 @@
> #include <linux/slab.h>
> #include <linux/kthread.h>
>
> +#ifdef CONFIG_DEVTMPFS_SAFE
> +# define DEVTMPFS_MFLAGS (MS_SILENT | MS_NOEXEC | MS_NOSUID)
> +#else
> +# define DEVTMPFS_MFLAGS MS_SILENT
> +#endif
> +
> static struct task_struct *thread;
>
> #if defined CONFIG_DEVTMPFS_MOUNT
> @@ -347,7 +353,8 @@ int devtmpfs_mount(const char *mntdir)
> if (!thread)
> return 0;
>
> - err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs", MS_SILENT, NULL);
> + err = sys_mount("devtmpfs", (char *)mntdir, "devtmpfs",
> + DEVTMPFS_MFLAGS, NULL);
> if (err)
> printk(KERN_INFO "devtmpfs: error mounting %i\n", err);
> else
> @@ -372,7 +379,7 @@ static int devtmpfsd(void *p)
> *err = sys_unshare(CLONE_NEWNS);
> if (*err)
> goto out;
> - *err = sys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
> + *err = sys_mount("devtmpfs", "/", "devtmpfs", DEVTMPFS_MFLAGS, options);
> if (*err)
> goto out;
> sys_chdir("/.."); /* will traverse into overmounted root */
> --
> 1.7.9.5
>
>
> --
> Kees Cook
> Chrome OS Security


Attachments:
(No filename) (4.31 kB)
(No filename) (198.00 B)
Download all attachments

2012-11-21 12:36:52

by Alan

[permalink] [raw]
Subject: Re: [PATCH v3] devtmpfs: mount with noexec and nosuid

> This instructs the kernel to include the MS_NOEXEC and MS_NOSUID mount
> flags when mounting devtmpfs.

So does a mount syscall

> In-kernel separation of executable and non-executable code combined
> with a proper executability policy is a basic technique to protect
> against exploits by buggy or malicious code or hardware errors. In
> terms of overhead it is a low-cost-high-effect technique especially on
> platforms with dedicated hardware support, e.g. x86_64 (look for "NX"
> feature in BIOS settings). Mounting devtmpfs with MS_NOEXEC flag is
> an essential building-block for this security technique.

Which is done via a mount syscall

>
> Notice: If enabled, software which depends on execution of
> runtime-generated code can only be used with restricted feature set or
> not at all, e.g. proprietary video drivers, JIT-compilers, most modern
> web browsers. The grsecurity-patchset provides exception mechanisms to
> solve this problem for e.g. desktop systems.

We don't generally advertise random third party patches in Kconfig
>
> For server and embedded systems with HA-requirements consider Y.

That is totally misleading. HA has no connection to security and sever
and most embedded systems have nothing to gain from this feature as they
have both other writable storage and interpreters available. So if you
are attacking a server box you don't care about noexec, you feed the
script to perl.

NAK