|
Message-ID: <20120222185503.GA24256@www.outflux.net> Date: Wed, 22 Feb 2012 10:55:03 -0800 From: Kees Cook <keescook@...omium.org> To: Andrew Morton <akpm@...ux-foundation.org> Cc: Ingo Molnar <mingo@...e.hu>, Marcin Slusarz <marcin.slusarz@...il.com>, linux-kernel@...r.kernel.org, Randy Dunlap <rdunlap@...otime.net>, Alexander Viro <viro@...iv.linux.org.uk>, linux-doc@...r.kernel.org, linux-fsdevel@...r.kernel.org, kernel-hardening@...ts.openwall.com Subject: [PATCH v2] fs: hardlink creation restriction cleanup Clean-up of hardlink restriction logic, as suggested by Andrew Morton. Signed-off-by: Kees Cook <keescook@...omium.org> --- v2: - add eye-strain-reduction-whitespace for Ingo. ;) --- fs/namei.c | 62 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 44 insertions(+), 18 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 8ed4e00..f86494c 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.0.4
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.