[tomoyo-users-en 240] Re: [tomoyo-dev-en 22] Re: TOMOYO and YAMA

Back to archive index
Jamie Nguyen dysco****@gmail*****
Thu Dec 2 00:46:09 JST 2010


Hi,

I actually falsely thought that yama had already been integrated, but
now realise that this is not the case. I can't tell from the
discussions on LKML whether yama will make 2.6.37 or not.

The latest patch I could find was here [1]. It couldn't apply, so
after manually applying changes, I have posted my own working patch
for 2.6.36.1 Linux kernel in case anyone is interested [2]. I can
confirm that both ccs-patch and yama are doing their job correctly. It
shouldn't matter which order ccs-patch and yama are applied in. I also
copy this to tomoyo-users-en for those interested (which is probably
more appropriate place for this thread anyway).

Now I have working ccs-patched kernel with extra symlink, hardlink and
ptrace scope restrictions that can in particular defend against /tmp
race conditions (among other things) :-)


Kind regards



[1] http://lkml.org/lkml/2010/6/28/233

[2]

diff -uNr linux-2.6.36/Documentation/Yama.txt
linux-2.6.36.new/Documentation/Yama.txt
--- linux-2.6.36/Documentation/Yama.txt 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.36.new/Documentation/Yama.txt     2010-12-01
14:51:55.459000003 +0000
@@ -0,0 +1,91 @@
+Yama is a Linux Security Module that collects a number of security
+protections that are not handled by the core kernel itself.  To select
+it at boot time, specify "security=yama" (though this will disable any
+other LSM).
+
+Yama is controlled through sysctl in /proc/sys/kernel/yama:
+
+- protected_sticky_symlinks
+- protected_nonaccess_hardlinks
+- ptrace_scope
+
+==============================================================
+
+protected_sticky_symlinks:
+
+A long-standing class of security issues is the symlink-based
+time-of-check-time-of-use race, most commonly seen in world-writable
+directories like /tmp. The common method of exploitation of this flaw
+is to cross privilege boundaries when following a given symlink (i.e. a
+root process follows a symlink belonging to another user).  For a likely
+incomplete list of hundreds of examples across the years, please see:
+http://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=/tmp
+
+When set to "0", symlink following behavior is unrestricted.
+
+When set to "1" symlinks are permitted to be followed only when outside
+a sticky world-writable directory, or when the uid of the symlink and
+follower match, or when the directory owner matches the symlink's owner.
+
+This protection is based on the restrictions in Openwall and grsecurity.
+
+==============================================================
+
+protected_nonaccess_hardlinks:
+
+Hardlinks can be abused in a similar fashion to symlinks in sticky
+world-writable directories, but their weakness is not limited to
+just that scenario. For example, if /etc and /home are on the same
+partition, a regular user can create a hardlink to /etc/shadow in their
+home directory. While it retains the original owner and permissions,
+it is possible for privileged programs that are otherwise symlink-safe
+to mistakenly access the file through its hardlink. Additionally, a very
+minor untraceable quota-bypassing local denial of service is possible by
+an attacker exhausting disk space by filling a world-writable directory
+with hardlinks.
+
+When set to "0", hardlink creation behavior is unrestricted.
+
+When set to "1", hardlinks cannot be created to files that a given user
+would be unable to read and write originally, or are otherwise sensitive.
+
+This protection is based on the restrictions in Openwall and grsecurity.
+
+==============================================================
+
+ptrace_scope:
+
+As Linux grows in popularity, it will become a larger target for
+malware. One particularly troubling weakness of the Linux process
+interfaces is that a single user is able to examine the memory and
+running state of any of their processes. For example, if one application
+(e.g. Pidgin) was compromised, it would be possible for an attacker to
+attach to other running processes (e.g. Firefox, SSH sessions, GPG agent,
+etc) to extract additional credentials and continue to expand the scope
+of their attack without resorting to user-assisted phishing.
+
+This is not a theoretical problem. SSH session hijacking
+(http://www.storm.net.nz/projects/7) and arbitrary code injection
+(http://c-skills.blogspot.com/2007/05/injectso.html) attacks already
+exist and remain possible if PTRACE is allowed to operate as before.
+PTRACE is not commonly used by non-developers and non-admins, so system
+builders should be allowed the option to disable this debugging system.
+
+For a solution, some applications use prctl(PR_SET_DUMPABLE, ...) to
+specifically disallow such PTRACE attachment (e.g. ssh-agent), but many
+do not. A more general solution is to only allow PTRACE directly from a
+parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still
+work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID"
+still work as root).
+
+0 - classic PTRACE permissions: a process can PTRACE any other process
+    running under the same uid, as long as it is dumpable (i.e. did not
+    transition uids, start privileged, or have prctl(PR_SET_DUMPABLE...)
+    called).
+
+1 - child-only PTRACE: a process can PTRACE only its descendants when
+    the above classic criteria is also met.
+
+This protection is based on the restrictions in grsecurity.
+
+==============================================================
diff -uNr linux-2.6.36/security/Kconfig linux-2.6.36.new/security/Kconfig
--- linux-2.6.36/security/Kconfig       2010-12-01 14:54:31.538000003 +0000
+++ linux-2.6.36.new/security/Kconfig   2010-12-01 14:50:19.547000003 +0000
@@ -140,6 +140,7 @@
 source security/selinux/Kconfig
 source security/smack/Kconfig
 source security/tomoyo/Kconfig
+source security/yama/Kconfig
 source security/apparmor/Kconfig

 source security/integrity/ima/Kconfig
@@ -165,6 +166,9 @@
        config DEFAULT_SECURITY_TOMOYO
                bool "TOMOYO" if SECURITY_TOMOYO=y

+    config DEFAULT_SECURITY_YAMA
+        bool "Yama" if SECURITY_YAMA=y
+
        config DEFAULT_SECURITY_APPARMOR
                bool "AppArmor" if SECURITY_APPARMOR=y

@@ -178,6 +182,7 @@
        default "selinux" if DEFAULT_SECURITY_SELINUX
        default "smack" if DEFAULT_SECURITY_SMACK
        default "tomoyo" if DEFAULT_SECURITY_TOMOYO
+    default "yama" if DEFAULT_SECURITY_YAMA
        default "apparmor" if DEFAULT_SECURITY_APPARMOR
        default "" if DEFAULT_SECURITY_DAC

diff -uNr linux-2.6.36/security/Makefile linux-2.6.36.new/security/Makefile
--- linux-2.6.36/security/Makefile      2010-12-01 14:54:31.538000003 +0000
+++ linux-2.6.36.new/security/Makefile  2010-12-01 14:51:15.227000003 +0000
@@ -6,6 +6,7 @@
 subdir-$(CONFIG_SECURITY_SELINUX)      += selinux
 subdir-$(CONFIG_SECURITY_SMACK)                += smack
 subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
+subdir-$(CONFIG_SECURITY_YAMA)      += yama
 subdir-$(CONFIG_SECURITY_APPARMOR)     += apparmor

 # always enable default capabilities
@@ -20,6 +21,7 @@
 obj-$(CONFIG_SECURITY_SMACK)           += smack/built-in.o
 obj-$(CONFIG_AUDIT)                    += lsm_audit.o
 obj-$(CONFIG_SECURITY_TOMOYO)          += tomoyo/built-in.o
+obj-$(CONFIG_SECURITY_YAMA)                    += yama/built-in.o
 obj-$(CONFIG_SECURITY_APPARMOR)                += apparmor/built-in.o
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o

diff -uNr linux-2.6.36/security/yama/Kconfig
linux-2.6.36.new/security/yama/Kconfig
--- linux-2.6.36/security/yama/Kconfig  1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.36.new/security/yama/Kconfig      2010-12-01
14:52:02.340000003 +0000
@@ -0,0 +1,13 @@
+config SECURITY_YAMA
+   bool "Yama NAC Support"
+   depends on SECURITY
+   select SECURITYFS
+   select SECURITY_PATH
+   default n
+   help
+     This selects Yama, the NAKed Access Control system which
+     provides additional global security settings above regular
+     Linux discretionary access controls.  Currently available
+     are symlink, hardlink, and PTRACE scope restrictions.
+
+     If you are unsure how to answer this question, answer N.
diff -uNr linux-2.6.36/security/yama/Makefile
linux-2.6.36.new/security/yama/Makefile
--- linux-2.6.36/security/yama/Makefile 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.36.new/security/yama/Makefile     2010-12-01
14:52:04.387000003 +0000
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SECURITY_YAMA) := yama.o
+
+yama-y := yama_lsm.o
diff -uNr linux-2.6.36/security/yama/yama_lsm.c
linux-2.6.36.new/security/yama/yama_lsm.c
--- linux-2.6.36/security/yama/yama_lsm.c       1970-01-01
01:00:00.000000000 +0100
+++ linux-2.6.36.new/security/yama/yama_lsm.c   2010-12-01
14:52:04.387000003 +0000
@@ -0,0 +1,235 @@
+/*
+ * Yama Linux Security Module
+ *
+ * Author: Kees Cook <kees.****@canon*****>
+ *
+ * Copyright (C) 2010 Canonical, Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/security.h>
+#include <linux/sysctl.h>
+#include <linux/ptrace.h>
+#include <linux/ratelimit.h>
+
+static int ptrace_scope = 1;
+static int protected_sticky_symlinks = 1;
+static int protected_nonaccess_hardlinks = 1;
+
+/**
+ * yama_ptrace_access_check - validate PTRACE_ATTACH calls
+ * @child: child task pointer
+ * @mode: ptrace attach mode
+ *
+ * Returns 0 if following the ptrace is allowed, -ve on error.
+ */
+static int yama_ptrace_access_check(struct task_struct *child,
+                   unsigned int mode)
+{
+   int rc;
+
+   rc = cap_ptrace_access_check(child, mode);
+   if (rc != 0)
+       return rc;
+
+   /* require ptrace target be a child of ptracer on attach */
+   if (mode == PTRACE_MODE_ATTACH && ptrace_scope &&
+       !capable(CAP_SYS_PTRACE)) {
+       struct task_struct *walker = child;
+
+       rcu_read_lock();
+       read_lock(&tasklist_lock);
+       while (walker->pid > 0) {
+           if (walker == current)
+               break;
+           walker = walker->real_parent;
+       }
+       if (walker->pid == 0)
+           rc = -EPERM;
+       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
+   }
+
+   if (rc) {
+       char name[sizeof(current->comm)];
+       printk_ratelimited(KERN_INFO "ptrace of non-child"
+           " pid %d was attempted by: %s (pid %d)\n",
+           child->pid,
+           get_task_comm(name, current),
+           current->pid);
+   }
+
+   return rc;
+}
+
+/**
+ * yama_inode_follow_link - check for symlinks in sticky world-writeable dirs
+ * @dentry: The inode/dentry of the symlink
+ * @nameidata: The path data of the symlink
+ *
+ * In the case of the protected_sticky_symlinks sysctl being enabled,
+ * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is
+ * in a sticky world-writable directory.  This is to protect privileged
+ * processes from failing races against path names that may change out
+ * from under them by way of other users creating malicious symlinks.
+ * It will permit symlinks to only be followed when outside a sticky
+ * world-writable directory, or when the uid of the symlink and follower
+ * match, or when the directory owner matches the symlink's owner.
+ *
+ * Returns 0 if following the symlink is allowed, -ve on error.
+ */
+static int yama_inode_follow_link(struct dentry *dentry,
+                 struct nameidata *nameidata)
+{
+   int rc = 0;
+   const struct inode *parent;
+   const struct inode *inode;
+   const struct cred *cred;
+
+   if (!protected_sticky_symlinks)
+       return 0;
+
+   /* owner and follower match? */
+   cred = current_cred();
+   inode = dentry->d_inode;
+   if (cred->fsuid == inode->i_uid)
+       return 0;
+
+   /* check parent directory mode and owner */
+   spin_lock(&dentry->d_lock);
+   parent = dentry->d_parent->d_inode;
+   if ((parent->i_mode & (S_ISVTX|S_IWOTH)) == (S_ISVTX|S_IWOTH) &&
+       parent->i_uid != inode->i_uid) {
+       rc = -EACCES;
+   }
+   spin_unlock(&dentry->d_lock);
+
+   if (rc) {
+       char name[sizeof(current->comm)];
+       printk_ratelimited(KERN_NOTICE "non-matching-uid symlink "
+           "following attempted in sticky world-writable "
+           "directory by %s (fsuid %d != %d)\n",
+           get_task_comm(name, current),
+           cred->fsuid, inode->i_uid);
+   }
+
+   return rc;
+}
+
+/**
+ * yama_path_link - verify that hardlinking is allowed
+ * @old_dentry: the source inode/dentry to hardlink from
+ * @new_dir: target directory
+ * @new_dentry: the target inode/dentry to hardlink to
+ *
+ * Block hardlink when all of:
+ *  - fsuid does not match inode
+ *  - not CAP_FOWNER
+ *  - and at least one of:
+ *    - inode is not a regular file
+ *    - inode is setuid
+ *    - inode is setgid and group-exec
+ *    - access failure for read and write
+ *
+ * Returns 0 if successful, -ve on error.
+ */
+static int yama_path_link(struct dentry *old_dentry, struct path *new_dir,
+             struct dentry *new_dentry)
+{
+   int rc = 0;
+   struct inode *inode = old_dentry->d_inode;
+   const int mode = inode->i_mode;
+   const struct cred *cred = current_cred();
+
+   if (!protected_nonaccess_hardlinks)
+       return 0;
+
+   if (cred->fsuid != inode->i_uid &&
+       (!S_ISREG(mode) || (mode & S_ISUID) ||
+        ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) ||
+        (generic_permission(inode, MAY_READ | MAY_WRITE, NULL))) &&
+       !capable(CAP_FOWNER)) {
+       char name[sizeof(current->comm)];
+       printk_ratelimited(KERN_INFO "non-accessible hardlink"
+           " creation was attempted by: %s (fsuid %d)\n",
+           get_task_comm(name, current),
+           cred->fsuid);
+       rc = -EPERM;
+   }
+
+   return rc;
+}
+
+static struct security_operations yama_ops = {
+   .name =         "yama",
+
+   .ptrace_access_check =  yama_ptrace_access_check,
+   .inode_follow_link =    yama_inode_follow_link,
+   .path_link =        yama_path_link,
+};
+
+#ifdef CONFIG_SYSCTL
+static int zero;
+static int one = 1;
+
+struct ctl_path yama_sysctl_path[] = {
+   { .procname = "kernel", },
+   { .procname = "yama", },
+   { }
+};
+
+static struct ctl_table yama_sysctl_table[] = {
+   {
+       .procname       = "protected_sticky_symlinks",
+       .data           = &protected_sticky_symlinks,
+       .maxlen         = sizeof(int),
+       .mode           = 0644,
+       .proc_handler   = proc_dointvec_minmax,
+       .extra1         = &zero,
+       .extra2         = &one,
+   },
+   {
+       .procname       = "protected_nonaccess_hardlinks",
+       .data           = &protected_nonaccess_hardlinks,
+       .maxlen         = sizeof(int),
+       .mode           = 0644,
+       .proc_handler   = proc_dointvec_minmax,
+       .extra1         = &zero,
+       .extra2         = &one,
+   },
+   {
+       .procname       = "ptrace_scope",
+       .data           = &ptrace_scope,
+       .maxlen         = sizeof(int),
+       .mode           = 0644,
+       .proc_handler   = proc_dointvec_minmax,
+       .extra1         = &zero,
+       .extra2         = &one,
+   },
+   { }
+};
+#endif /* CONFIG_SYSCTL */
+
+static __init int yama_init(void)
+{
+   if (!security_module_enable(&yama_ops))
+       return 0;
+
+   printk(KERN_INFO "Yama: becoming mindful.\n");
+
+   if (register_security(&yama_ops))
+       panic("Yama: kernel registration failed.\n");
+
+#ifdef CONFIG_SYSCTL
+   if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))
+       panic("Yama: sysctl registration failed.\n");
+#endif
+
+   return 0;
+}
+
+security_initcall(yama_init);




More information about the tomoyo-users-en mailing list
Back to archive index