Received: by 10.223.185.116 with SMTP id b49csp5386212wrg; Tue, 27 Feb 2018 12:23:26 -0800 (PST) X-Google-Smtp-Source: AH8x224J2tS+mAVdTVGVdK9bXXeBhyvEBfd2XcGqUKS89c5M7dWYB6SKy0CR3MnCTDDSXkcR4weg X-Received: by 2002:a17:902:a607:: with SMTP id u7-v6mr15105548plq.367.1519763006222; Tue, 27 Feb 2018 12:23:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519763006; cv=none; d=google.com; s=arc-20160816; b=YEJvlEYep+lC9ht2Q6nSa40VUlxwR4FM4y9AfxPb0oWXTKiZJ8FTgTkQ+J3ZGMH9Uq b8/5nNL9fyQD5DRr9MZKOuj3Bo01hQhog1waSuNImGS7bwnFCIv8vdW+KXIaSoE86kz3 KUov+1K2VOZAQLgqmwxQ9tqhg3s5hB59IiiNX9JsbPu9+zPXNvLUbDpbEMVVAdR2gSOF oFbHv8dv0bBFwe2i2rtk8fJeZVvpJPZ4S4XL1D8Rzhp7FNC6WWdliHc2FijVEu1KOAFT h/u9otaxIne0wLyZiRqyL0YcnfXt0gQGmcPIDtYgd7A5G6Q7npYkC5ZVR/KIwcVs6Fc9 qBGw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :references:in-reply-to:mime-version:dkim-signature:dkim-signature :arc-authentication-results; bh=TbgiwYgzNbcvQBOO1LGzjHgj+MbDaH/LBb/xsX8q4wY=; b=bzg/RxO4FNx2UNsfB2y8eUOKxSBdMghSLPA3yrcSbT/bR29CagaVGt2elJY9Rby0pa bFjEtt8lZQcmcKbMpVlyT1OIPL+OfPTgRYPqdMo9g3wF0MfvjXVMy9glsOkt65/lJhA6 gQn8y0SzkCsNo8blGFfxTu35T5Uznqm4eR75EcmLwAyJA657EGrJXJhjYRXDisORsodq Mnizc2HxgNhF0KKF7viWKuHFmrtY/TvPG+wFxH4VDLGXzNZrgdAmFas81prjqs0tblCy 0XljmdU/R8uLZFseTHdsj9WZW7vWUTTQkpQ1X//u0tMrQDc4N6DC7eVN9UhY2ce4XzLm EFOg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@google.com header.s=20161025 header.b=KK+shY3C; dkim=fail header.i=@chromium.org header.s=google header.b=ju46Q0tO; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p5si7403633pga.372.2018.02.27.12.23.10; Tue, 27 Feb 2018 12:23:26 -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=fail header.i=@google.com header.s=20161025 header.b=KK+shY3C; dkim=fail header.i=@chromium.org header.s=google header.b=ju46Q0tO; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751831AbeB0UWX (ORCPT + 99 others); Tue, 27 Feb 2018 15:22:23 -0500 Received: from mail-vk0-f68.google.com ([209.85.213.68]:36420 "EHLO mail-vk0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751628AbeB0UWV (ORCPT ); Tue, 27 Feb 2018 15:22:21 -0500 Received: by mail-vk0-f68.google.com with SMTP id q7so76376vkh.3 for ; Tue, 27 Feb 2018 12:22:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=TbgiwYgzNbcvQBOO1LGzjHgj+MbDaH/LBb/xsX8q4wY=; b=KK+shY3Cr+jQwH+el7Ban8O3TdKvA+kq7BssyK6b0boIPQR/i7BTZfLySqLUBdQhM5 /ItCNCxMtyz4h6zSeIhcIWUKJQAiXDeuTZ6t/X4TMVc4v07HRM5QzNKdt3PEXQgeX5Sc n4c5d315ZYeZOs6R4Q8+tM7Lw3qQlGHUEakv9V6bZeVVvrL9PmsHfky6ITZJmqRakpH8 aDGRXZ2b3Q7AKTNv0yrBq2bzwwRHJsM6GS8uGPMGNco5YzyUFUAUEjP6Zx4pmh4kUDJe Nr2xHvb4BWvo8fsWAfNPRfP2ClKbOQXlj/mLapnd/qCXaWVra5PZM/Fdm/CzlfLg3ysK AcgA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=mime-version:sender:in-reply-to:references:from:date:message-id :subject:to:cc; bh=TbgiwYgzNbcvQBOO1LGzjHgj+MbDaH/LBb/xsX8q4wY=; b=ju46Q0tOtZ0ncBkbyjCWFiVcBsEb8XrRKvSdraBY+FGAgXJAbt6SoL/pp96AOy76aN NKvjmeuySqawzYLzWjcnydL5I2fbAOKyDG0QRW/StukTNApYywyuYi1HjPJ0ZKJac07V FNTcDpHQGERz5jyWIAwg/iGOvQgs0YceNAXIk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:sender:in-reply-to:references:from :date:message-id:subject:to:cc; bh=TbgiwYgzNbcvQBOO1LGzjHgj+MbDaH/LBb/xsX8q4wY=; b=CYMyKe3yayxbOcUTgmKAVqGcjLMP14fGE/MtcW8zh9rJqnJAF5bTtHJTyQByV65Pde nfWZQvYB2A3J9bKDC4KOPL0WZO6Mf2206DUV6oK/WQjrtR57QbxOm3+SlojXEN5otq6n bqOFW/HD20/QEWwfCSsICJh0/WjZp2jPbdgWI9SfsIzwFbZxDHVoPS6ON//tgfMLPd8+ Fe/ErvFlSm3Kv30mDkcbVCsA0KqdcE/QByBtRTFVqVasmjW7vNLsjy6FH8IPMrQdRtCS zzpHdEV+oq/Vw/EBmTI9Z0js5N+5pWPGMGq3rOQdnIWE7lLr6SIajj+I9WdG10JIb6Mo zF2w== X-Gm-Message-State: APf1xPDDxDmXbdtOcN7fV1/RWLujlJy6yuVX6tpiATv1kWyv6YZxYgsc mO9bRJ892wsS4kKMYuO4MaH+vBM/1PTKLPe5ZjH4pecQJT4= X-Received: by 10.31.230.132 with SMTP id d126mr11477611vkh.123.1519762940250; Tue, 27 Feb 2018 12:22:20 -0800 (PST) MIME-Version: 1.0 Received: by 10.31.242.140 with HTTP; Tue, 27 Feb 2018 12:22:18 -0800 (PST) In-Reply-To: References: <1519729200-16056-1-git-send-email-s.mesoraca16@gmail.com> From: Kees Cook Date: Tue, 27 Feb 2018 12:22:18 -0800 X-Google-Sender-Auth: LtfsI3fAYX2mgYsxzWgnd_0cp_A Message-ID: Subject: Re: [PATCH v4] Protected FIFOs and regular files To: Salvatore Mesoraca Cc: LKML , Kernel Hardening , "linux-fsdevel@vger.kernel.org" , Alan Cox , Alexander Viro , David Laight , Ian Campbell , Jann Horn , Matthew Wilcox , Pavel Vasilyev , Solar Designer , "Eric W. Biederman" , "Tobin C. Harding" Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Feb 27, 2018 at 11:47 AM, Kees Cook wrote: > On Tue, Feb 27, 2018 at 3:00 AM, Salvatore Mesoraca > wrote: >> 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. >> >> Suggested-by: Solar Designer >> Suggested-by: Kees Cook >> Signed-off-by: Salvatore Mesoraca >> --- >> >> Notes: >> Changes in v3: >> - Fixed format string for uid_t that is unsigned >> (suggested by Jann Horn). >> Changes in v4: >> - Some English fixes (suggested by Tobin C. Harding). >> - The original patchset has been split to help this part >> land upstream (suggested by Solar Designer). >> >> Documentation/sysctl/fs.txt | 36 ++++++++++++++++++++++++++ >> fs/namei.c | 61 ++++++++++++++++++++++++++++++++++++++++++--- >> include/linux/fs.h | 2 ++ >> kernel/sysctl.c | 18 +++++++++++++ >> 4 files changed, 114 insertions(+), 3 deletions(-) >> >> diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt >> index 6c00c1e..819caf8 100644 >> --- a/Documentation/sysctl/fs.txt >> +++ b/Documentation/sysctl/fs.txt >> @@ -34,7 +34,9 @@ Currently, these files are in /proc/sys/fs: >> - 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 restrictions in Openwall and grsecurity. >> >> ============================================================== >> >> +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 >> diff --git a/fs/namei.c b/fs/namei.c >> index 921ae32..eaab668 100644 >> --- a/fs/namei.c >> +++ b/fs/namei.c >> @@ -883,6 +883,8 @@ static inline void put_link(struct nameidata *nd) >> >> 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 >> @@ -996,6 +998,54 @@ 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 >> + * @name: the file name >> + * @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, >> + const unsigned char * const name, >> + 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))))) { >> + pr_notice_ratelimited("denied writing in '%s' of %u.%u in a sticky directory by UID %u, EUID %u, process %s:%d.\n", >> + name, >> + from_kuid(&init_user_ns, inode->i_uid), >> + from_kgid(&init_user_ns, inode->i_gid), >> + from_kuid(&init_user_ns, current_uid()), >> + from_kuid(&init_user_ns, current_euid()), >> + current->comm, current->pid); > > Instead of this pr_notice_ratelimited(), I think > audit_log_link_denied() should be refactored and used instead. Drop > this line from this patch, and I think this is great as-is. The > logging can be separate (as it may get heavily bike-shed, as I > experienced with hard/symlink restrictions). > > Otherwise, I think this looks great. > > Acked-by: Kees Cook I've also tested this now; so: Tested-by: Kees Cook # grep . /proc/sys/fs/protected_* /proc/sys/fs/protected_fifos:0 /proc/sys/fs/protected_hardlinks:1 /proc/sys/fs/protected_regular:0 /proc/sys/fs/protected_symlinks:1 # cd /tmp # mkfifo fifo # touch regular # chown nobody fifo regular # chmod a+w fifo regular # chmod a+w regular # cat fifo > output & # su - keescook $ cd /tmp $ python ... >>> import os >>> fd = os.open("fifo", os.O_RDWR | os.O_CREAT) >>> os.write(fd, "OHAI\n") 5 >>> fd = os.open("regular", os.O_RDWR | os.O_CREAT) >>> os.write(fd, "OHAI\n") 5 >>> exit() $ exit # echo 1 > /proc/sys/fs/protected_fifos # echo 1 > /proc/sys/fs/protected_regular # su - keescook $ cd /tmp $ python ... >>> import os >>> fd = os.open("fifo", os.O_RDWR | os.O_CREAT) Traceback (most recent call last): File "", line 1, in OSError: [Errno 13] Permission denied: 'fifo' >>> fd = os.open("regular", os.O_RDWR | os.O_CREAT) Traceback (most recent call last): File "", line 1, in OSError: [Errno 13] Permission denied: 'regular' > I'll create a branch for this on git.kernel.org and see if anything > surprising pops out. :) Here it is with my suggested refactoring of the audit message: https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=kspp/userspace/protected-creat Which produces: [ 146.854080] audit: type=1703 audit(1519762816.978:95): op=fifo ppid=3091 pid=3092 auid=0 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts8 ses=1 comm="python" exe="/usr/bin/python2.7" res=0 [ 146.858691] audit: type=1302 audit(1519762816.978:95): item=0 name="/tmp/fifo" inode=531 dev=fd:01 mode=010666 ouid=65534 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0000000000000000 cap_fi=0000000000000000 cap_fe=0 cap_fver=0 ... [ 152.993518] audit: type=1703 audit(1519762823.117:96): op=regular ppid=3091 pid=3092 auid=0 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=pts8 ses=1 comm="python" exe="/usr/bin/python2.7" res=0 [ 152.997963] audit: type=1302 audit(1519762823.117:96): item=0 name="/tmp/regular" inode=700 dev=fd:01 mode=0100666 ouid=65534 ogid=0 rdev=00:00 nametype=NORMAL cap_fp=0000000000000000 cap_fi=0000000000000000 cap_fe=0 cap_fver=0 and other things (uid, etc) -Kees -- Kees Cook Pixel Security