Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp2558078imu; Thu, 29 Nov 2018 06:53:15 -0800 (PST) X-Google-Smtp-Source: AFSGD/VKYsjxjNrmCO3nbnB46d02U1NkVuvGGRHhCCHR3f+jqY5lbaCxfFySJF+rgKTKBcxpxb0m X-Received: by 2002:a62:2292:: with SMTP id p18mr1715123pfj.9.1543503194973; Thu, 29 Nov 2018 06:53:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1543503194; cv=none; d=google.com; s=arc-20160816; b=s+SQYTBxGe8uyFMWFDDi7+me/8CU7gYBRg4DZnevydLDJ3DIFeX6VGKn2GT4KPyvY5 cOPjzDjwGbzy2dhA5mjVpNIiI/Dg+dwUSBx4Bjz7+CdpxC8tqJEZHfW6jKKV/eQ89468 58pwcAioqowti6bkTcHLVB1dvT1fwLSzD9mb0S+rNNqWDp/LCWCjUpObmpFOr4bPNiIu ScRuSNUxDecceBBmL0ff3rwjGlFNm3fI48GVXRb3lK04xGaq2/EDOGkquR0Y25TIUvVp OeLISFooUGtinAlTr1v/XDPufpi1n993gqLT+xkyS3j2sq/4kAFmeVvaiDzm3XOl579u wWnw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=EaOE+OhEWF686gd4vCd3g2RNwPrjH6X3sVdvpXyyz+Q=; b=wI+RhBVhpMpa2GkjD0g/UYJsuLXFbCuJqP+u0miTSl1MIhrPjRx2N1s6gUErugh8rn jxXx16YIE1dk4ubtG1oVLr1p0jM+5AOPIiqYh/m9azhSDao76a82MxOUOEYoqCJG31di JDEBsGvwj4tb866AXwwr7BnqRzw8JP7bWfzujJxCtSjNRZCPzAD9ZOp3Fv7J1LSn7oEm 32YvCdau1r0XyEuJh/xey8ba7nmvhOCsi+2MI+GhKpb0PFkfowglqM7qlGIYK+s7kgA7 P2wd9GAdTPGxxXYw3fuj0/KxRK1CMVIE4442qSZF2NbUs3rk6X9A5NbnQ24pLMNTijqX FFBA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=mV3GLq0+; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t20si2165906ply.359.2018.11.29.06.52.47; Thu, 29 Nov 2018 06:53:14 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=mV3GLq0+; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732405AbeK3B3Q (ORCPT + 99 others); Thu, 29 Nov 2018 20:29:16 -0500 Received: from mail.kernel.org ([198.145.29.99]:55514 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728693AbeK3B3Q (ORCPT ); Thu, 29 Nov 2018 20:29:16 -0500 Received: from localhost (5356596B.cm-6-7b.dynamic.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id ED766213A2; Thu, 29 Nov 2018 14:23:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1543501423; bh=cQgmg0kfKx1jKdzBJOfG1ZsMIDka3SCVBMwDSncxVBI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mV3GLq0+Bm5wTtc1a/66o3IUqQqLqzlH57aPI865aDatcgHf+H/Asw2EnZp9NzioV g1akCS09MWfpONsUNCxYzCYjOFPtNkDV3Krn/GiDljy/EuqbRixGAIXZzEIoiT4olh b9ECvQ+XYL3gtO7Ar/H0IO4RslFHfKH2D5MFPg0I= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Salvatore Mesoraca , Kees Cook , Solar Designer , Al Viro , Dan Carpenter , Andrew Morton , Linus Torvalds , Loic Subject: [PATCH 4.9 84/92] namei: allow restricted O_CREAT of FIFOs and regular files Date: Thu, 29 Nov 2018 15:12:53 +0100 Message-Id: <20181129140113.433177659@linuxfoundation.org> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181129140106.520639693@linuxfoundation.org> References: <20181129140106.520639693@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Salvatore Mesoraca commit 30aba6656f61ed44cba445a3c0d38b296fa9e8f5 upstream. Disallows open of FIFOs or regular files not owned by the user in world writable sticky directories, unless the owner is the same as that of the directory or the file is opened without the O_CREAT flag. The purpose is to make data spoofing attacks harder. This protection can be turned on and off separately for FIFOs and regular files via sysctl, just like the symlinks/hardlinks protection. This patch is based on Openwall's "HARDEN_FIFO" feature by Solar Designer. This is a brief list of old vulnerabilities that could have been prevented by this feature, some of them even allow for privilege escalation: CVE-2000-1134 CVE-2007-3852 CVE-2008-0525 CVE-2009-0416 CVE-2011-4834 CVE-2015-1838 CVE-2015-7442 CVE-2016-7489 This list is not meant to be complete. It's difficult to track down all vulnerabilities of this kind because they were often reported without any mention of this particular attack vector. In fact, before hardlinks/symlinks restrictions, fifos/regular files weren't the favorite vehicle to exploit them. [s.mesoraca16@gmail.com: fix bug reported by Dan Carpenter] Link: https://lkml.kernel.org/r/20180426081456.GA7060@mwanda Link: http://lkml.kernel.org/r/1524829819-11275-1-git-send-email-s.mesoraca16@gmail.com [keescook@chromium.org: drop pr_warn_ratelimited() in favor of audit changes in the future] [keescook@chromium.org: adjust commit subjet] Link: http://lkml.kernel.org/r/20180416175918.GA13494@beast Signed-off-by: Salvatore Mesoraca Signed-off-by: Kees Cook Suggested-by: Solar Designer Suggested-by: Kees Cook Cc: Al Viro Cc: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Loic Signed-off-by: Greg Kroah-Hartman --- Documentation/sysctl/fs.txt | 36 +++++++++++++++++++++++++++++ fs/namei.c | 53 +++++++++++++++++++++++++++++++++++++++++--- include/linux/fs.h | 2 + kernel/sysctl.c | 18 ++++++++++++++ 4 files changed, 106 insertions(+), 3 deletions(-) --- a/Documentation/sysctl/fs.txt +++ b/Documentation/sysctl/fs.txt @@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/ - overflowgid - pipe-user-pages-hard - pipe-user-pages-soft +- protected_fifos - protected_hardlinks +- protected_regular - protected_symlinks - suid_dumpable - super-max @@ -182,6 +184,24 @@ applied. ============================================================== +protected_fifos: + +The intent of this protection is to avoid unintentional writes to +an attacker-controlled FIFO, where a program expected to create a regular +file. + +When set to "0", writing to FIFOs is unrestricted. + +When set to "1" don't allow O_CREAT open on FIFOs that we don't own +in world writable sticky directories, unless they are owned by the +owner of the directory. + +When set to "2" it also applies to group writable sticky directories. + +This protection is based on the restrictions in Openwall. + +============================================================== + protected_hardlinks: A long-standing class of security issues is the hardlink-based @@ -202,6 +222,22 @@ This protection is based on the restrict ============================================================== +protected_regular: + +This protection is similar to protected_fifos, but it +avoids writes to an attacker-controlled regular file, where a program +expected to create one. + +When set to "0", writing to regular files is unrestricted. + +When set to "1" don't allow O_CREAT open on regular files that we +don't own in world writable sticky directories, unless they are +owned by the owner of the directory. + +When set to "2" it also applies to group writable sticky directories. + +============================================================== + protected_symlinks: A long-standing class of security issues is the symlink-based --- a/fs/namei.c +++ b/fs/namei.c @@ -892,6 +892,8 @@ static inline void put_link(struct namei int sysctl_protected_symlinks __read_mostly = 0; int sysctl_protected_hardlinks __read_mostly = 0; +int sysctl_protected_fifos __read_mostly; +int sysctl_protected_regular __read_mostly; /** * may_follow_link - Check symlink following for unsafe situations @@ -1005,6 +1007,45 @@ static int may_linkat(struct path *link) return -EPERM; } +/** + * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory + * should be allowed, or not, on files that already + * exist. + * @dir: the sticky parent directory + * @inode: the inode of the file to open + * + * Block an O_CREAT open of a FIFO (or a regular file) when: + * - sysctl_protected_fifos (or sysctl_protected_regular) is enabled + * - the file already exists + * - we are in a sticky directory + * - we don't own the file + * - the owner of the directory doesn't own the file + * - the directory is world writable + * If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2 + * the directory doesn't have to be world writable: being group writable will + * be enough. + * + * Returns 0 if the open is allowed, -ve on error. + */ +static int may_create_in_sticky(struct dentry * const dir, + struct inode * const inode) +{ + if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || + (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || + likely(!(dir->d_inode->i_mode & S_ISVTX)) || + uid_eq(inode->i_uid, dir->d_inode->i_uid) || + uid_eq(current_fsuid(), inode->i_uid)) + return 0; + + if (likely(dir->d_inode->i_mode & 0002) || + (dir->d_inode->i_mode & 0020 && + ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) || + (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) { + return -EACCES; + } + return 0; +} + static __always_inline const char *get_link(struct nameidata *nd) { @@ -3356,9 +3397,15 @@ finish_open: if (error) return error; audit_inode(nd->name, nd->path.dentry, 0); - error = -EISDIR; - if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) - goto out; + if (open_flag & O_CREAT) { + error = -EISDIR; + if (d_is_dir(nd->path.dentry)) + goto out; + error = may_create_in_sticky(dir, + d_backing_inode(nd->path.dentry)); + if (unlikely(error)) + goto out; + } error = -ENOTDIR; if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) goto out; --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -69,6 +69,8 @@ extern struct inodes_stat_t inodes_stat; extern int leases_enable, lease_break_time; extern int sysctl_protected_symlinks; extern int sysctl_protected_hardlinks; +extern int sysctl_protected_fifos; +extern int sysctl_protected_regular; struct buffer_head; typedef int (get_block_t)(struct inode *inode, sector_t iblock, --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1795,6 +1795,24 @@ static struct ctl_table fs_table[] = { .extra2 = &one, }, { + .procname = "protected_fifos", + .data = &sysctl_protected_fifos, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two, + }, + { + .procname = "protected_regular", + .data = &sysctl_protected_regular, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two, + }, + { .procname = "suid_dumpable", .data = &suid_dumpable, .maxlen = sizeof(int),