xorl %eax, %eax

Linux kernel CAP_FS_SET Missing Capabilities

leave a comment »

Another great bug from Linux kernel 2.6.30-rc2’s ChangeLog. The discussion about this bug was started on 11 March 2009 by a post of Igor Zhbanov at LKML. This is a design flaw in the POSIX Capabilities of the Linux kernel and as I. Zhbanov pointed out:

Suppose you have NFS-share exported even with root_squash option.
If one client was compromised, local root can set CAP_MKNOD to some
local user’s process. Then that user can execute mknod to create a device
that will be owned by that user, e.g. block device file for /dev/hda hard drive.And he can create that device file on NFS-share (even exported with root_squash
option). After that he can someway (ssh, cgi) execute code on another nfs client
or the server to modify it’s filesystem. It will be possible because
he owns that
device file on nfs share.

And this is just an example since this capability is used in various functions apart from NFS. This missing CAP_MKNOD and CAP_LINUX_IMMUTABLE capabilities to the flawed capabilities CAP_FS_SET and CAP_NFSD_SET at include/linux/capability.h were patched like this:

        for (__capi = 0; __capi < _KERNEL_CAPABILITY_U32S; ++__capi)

+ *
+ * The fs mask is all the privileges that fsuid==0 historically meant.
+ * At one time in the past, that included CAP_MKNOD and CAP_LINUX_IMMUTABLE.
+ *
+ * It has never meant setting security.* and trusted.* xattrs.
+ *
+ * We could also define fsmask as follows:
+ *   1. CAP_FS_MASK is the privilege to bypass all fs-related DAC permissions
+ *   2. The security.* and trusted.* xattrs are fs-related MAC permissions
+ */
 # define CAP_FS_MASK_B0     (CAP_TO_MASK(CAP_CHOWN)            \
+                           | CAP_TO_MASK(CAP_MKNOD)            \
                            | CAP_TO_MASK(CAP_DAC_OVERRIDE)     \
                            | CAP_TO_MASK(CAP_DAC_READ_SEARCH)  \
                            | CAP_TO_MASK(CAP_FOWNER)           \

And the rest of the patching…

 # define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }})
-# define CAP_FS_SET       ((kernel_cap_t){{ CAP_FS_MASK_B0, CAP_FS_MASK_B1 } })
+# define CAP_FS_SET       ((kernel_cap_t){{ CAP_FS_MASK_B0 \
+                                   | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \
+                                   CAP_FS_MASK_B1 } })
 # define CAP_NFSD_SET     ((kernel_cap_t){{ CAP_FS_MASK_B0 \
-                                           | CAP_TO_MASK(CAP_SYS_RESOURCE) \
-                                           | CAP_TO_MASK(CAP_MKNOD), \
-                                           CAP_FS_MASK_B1 } })
+                                   | CAP_TO_MASK(CAP_SYS_RESOURCE), \
+                                   CAP_FS_MASK_B1 } })

 #endif /* _KERNEL_CAPABILITY_U32S != 2 */

Unfortunately I haven’t spend any time in exploiting this yet and I cannot give any hints but if I have time I’ll do it tomorrow. :-)

[more info]

Written by xorl

April 25, 2009 at 00:47

Posted in bugs, linux

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