UBUNTU: SAUCE: fs: block hardlinks to non-accessible sources
Hardlinks can be abused in a similar fashion to symlinks above, but they
are not limited to world-writable directories. 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.
The solution is to not allow the creation of hardlinks to files that a
given user would be unable to read or write originally, or are otherwise
sensitive.
Some links to the history of its discussion:
1997 Dec, Yuri Kuzmenko http://lkml.org/lkml/1997/12/29/20
2002 Apr, Chris Wright http://lkml.org/lkml/2002/4/13/99
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. Also, please reference
where POSIX says this.
- Might break atd, courier, and other unknown applications that use this
feature.
- These applications are easy to spot and can be tested and
fixed. Applications that are vulnerable to hardlink attacks by not
having the change aren't.
- Applications should correctly drop privileges before attempting to
access user files.
- 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 patch is based on the patch in grsecurity, which is similar to the
patch in Openwall. I have added a sysctl to toggle the behavior back
to the old handling via /proc/sys/fs/weak-nonaccess-hardlinks, as well as
a ratelimited deprecation warning.
/* sysctl for symlink permissions checking */
int weak_sticky_symlinks;
+/* sysctl for hardlink permissions checking */
+int weak_nonaccess_hardlinks;
/*
* If a non-root user executes a setuid-root binary in
@@ -304,6 +306,48 @@ int cap_inode_follow_link(struct dentry *dentry,
return 0;
}
+#ifdef CONFIG_SECURITY_PATH
+/*
+ * cap_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 or write
+ *
+ * Returns 0 if successful, -ve on error.
+ */
+int cap_path_link(struct dentry *old_dentry, struct path *new_dir,
+ struct dentry *new_dentry)
+{
+ struct inode *inode = old_dentry->d_inode;
+ const int mode = inode->i_mode;
+ const struct cred *cred = current_cred();
+
+ if (weak_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)) {
+ printk_ratelimited(KERN_INFO "deprecated non-accessible"
+ " hardlink creation was attempted by: %s
",
+ current->comm);
+ return -EPERM;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_SECURITY_PATH */
+
/*
* Calculate the new process capability sets from the capability sets attached
* to a file.
--
1.7.0.4
--
Kees Cook
Ubuntu Security Team
--
kernel-team mailing list
kernel-team@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/kernel-team
05-12-2010, 04:03 PM
Kees Cook
UBUNTU: SAUCE: fs: block hardlinks to non-accessible sources
Hardlinks can be abused in a similar fashion to symlinks above, but they
are not limited to world-writable directories. 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.
The solution is to not allow the creation of hardlinks to files that a
given user would be unable to read or write originally, or are otherwise
sensitive.
Some links to the history of its discussion:
1997 Dec, Yuri Kuzmenko http://lkml.org/lkml/1997/12/29/20
2002 Apr, Chris Wright http://lkml.org/lkml/2002/4/13/99
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. Also, please reference
where POSIX says this.
- Might break atd, courier, and other unknown applications that use this
feature.
- These applications are easy to spot and can be tested and
fixed. Applications that are vulnerable to hardlink attacks by not
having the change aren't.
- Applications should correctly drop privileges before attempting to
access user files.
- 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 patch is based on the patch in grsecurity, which is similar to the
patch in Openwall. I have added a sysctl to toggle the behavior back
to the old handling via /proc/sys/fs/weak-nonaccess-hardlinks, as well as
a ratelimited deprecation warning.