[kernel] r18763 - in dists/sid/linux-2.6/debian: . config patches/features/all patches/series

Ben Hutchings benh at alioth.debian.org
Fri Mar 2 04:49:27 UTC 2012


Author: benh
Date: Fri Mar  2 04:49:25 2012
New Revision: 18763

Log:
fs: Introduce and enable security restrictions on links

Add the longstanding symlink and hard link restriction patches as
found in mmotm.  Explicitly enable these restrictions and point to the
documentation.

Added:
   dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restriction-cleanup.patch
   dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restrictions-fix.patch
   dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restrictions.patch
   dists/sid/linux-2.6/debian/patches/features/all/fs-symlink-restrictions-on-sticky-directories-fix-2.patch
   dists/sid/linux-2.6/debian/patches/features/all/fs-symlink-restrictions-on-sticky-directories.patch
Modified:
   dists/sid/linux-2.6/debian/changelog
   dists/sid/linux-2.6/debian/config/config
   dists/sid/linux-2.6/debian/patches/series/base

Modified: dists/sid/linux-2.6/debian/changelog
==============================================================================
--- dists/sid/linux-2.6/debian/changelog	Fri Mar  2 03:30:27 2012	(r18762)
+++ dists/sid/linux-2.6/debian/changelog	Fri Mar  2 04:49:25 2012	(r18763)
@@ -20,6 +20,13 @@
     - Update Dutch (Willem Kuyn) (Closes: #658736)
     - Add Polish (Michał Kułach) (Closes: #658912)
   * Bump ABI to 2
+  * fs: Introduce and enable security restrictions on links:
+    - Do not follow symlinks in /tmp that are owned by other users
+      (sysctl: fs.protected_symlinks)
+    - Do not allow unprivileged users to create hard links to sensitive files
+      (sysctl: fs.protected_hardlinks) (Closes: #609455)
+    The precise restrictions are specified in Documentation/sysctl/fs.txt in
+    the linux-doc-3.2 and linux-source-3.2 packages.
 
  -- Bastian Blank <waldi at debian.org>  Thu, 01 Mar 2012 11:47:17 +0100
 

Modified: dists/sid/linux-2.6/debian/config/config
==============================================================================
--- dists/sid/linux-2.6/debian/config/config	Fri Mar  2 03:30:27 2012	(r18762)
+++ dists/sid/linux-2.6/debian/config/config	Fri Mar  2 04:49:25 2012	(r18763)
@@ -3254,6 +3254,9 @@
 CONFIG_HUGETLBFS=y
 CONFIG_MISC_FILESYSTEMS=y
 CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_PROTECTED_LINKS=y
+CONFIG_PROTECTED_SYMLINKS=y
+CONFIG_PROTECTED_HARDLINKS=y
 
 ##
 ## file: fs/9p/Kconfig

Added: dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restriction-cleanup.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restriction-cleanup.patch	Fri Mar  2 04:49:25 2012	(r18763)
@@ -0,0 +1,112 @@
+From 52db90d0fa770e2277645eb34956820cec26b2cb Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook at chromium.org>
+Date: Sat, 25 Feb 2012 12:28:44 +1100
+Subject: [PATCH 5/5] fs: hardlink creation restriction cleanup
+
+Clean-up of hardlink restriction logic, as suggested by Andrew Morton.
+
+Signed-off-by: Kees Cook <keescook at chromium.org>
+Cc: Ingo Molnar <mingo at elte.hu>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+---
+ fs/namei.c |   62 ++++++++++++++++++++++++++++++++++++++++++-----------------
+ 1 files changed, 44 insertions(+), 18 deletions(-)
+
+diff --git a/fs/namei.c b/fs/namei.c
+index fe13533..1436fae 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -693,46 +693,72 @@ static inline int may_follow_link(struct path *link)
+ }
+ 
+ /**
++ * safe_hardlink_source - Check for safe hardlink conditions
++ * @inode: the source inode to hardlink from
++ *
++ * Return false if at least one of the following conditions:
++ *    - inode is not a regular file
++ *    - inode is setuid
++ *    - inode is setgid and group-exec
++ *    - access failure for read and write
++ *
++ * Otherwise returns true.
++ */
++static bool safe_hardlink_source(struct inode *inode)
++{
++	mode_t mode = inode->i_mode;
++
++	/* Special files should not get pinned to the filesystem. */
++	if (!S_ISREG(mode))
++		return false;
++
++	/* Setuid files should not get pinned to the filesystem. */
++	if (mode & S_ISUID)
++		return false;
++
++	/* Executable setgid files should not get pinned to the filesystem. */
++	if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
++		return false;
++
++	/* Hardlinking to unreadable or unwritable sources is dangerous. */
++	if (inode_permission(inode, MAY_READ | MAY_WRITE))
++		return false;
++
++	return true;
++}
++
++/**
+  * may_linkat - Check permissions for creating a hardlink
+  * @link: the source to hardlink from
+  *
+  * Block hardlink when all of:
+  *  - sysctl_protected_hardlinks enabled
+  *  - fsuid does not match inode
+- *  - 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
++ *  - hardlink source is unsafe (see safe_hardlink_source() above)
+  *  - not CAP_FOWNER
+  *
+  * Returns 0 if successful, -ve on error.
+  */
+ static int may_linkat(struct path *link)
+ {
+-	int error = 0;
+ 	const struct cred *cred;
+ 	struct inode *inode;
+-	int mode;
+ 
+ 	if (!sysctl_protected_hardlinks)
+ 		return 0;
+ 
+ 	cred = current_cred();
+ 	inode = link->dentry->d_inode;
+-	mode = inode->i_mode;
+-
+-	if (cred->fsuid != inode->i_uid &&
+-	    (!S_ISREG(mode) || (mode & S_ISUID) ||
+-	     ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) ||
+-	     (inode_permission(inode, MAY_READ | MAY_WRITE))) &&
+-	    !capable(CAP_FOWNER))
+-		error = -EPERM;
+ 
+-	if (error)
+-		audit_log_link_denied("linkat", link);
++	/* Source inode owner (or CAP_FOWNER) can hardlink all they like,
++	 * otherwise, it must be a safe source.
++	 */
++	if (cred->fsuid == inode->i_uid || safe_hardlink_source(inode) ||
++	    capable(CAP_FOWNER))
++		return 0;
+ 
+-	return error;
++	audit_log_link_denied("linkat", link);
++	return -EPERM;
+ }
+ #else
+ static inline int may_follow_link(struct path *link)
+-- 
+1.7.9.1
+

Added: dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restrictions-fix.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restrictions-fix.patch	Fri Mar  2 04:49:25 2012	(r18763)
@@ -0,0 +1,39 @@
+From 19f621ccbef745dedad641f44f535e3bcb00f30d Mon Sep 17 00:00:00 2001
+From: Andrew Morton <akpm at linux-foundation.org>
+Date: Sat, 25 Feb 2012 12:28:43 +1100
+Subject: [PATCH 4/5] fs-hardlink-creation-restrictions-fix
+
+uninline may_linkat() and audit_log_link_denied().
+
+Cc: Kees Cook <keescook at chromium.org>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+---
+ fs/namei.c |    5 ++---
+ 1 files changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/fs/namei.c b/fs/namei.c
+index 7be190c..fe13533 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -629,8 +629,7 @@ int sysctl_protected_symlinks __read_mostly =
+ int sysctl_protected_hardlinks __read_mostly =
+ 	CONFIG_PROTECTED_HARDLINKS_SYSCTL;
+ 
+-static inline void
+-audit_log_link_denied(const char *operation, struct path *link)
++static void audit_log_link_denied(const char *operation, struct path *link)
+ {
+ 	struct audit_buffer *ab;
+ 
+@@ -709,7 +708,7 @@ static inline int may_follow_link(struct path *link)
+  *
+  * Returns 0 if successful, -ve on error.
+  */
+-static inline int may_linkat(struct path *link)
++static int may_linkat(struct path *link)
+ {
+ 	int error = 0;
+ 	const struct cred *cred;
+-- 
+1.7.9.1
+

Added: dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restrictions.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/fs-hardlink-creation-restrictions.patch	Fri Mar  2 04:49:25 2012	(r18763)
@@ -0,0 +1,390 @@
+From fa3abdeee4e792ed794eef7ea71e7e0073cec32d Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook at chromium.org>
+Date: Sat, 25 Feb 2012 12:28:43 +1100
+Subject: [PATCH 3/5] fs: hardlink creation restrictions
+
+On systems that have user-writable directories on the same partition as
+system files, a long-standing class of security issues is the
+hardlink-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
+hardlink (i.e.  a root process follows a hardlink created by another
+user).  Additionally, an issue exists where users can "pin" a potentially
+vulnerable setuid/setgid file so that an administrator will not actually
+upgrade a system fully.
+
+The solution is to permit hardlinks to only be created when the user is
+already the existing file's owner, or if they already have read/write
+access to the existing file.
+
+Many Linux users are surprised when they learn they can link to files they
+have no access to, so this change appears to follow the doctrine of "least
+surprise".  Additionally, this change does not violate POSIX, which states
+"the implementation may require that the calling process has permission to
+access the existing file"[1].
+
+This change is known to break some implementations of the "at" daemon,
+though the version used by Fedora and Ubuntu has been fixed[2] for a
+while.  Otherwise, the change has been undisruptive while in use in Ubuntu
+for the last 1.5 years.
+
+This patch is based on the patch in Openwall and grsecurity.  I have added
+a sysctl to enable the protected behavior, documentation, and an audit
+notification.
+
+[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html
+[2] http://anonscm.debian.org/gitweb/?p=collab-maint/at.git;a=commitdiff;h=f4114656c3a6c6f6070e315ffdf940a49eda3279
+
+Signed-off-by: Kees Cook <keescook at chromium.org>
+Acked-by: Ingo Molnar <mingo at elte.hu>
+Cc: Matthew Wilcox <matthew at wil.cx>
+Cc: Alexander Viro <viro at zeniv.linux.org.uk>
+Cc: Rik van Riel <riel at redhat.com>
+Cc: Federica Teodori <federica.teodori at googlemail.com>
+Cc: Lucian Adrian Grijincu <lucian.grijincu at gmail.com>
+Cc: Peter Zijlstra <a.p.zijlstra at chello.nl>
+Cc: Eric Paris <eparis at redhat.com>
+Cc: Randy Dunlap <rdunlap at xenotime.net>
+Cc: Dan Rosenberg <drosenberg at vsecurity.com>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+---
+ Documentation/sysctl/fs.txt |   21 ++++++++
+ fs/Kconfig                  |   54 ++++++++++++++++------
+ fs/namei.c                  |  109 ++++++++++++++++++++++++++++++++-----------
+ include/linux/fs.h          |    1 +
+ kernel/sysctl.c             |   11 ++++-
+ 5 files changed, 153 insertions(+), 43 deletions(-)
+
+diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
+index 01daa80..9d29414 100644
+--- a/Documentation/sysctl/fs.txt
++++ b/Documentation/sysctl/fs.txt
+@@ -32,6 +32,7 @@ Currently, these files are in /proc/sys/fs:
+ - nr_open
+ - overflowuid
+ - overflowgid
++- protected_hardlinks
+ - protected_symlinks
+ - suid_dumpable
+ - super-max
+@@ -158,6 +159,26 @@ The default is 65534.
+ 
+ ==============================================================
+ 
++protected_hardlinks:
++
++A long-standing class of security issues is the hardlink-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 hardlink (i.e. a
++root process follows a hardlink created by another user). Additionally,
++on systems without separated partitions, this stops unauthorized users
++from "pinning" vulnerable setuid/setgid files against being upgraded by
++the administrator, or linking to special files.
++
++When set to "0", hardlink creation behavior is unrestricted.
++
++When set to "1" hardlinks cannot be created by users if they do not
++already own the source file, or do not have read/write access to it.
++
++This protection is based on the restrictions in Openwall and grsecurity.
++
++==============================================================
++
+ protected_symlinks:
+ 
+ A long-standing class of security issues is the symlink-based
+diff --git a/fs/Kconfig b/fs/Kconfig
+index f2c46f3..d2a422e 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -272,27 +272,29 @@ endif # NETWORK_FILESYSTEMS
+ source "fs/nls/Kconfig"
+ source "fs/dlm/Kconfig"
+ 
+-config PROTECTED_SYMLINKS
+-	bool "Evaluate vulnerable symlink conditions"
++config PROTECTED_LINKS
++	bool "Evaluate vulnerable link conditions"
+ 	default y
+ 	help
+-	  A long-standing class of security issues is the symlink-based
++	  A long-standing class of security issues is the link-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 malicious symlink belonging to another user).
++	  when following a given link (i.e. a root process follows
++	  a malicious symlink belonging to another user, or a hardlink
++	  created to a root-owned file).
+ 
+-	  Enabling this adds the logic to examine these dangerous symlink
+-	  conditions. Whether or not the dangerous symlink situations are
+-	  allowed is controlled by PROTECTED_SYMLINKS_ENABLED.
++	  Enabling this adds the logic to examine these dangerous link
++	  conditions. Whether or not the dangerous link situations are
++	  allowed is controlled by PROTECTED_HARDLINKS_ENABLED and
++	  PROTECTED_SYMLINKS_ENABLED.
+ 
+-config PROTECTED_SYMLINKS_ENABLED
+-	depends on PROTECTED_SYMLINKS
++config PROTECTED_SYMLINKS
++	depends on PROTECTED_LINKS
+ 	bool "Disallow symlink following in sticky world-writable dirs"
+ 	default y
+ 	help
+-	  Solve ToCToU symlink race vulnerablities by permitting symlinks
++	  Solve ToCToU symlink race vulnerabilities by permitting symlinks
+ 	  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 and symlink owners match.
+@@ -300,10 +302,34 @@ config PROTECTED_SYMLINKS_ENABLED
+ 	  When PROC_SYSCTL is enabled, this setting can also be controlled
+ 	  via /proc/sys/kernel/protected_symlinks.
+ 
+-config PROTECTED_SYMLINKS_ENABLED_SYSCTL
+-	depends on PROTECTED_SYMLINKS
++	  See Documentation/sysctl/fs.txt for details.
++
++config PROTECTED_SYMLINKS_SYSCTL
++	depends on PROTECTED_LINKS
++	int
++	default "1" if PROTECTED_SYMLINKS
++	default "0"
++
++config PROTECTED_HARDLINKS
++	depends on PROTECTED_LINKS
++	bool "Disallow hardlink creation to non-accessible files"
++	default y
++	help
++	  Solve ToCToU hardlink race vulnerabilities by permitting hardlinks
++	  to be created only when to a regular file that is owned by the user,
++	  or is readable and writable by the user. Also blocks users from
++	  "pinning" vulnerable setuid/setgid programs from being upgraded by
++	  the administrator.
++
++	  When PROC_SYSCTL is enabled, this setting can also be controlled
++	  via /proc/sys/kernel/protected_hardlinks.
++
++	  See Documentation/sysctl/fs.txt for details.
++
++config PROTECTED_HARDLINKS_SYSCTL
++	depends on PROTECTED_LINKS
+ 	int
+-	default "1" if PROTECTED_SYMLINKS_ENABLED
++	default "1" if PROTECTED_HARDLINKS
+ 	default "0"
+ 
+ endmenu
+diff --git a/fs/namei.c b/fs/namei.c
+index 39edcf7..7be190c 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -623,16 +623,33 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
+ 	path_put(link);
+ }
+ 
+-#ifdef CONFIG_PROTECTED_SYMLINKS
++#ifdef CONFIG_PROTECTED_LINKS
+ int sysctl_protected_symlinks __read_mostly =
+-	CONFIG_PROTECTED_SYMLINKS_ENABLED_SYSCTL;
++	CONFIG_PROTECTED_SYMLINKS_SYSCTL;
++int sysctl_protected_hardlinks __read_mostly =
++	CONFIG_PROTECTED_HARDLINKS_SYSCTL;
++
++static inline void
++audit_log_link_denied(const char *operation, struct path *link)
++{
++	struct audit_buffer *ab;
++
++	ab = audit_log_start(current->audit_context, GFP_KERNEL, AUDIT_AVC);
++	audit_log_format(ab, "op=%s action=denied", operation);
++	audit_log_format(ab, " pid=%d comm=", current->pid);
++	audit_log_untrustedstring(ab, current->comm);
++	audit_log_d_path(ab, " path=", link);
++	audit_log_format(ab, " dev=");
++	audit_log_untrustedstring(ab, link->dentry->d_inode->i_sb->s_id);
++	audit_log_format(ab, " ino=%lu", link->dentry->d_inode->i_ino);
++	audit_log_end(ab);
++}
+ 
+ /**
+  * may_follow_link - Check symlink following for unsafe situations
+- * @dentry: The inode/dentry of the symlink
+- * @nameidata: The path data of the symlink
++ * @link: The path of the symlink
+  *
+- * In the case of the protected_symlinks sysctl being enabled,
++ * In the case of the sysctl_protected_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
+@@ -643,19 +660,20 @@ int sysctl_protected_symlinks __read_mostly =
+  *
+  * Returns 0 if following the symlink is allowed, -ve on error.
+  */
+-static inline int
+-may_follow_link(struct dentry *dentry, struct nameidata *nameidata)
++static inline int may_follow_link(struct path *link)
+ {
+ 	int error = 0;
+ 	const struct inode *parent;
+ 	const struct inode *inode;
+ 	const struct cred *cred;
++	struct dentry *dentry;
+ 
+ 	if (!sysctl_protected_symlinks)
+ 		return 0;
+ 
+ 	/* Allowed if owner and follower match. */
+ 	cred = current_cred();
++	dentry = link->dentry;
+ 	inode = dentry->d_inode;
+ 	if (cred->fsuid == inode->i_uid)
+ 		return 0;
+@@ -669,29 +687,61 @@ may_follow_link(struct dentry *dentry, struct nameidata *nameidata)
+ 	}
+ 	spin_unlock(&dentry->d_lock);
+ 
+-#ifdef CONFIG_AUDIT
+-	if (error) {
+-		struct audit_buffer *ab;
+-
+-		ab = audit_log_start(current->audit_context,
+-				     GFP_KERNEL, AUDIT_AVC);
+-		audit_log_format(ab, "op=follow_link action=denied");
+-		audit_log_format(ab, " pid=%d comm=", current->pid);
+-		audit_log_untrustedstring(ab, current->comm);
+-		audit_log_d_path(ab, " path=", &nameidata->path);
+-		audit_log_format(ab, " name=");
+-		audit_log_untrustedstring(ab, dentry->d_name.name);
+-		audit_log_format(ab, " dev=");
+-		audit_log_untrustedstring(ab, inode->i_sb->s_id);
+-		audit_log_format(ab, " ino=%lu", inode->i_ino);
+-		audit_log_end(ab);
+-	}
+-#endif
++	if (error)
++		audit_log_link_denied("follow_link", link);
++
++	return error;
++}
++
++/**
++ * may_linkat - Check permissions for creating a hardlink
++ * @link: the source to hardlink from
++ *
++ * Block hardlink when all of:
++ *  - sysctl_protected_hardlinks enabled
++ *  - fsuid does not match inode
++ *  - 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
++ *  - not CAP_FOWNER
++ *
++ * Returns 0 if successful, -ve on error.
++ */
++static inline int may_linkat(struct path *link)
++{
++	int error = 0;
++	const struct cred *cred;
++	struct inode *inode;
++	int mode;
++
++	if (!sysctl_protected_hardlinks)
++		return 0;
++
++	cred = current_cred();
++	inode = link->dentry->d_inode;
++	mode = inode->i_mode;
++
++	if (cred->fsuid != inode->i_uid &&
++	    (!S_ISREG(mode) || (mode & S_ISUID) ||
++	     ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) ||
++	     (inode_permission(inode, MAY_READ | MAY_WRITE))) &&
++	    !capable(CAP_FOWNER))
++		error = -EPERM;
++
++	if (error)
++		audit_log_link_denied("linkat", link);
++
+ 	return error;
+ }
+ #else
+-static inline int
+-may_follow_link(struct dentry *dentry, struct nameidata *nameidata)
++static inline int may_follow_link(struct path *link)
++{
++	return 0;
++}
++
++static inline int may_linkat(struct path *link)
+ {
+ 	return 0;
+ }
+@@ -720,7 +770,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p, bool sensitive)
+ 	nd_set_link(nd, NULL);
+ 
+ 	if (sensitive)
+-		error = may_follow_link(link->dentry, nd);
++		error = may_follow_link(link);
+ 	if (!error)
+ 		error = security_inode_follow_link(link->dentry, nd);
+ 	if (error) {
+@@ -3058,6 +3108,9 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
+ 	error = -EXDEV;
+ 	if (old_path.mnt != new_path.mnt)
+ 		goto out_dput;
++	error = may_linkat(&old_path);
++	if (error)
++		goto out_dput;
+ 	error = mnt_want_write(new_path.mnt);
+ 	if (error)
+ 		goto out_dput;
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 404cc89..f42a557 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -424,6 +424,7 @@ extern int sysctl_nr_open;
+ extern struct inodes_stat_t inodes_stat;
+ extern int leases_enable, lease_break_time;
+ extern int sysctl_protected_symlinks;
++extern int sysctl_protected_hardlinks;
+ 
+ struct buffer_head;
+ typedef int (get_block_t)(struct inode *inode, sector_t iblock,
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 0624e7c..0b29d58 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -1497,7 +1497,7 @@ static struct ctl_table fs_table[] = {
+ 	},
+ #endif
+ #endif
+-#ifdef CONFIG_PROTECTED_SYMLINKS
++#ifdef CONFIG_PROTECTED_LINKS
+ 	{
+ 		.procname	= "protected_symlinks",
+ 		.data		= &sysctl_protected_symlinks,
+@@ -1507,6 +1507,15 @@ static struct ctl_table fs_table[] = {
+ 		.extra1		= &zero,
+ 		.extra2		= &one,
+ 	},
++	{
++		.procname	= "protected_hardlinks",
++		.data		= &sysctl_protected_hardlinks,
++		.maxlen		= sizeof(int),
++		.mode		= 0600,
++		.proc_handler	= proc_dointvec_minmax,
++		.extra1		= &zero,
++		.extra2		= &one,
++	},
+ #endif
+ 	{
+ 		.procname	= "suid_dumpable",
+-- 
+1.7.9.1
+

Added: dists/sid/linux-2.6/debian/patches/features/all/fs-symlink-restrictions-on-sticky-directories-fix-2.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/fs-symlink-restrictions-on-sticky-directories-fix-2.patch	Fri Mar  2 04:49:25 2012	(r18763)
@@ -0,0 +1,151 @@
+From d48f814bd83a3cbd95dedaf5e4dd91c05cffddc6 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook at chromium.org>
+Date: Sat, 25 Feb 2012 12:28:43 +1100
+Subject: [PATCH 2/5] fs-symlink-restrictions-on-sticky-directories-fix-2
+
+s/sticky_//
+
+Cc: Kees Cook <keescook at chromium.org>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+---
+ Documentation/sysctl/fs.txt |    4 ++--
+ fs/Kconfig                  |   16 ++++++++--------
+ fs/namei.c                  |   10 +++++-----
+ include/linux/fs.h          |    2 +-
+ kernel/sysctl.c             |    6 +++---
+ 5 files changed, 19 insertions(+), 19 deletions(-)
+
+diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
+index 4b47cd5..01daa80 100644
+--- a/Documentation/sysctl/fs.txt
++++ b/Documentation/sysctl/fs.txt
+@@ -32,7 +32,7 @@ Currently, these files are in /proc/sys/fs:
+ - nr_open
+ - overflowuid
+ - overflowgid
+-- protected_sticky_symlinks
++- protected_symlinks
+ - suid_dumpable
+ - super-max
+ - super-nr
+@@ -158,7 +158,7 @@ The default is 65534.
+ 
+ ==============================================================
+ 
+-protected_sticky_symlinks:
++protected_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
+diff --git a/fs/Kconfig b/fs/Kconfig
+index d0fdbdd..f2c46f3 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -272,7 +272,7 @@ endif # NETWORK_FILESYSTEMS
+ source "fs/nls/Kconfig"
+ source "fs/dlm/Kconfig"
+ 
+-config PROTECTED_STICKY_SYMLINKS
++config PROTECTED_SYMLINKS
+ 	bool "Evaluate vulnerable symlink conditions"
+ 	default y
+ 	help
+@@ -285,10 +285,10 @@ config PROTECTED_STICKY_SYMLINKS
+ 
+ 	  Enabling this adds the logic to examine these dangerous symlink
+ 	  conditions. Whether or not the dangerous symlink situations are
+-	  allowed is controlled by PROTECTED_STICKY_SYMLINKS_ENABLED.
++	  allowed is controlled by PROTECTED_SYMLINKS_ENABLED.
+ 
+-config PROTECTED_STICKY_SYMLINKS_ENABLED
+-	depends on PROTECTED_STICKY_SYMLINKS
++config PROTECTED_SYMLINKS_ENABLED
++	depends on PROTECTED_SYMLINKS
+ 	bool "Disallow symlink following in sticky world-writable dirs"
+ 	default y
+ 	help
+@@ -298,12 +298,12 @@ config PROTECTED_STICKY_SYMLINKS_ENABLED
+ 	  directory and symlink owners match.
+ 
+ 	  When PROC_SYSCTL is enabled, this setting can also be controlled
+-	  via /proc/sys/kernel/protected_sticky_symlinks.
++	  via /proc/sys/kernel/protected_symlinks.
+ 
+-config PROTECTED_STICKY_SYMLINKS_ENABLED_SYSCTL
+-	depends on PROTECTED_STICKY_SYMLINKS
++config PROTECTED_SYMLINKS_ENABLED_SYSCTL
++	depends on PROTECTED_SYMLINKS
+ 	int
+-	default "1" if PROTECTED_STICKY_SYMLINKS_ENABLED
++	default "1" if PROTECTED_SYMLINKS_ENABLED
+ 	default "0"
+ 
+ endmenu
+diff --git a/fs/namei.c b/fs/namei.c
+index 5b4c05b..39edcf7 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -623,16 +623,16 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
+ 	path_put(link);
+ }
+ 
+-#ifdef CONFIG_PROTECTED_STICKY_SYMLINKS
+-int sysctl_protected_sticky_symlinks __read_mostly =
+-	CONFIG_PROTECTED_STICKY_SYMLINKS_ENABLED_SYSCTL;
++#ifdef CONFIG_PROTECTED_SYMLINKS
++int sysctl_protected_symlinks __read_mostly =
++	CONFIG_PROTECTED_SYMLINKS_ENABLED_SYSCTL;
+ 
+ /**
+  * may_follow_link - Check symlink following for unsafe situations
+  * @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,
++ * In the case of the protected_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
+@@ -651,7 +651,7 @@ may_follow_link(struct dentry *dentry, struct nameidata *nameidata)
+ 	const struct inode *inode;
+ 	const struct cred *cred;
+ 
+-	if (!sysctl_protected_sticky_symlinks)
++	if (!sysctl_protected_symlinks)
+ 		return 0;
+ 
+ 	/* Allowed if owner and follower match. */
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index aba8db0..404cc89 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -423,7 +423,7 @@ extern unsigned long get_max_files(void);
+ extern int sysctl_nr_open;
+ extern struct inodes_stat_t inodes_stat;
+ extern int leases_enable, lease_break_time;
+-extern int sysctl_protected_sticky_symlinks;
++extern int sysctl_protected_symlinks;
+ 
+ struct buffer_head;
+ typedef int (get_block_t)(struct inode *inode, sector_t iblock,
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index c469b88..0624e7c 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -1497,10 +1497,10 @@ static struct ctl_table fs_table[] = {
+ 	},
+ #endif
+ #endif
+-#ifdef CONFIG_PROTECTED_STICKY_SYMLINKS
++#ifdef CONFIG_PROTECTED_SYMLINKS
+ 	{
+-		.procname	= "protected_sticky_symlinks",
+-		.data		= &sysctl_protected_sticky_symlinks,
++		.procname	= "protected_symlinks",
++		.data		= &sysctl_protected_symlinks,
+ 		.maxlen		= sizeof(int),
+ 		.mode		= 0600,
+ 		.proc_handler	= proc_dointvec_minmax,
+-- 
+1.7.9.1
+

Added: dists/sid/linux-2.6/debian/patches/features/all/fs-symlink-restrictions-on-sticky-directories.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/sid/linux-2.6/debian/patches/features/all/fs-symlink-restrictions-on-sticky-directories.patch	Fri Mar  2 04:49:25 2012	(r18763)
@@ -0,0 +1,329 @@
+From af16d0017a7de1f00af3966b5013bebfce8a81b4 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook at chromium.org>
+Date: Sat, 25 Feb 2012 12:28:42 +1100
+Subject: [PATCH 1/5] fs: symlink restrictions on sticky directories
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+A longstanding 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
+
+The solution is to 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.
+
+Some pointers to the history of earlier discussion that I could find:
+
+ 1996 Aug, Zygo Blaxell
+  http://marc.info/?l=bugtraq&m=87602167419830&w=2
+ 1996 Oct, Andrew Tridgell
+  http://lkml.indiana.edu/hypermail/linux/kernel/9610.2/0086.html
+ 1997 Dec, Albert D Cahalan
+  http://lkml.org/lkml/1997/12/16/4
+ 2005 Feb, Lorenzo Hernández García-Hierro
+  http://lkml.indiana.edu/hypermail/linux/kernel/0502.0/1896.html
+ 2010 May, Kees Cook
+  https://lkml.org/lkml/2010/5/30/144
+
+Past objections and rebuttals could be summarized as:
+
+ - Violates POSIX.
+   - POSIX didn't consider this situation and it's not useful to follow
+     a broken specification at the cost of security.
+ - Might break unknown applications that use this feature.
+   - Applications that break because of the change are easy to spot and
+     fix. Applications that are vulnerable to symlink ToCToU by not having
+     the change aren't. Additionally, no applications have yet been found
+     that rely on this behavior.
+ - Applications should just use mkstemp() or O_CREATE|O_EXCL.
+   - True, but applications are not perfect, and new software is written
+     all the time that makes these mistakes; blocking this flaw at the
+     kernel is a single solution to the entire class of vulnerability.
+ - This should live in the core VFS.
+   - This should live in an LSM. (https://lkml.org/lkml/2010/5/31/135)
+ - This should live in an LSM.
+   - This should live in the core VFS. (https://lkml.org/lkml/2010/8/2/188)
+
+This patch is based on the patch in Openwall and grsecurity, along with
+suggestions from Al Viro.  I have added a sysctl to enable the protected
+behavior, documentation, and an audit notification.
+
+[akpm at linux-foundation.org: move sysctl_protected_sticky_symlinks declaration into .h]
+Signed-off-by: Kees Cook <keescook at chromium.org>
+Reviewed-by: Ingo Molnar <mingo at elte.hu>
+Cc: Matthew Wilcox <matthew at wil.cx>
+Cc: Alexander Viro <viro at zeniv.linux.org.uk>
+Cc: Rik van Riel <riel at redhat.com>
+Cc: Federica Teodori <federica.teodori at googlemail.com>
+Cc: Lucian Adrian Grijincu <lucian.grijincu at gmail.com>
+Cc: Ingo Molnar <mingo at elte.hu>
+Cc: Peter Zijlstra <a.p.zijlstra at chello.nl>
+Cc: Eric Paris <eparis at redhat.com>
+Cc: Randy Dunlap <rdunlap at xenotime.net>
+Cc: Dan Rosenberg <drosenberg at vsecurity.com>
+Signed-off-by: Andrew Morton <akpm at linux-foundation.org>
+---
+ Documentation/sysctl/fs.txt |   21 ++++++++++
+ fs/Kconfig                  |   34 ++++++++++++++++
+ fs/namei.c                  |   91 ++++++++++++++++++++++++++++++++++++++++---
+ include/linux/fs.h          |    1 +
+ kernel/sysctl.c             |   11 +++++
+ 5 files changed, 152 insertions(+), 6 deletions(-)
+
+diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
+index 88fd7f5..4b47cd5 100644
+--- a/Documentation/sysctl/fs.txt
++++ b/Documentation/sysctl/fs.txt
+@@ -32,6 +32,7 @@ Currently, these files are in /proc/sys/fs:
+ - nr_open
+ - overflowuid
+ - overflowgid
++- protected_sticky_symlinks
+ - suid_dumpable
+ - super-max
+ - super-nr
+@@ -157,6 +158,26 @@ The default is 65534.
+ 
+ ==============================================================
+ 
++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.
++
++==============================================================
++
+ suid_dumpable:
+ 
+ This value can be used to query and set the core dump mode for setuid
+diff --git a/fs/Kconfig b/fs/Kconfig
+index 1497ddf..d0fdbdd 100644
+--- a/fs/Kconfig
++++ b/fs/Kconfig
+@@ -272,4 +272,38 @@ endif # NETWORK_FILESYSTEMS
+ source "fs/nls/Kconfig"
+ source "fs/dlm/Kconfig"
+ 
++config PROTECTED_STICKY_SYMLINKS
++	bool "Evaluate vulnerable symlink conditions"
++	default y
++	help
++	  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 malicious symlink belonging to another user).
++
++	  Enabling this adds the logic to examine these dangerous symlink
++	  conditions. Whether or not the dangerous symlink situations are
++	  allowed is controlled by PROTECTED_STICKY_SYMLINKS_ENABLED.
++
++config PROTECTED_STICKY_SYMLINKS_ENABLED
++	depends on PROTECTED_STICKY_SYMLINKS
++	bool "Disallow symlink following in sticky world-writable dirs"
++	default y
++	help
++	  Solve ToCToU symlink race vulnerablities by permitting symlinks
++	  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 and symlink owners match.
++
++	  When PROC_SYSCTL is enabled, this setting can also be controlled
++	  via /proc/sys/kernel/protected_sticky_symlinks.
++
++config PROTECTED_STICKY_SYMLINKS_ENABLED_SYSCTL
++	depends on PROTECTED_STICKY_SYMLINKS
++	int
++	default "1" if PROTECTED_STICKY_SYMLINKS_ENABLED
++	default "0"
++
+ endmenu
+diff --git a/fs/namei.c b/fs/namei.c
+index 5d1fab5..5b4c05b 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -623,10 +623,84 @@ static inline void put_link(struct nameidata *nd, struct path *link, void *cooki
+ 	path_put(link);
+ }
+ 
++#ifdef CONFIG_PROTECTED_STICKY_SYMLINKS
++int sysctl_protected_sticky_symlinks __read_mostly =
++	CONFIG_PROTECTED_STICKY_SYMLINKS_ENABLED_SYSCTL;
++
++/**
++ * may_follow_link - Check symlink following for unsafe situations
++ * @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 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.
++ *
++ * Returns 0 if following the symlink is allowed, -ve on error.
++ */
++static inline int
++may_follow_link(struct dentry *dentry, struct nameidata *nameidata)
++{
++	int error = 0;
++	const struct inode *parent;
++	const struct inode *inode;
++	const struct cred *cred;
++
++	if (!sysctl_protected_sticky_symlinks)
++		return 0;
++
++	/* Allowed if 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) {
++		error = -EACCES;
++	}
++	spin_unlock(&dentry->d_lock);
++
++#ifdef CONFIG_AUDIT
++	if (error) {
++		struct audit_buffer *ab;
++
++		ab = audit_log_start(current->audit_context,
++				     GFP_KERNEL, AUDIT_AVC);
++		audit_log_format(ab, "op=follow_link action=denied");
++		audit_log_format(ab, " pid=%d comm=", current->pid);
++		audit_log_untrustedstring(ab, current->comm);
++		audit_log_d_path(ab, " path=", &nameidata->path);
++		audit_log_format(ab, " name=");
++		audit_log_untrustedstring(ab, dentry->d_name.name);
++		audit_log_format(ab, " dev=");
++		audit_log_untrustedstring(ab, inode->i_sb->s_id);
++		audit_log_format(ab, " ino=%lu", inode->i_ino);
++		audit_log_end(ab);
++	}
++#endif
++	return error;
++}
++#else
++static inline int
++may_follow_link(struct dentry *dentry, struct nameidata *nameidata)
++{
++	return 0;
++}
++#endif
++
+ static __always_inline int
+-follow_link(struct path *link, struct nameidata *nd, void **p)
++follow_link(struct path *link, struct nameidata *nd, void **p, bool sensitive)
+ {
+-	int error;
++	int error = 0;
+ 	struct dentry *dentry = link->dentry;
+ 
+ 	BUG_ON(nd->flags & LOOKUP_RCU);
+@@ -645,7 +719,10 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
+ 	touch_atime(link->mnt, dentry);
+ 	nd_set_link(nd, NULL);
+ 
+-	error = security_inode_follow_link(link->dentry, nd);
++	if (sensitive)
++		error = may_follow_link(link->dentry, nd);
++	if (!error)
++		error = security_inode_follow_link(link->dentry, nd);
+ 	if (error) {
+ 		*p = ERR_PTR(error); /* no ->put_link(), please */
+ 		path_put(&nd->path);
+@@ -1342,7 +1419,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
+ 		struct path link = *path;
+ 		void *cookie;
+ 
+-		res = follow_link(&link, nd, &cookie);
++		res = follow_link(&link, nd, &cookie, false);
+ 		if (!res)
+ 			res = walk_component(nd, path, &nd->last,
+ 					     nd->last_type, LOOKUP_FOLLOW);
+@@ -1615,7 +1692,8 @@ static int path_lookupat(int dfd, const char *name,
+ 			void *cookie;
+ 			struct path link = path;
+ 			nd->flags |= LOOKUP_PARENT;
+-			err = follow_link(&link, nd, &cookie);
++
++			err = follow_link(&link, nd, &cookie, true);
+ 			if (!err)
+ 				err = lookup_last(nd, &path);
+ 			put_link(nd, &link, cookie);
+@@ -2327,7 +2405,8 @@ static struct file *path_openat(int dfd, const char *pathname,
+ 		}
+ 		nd->flags |= LOOKUP_PARENT;
+ 		nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
+-		error = follow_link(&link, nd, &cookie);
++
++		error = follow_link(&link, nd, &cookie, true);
+ 		if (unlikely(error))
+ 			filp = ERR_PTR(error);
+ 		else
+diff --git a/include/linux/fs.h b/include/linux/fs.h
+index 9808b21..aba8db0 100644
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -423,6 +423,7 @@ extern unsigned long get_max_files(void);
+ extern int sysctl_nr_open;
+ extern struct inodes_stat_t inodes_stat;
+ extern int leases_enable, lease_break_time;
++extern int sysctl_protected_sticky_symlinks;
+ 
+ struct buffer_head;
+ typedef int (get_block_t)(struct inode *inode, sector_t iblock,
+diff --git a/kernel/sysctl.c b/kernel/sysctl.c
+index 62538ee..c469b88 100644
+--- a/kernel/sysctl.c
++++ b/kernel/sysctl.c
+@@ -1497,6 +1497,17 @@ static struct ctl_table fs_table[] = {
+ 	},
+ #endif
+ #endif
++#ifdef CONFIG_PROTECTED_STICKY_SYMLINKS
++	{
++		.procname	= "protected_sticky_symlinks",
++		.data		= &sysctl_protected_sticky_symlinks,
++		.maxlen		= sizeof(int),
++		.mode		= 0600,
++		.proc_handler	= proc_dointvec_minmax,
++		.extra1		= &zero,
++		.extra2		= &one,
++	},
++#endif
+ 	{
+ 		.procname	= "suid_dumpable",
+ 		.data		= &suid_dumpable,
+-- 
+1.7.9.1
+

Modified: dists/sid/linux-2.6/debian/patches/series/base
==============================================================================
--- dists/sid/linux-2.6/debian/patches/series/base	Fri Mar  2 03:30:27 2012	(r18762)
+++ dists/sid/linux-2.6/debian/patches/series/base	Fri Mar  2 04:49:25 2012	(r18763)
@@ -81,3 +81,8 @@
 + bugfix/x86/drm-i915-fix-operator-precedence-when-enabling-RC6p.patch
 + bugfix/all/ipsec-be-careful-of-non-existing-mac-headers.patch
 
++ features/all/fs-symlink-restrictions-on-sticky-directories.patch
++ features/all/fs-symlink-restrictions-on-sticky-directories-fix-2.patch
++ features/all/fs-hardlink-creation-restrictions.patch
++ features/all/fs-hardlink-creation-restrictions-fix.patch
++ features/all/fs-hardlink-creation-restriction-cleanup.patch



More information about the Kernel-svn-changes mailing list