Received: by 10.223.185.116 with SMTP id b49csp5353162wrg; Tue, 27 Feb 2018 11:48:47 -0800 (PST) X-Google-Smtp-Source: AH8x226f5Xg+L80iMasHb2snVZrSrpCai0f71RR0ZMqjaRsBmjkivLDnvk8052+Xz2LaPyWB7PWB X-Received: by 2002:a17:902:4381:: with SMTP id j1-v6mr15151465pld.297.1519760927288; Tue, 27 Feb 2018 11:48:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519760927; cv=none; d=google.com; s=arc-20160816; b=k4btMQf9GOWBLi3AB/GxA3fsNruHIIfhZCukpIVfnXLccYcRiU2Tx6O5+GIp3qh6nB PbKWyVA5wTZmBPcWFgXbpaZfgyzT188vTnZOrLOsJG1r7ali3UBVqZf7c9CBWjKGPb7I n7bLP3G2Ig/tc2TSUd4FyG4UoTLRMGNAvg1dg+S/vi3t8vPxtLhwMMTJXm43yURylvcd upBPRlKNlSbnizsDVt78ZifHH5ZDNvLIkgvhiDf1titHmY8eTzx0JEgpd3CI4Xp9duxB vz4GVGuoliJus/MMlcx64sQ6+bqffqLM3I3TfrmPCw/X1NI3JagCom32VrhC1s6VfYg/ yPUg== 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=qOxnbzTVjCyoLUDcWlYxFLCa4lkMbJ5/Yof9NRpM65U=; b=EDKZAKYu3QeX5WLRxhqSw6oQ8vTOzet8ZehWFTL27/TjJiZq1ysGh3YZAqttPyt6s3 faqPZkX9ejIKFjNl0M2beqO65tZ6uFSxojmQlN0g61TnZ95mXuXp/tN+tk3cBiR3Wstv gCLYnVY/yfiSPavbVBKYRQv3BnxmIcODpWOCFijPqPFTTNRRSixijH0/t1zvHx0MU6c1 FQrk5S9KJ1tzGlr5KM52STJyTB1huUi0cq+Y9aMSawy+93Wv75O5HEcPUyHdRmf3ycCg /oxwi6esCOprEWcJ6dLPyEhLMlcpIH/O1x7kaO1KYOYaAUHphRm+wxyULp73xWrU9V+X HutA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@google.com header.s=20161025 header.b=QdWAJzLk; dkim=fail header.i=@chromium.org header.s=google header.b=BBE0g0mD; 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 s193si7289358pgs.825.2018.02.27.11.48.32; Tue, 27 Feb 2018 11:48:47 -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=QdWAJzLk; dkim=fail header.i=@chromium.org header.s=google header.b=BBE0g0mD; 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 S1751957AbeB0Tru (ORCPT + 99 others); Tue, 27 Feb 2018 14:47:50 -0500 Received: from mail-vk0-f68.google.com ([209.85.213.68]:44258 "EHLO mail-vk0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751788AbeB0Trs (ORCPT ); Tue, 27 Feb 2018 14:47:48 -0500 Received: by mail-vk0-f68.google.com with SMTP id t126so12952582vkb.11 for ; Tue, 27 Feb 2018 11:47:47 -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=qOxnbzTVjCyoLUDcWlYxFLCa4lkMbJ5/Yof9NRpM65U=; b=QdWAJzLk0J7I2goZhunRMf7UFPzLnFIu63FYsGozaGEUa/eINLE2pqxSlPoFQnVn3m HNk6c6B1Z8ps7ecFMNDsCHtdgp4MCAPrmvxr6YUT9aKngeyZZ/4jEEC0CRDgYARik4Kt 5iSF4fT+HGOPiBGEVTt+PzBgTtMScHoEfTsGNVIrLTrXCHnyJQlmyk/Chdm+kKt2xk2V fziRPeyI+8MzNZrQT53W6E78m7qEZ7tGRzhJ21LSA6QEoz2Z1Ehu8Ee+j7zhmQ5wnex9 GwR8OytqNmlX+ZZXXNfnhMGQ8NF6Lap9tuox0hNCPWbQKWXg5nPoPqlQCJq1YGmZx+LR BG8w== 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=qOxnbzTVjCyoLUDcWlYxFLCa4lkMbJ5/Yof9NRpM65U=; b=BBE0g0mD//wGsX3tUFXwd7DNe/6Jej+R0CAjNyxAOe2NVoE4dDakuwJTskLI7XsYEO z8vQdciNUy7nJvwXqE/RT8S52krGyeDU325uELaJCFvd9R2C/f2DXpx0IxM61uhp8ogb QTu8UJRtMbVtGF0j9UB3Nfg7oY56vHj6qoFJ8= 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=qOxnbzTVjCyoLUDcWlYxFLCa4lkMbJ5/Yof9NRpM65U=; b=iT/HvkH7rq3yWJnzCENMRd5Qs8aFQkWV9CtKPPrL5hMOkOzrj3bvtX44I4NtWRPpR9 6jKcvizWDziLKqO8nobXckV5Mh/s7XdJLv5/CmFeCDVQOGe7hcMjpHYNkdrNl3jdTx1Y s82FNQ9RDGFwOSrG3SxW4ot9nNyZzR0+hf58bWABKjNG7zyEEObf3+W1k1+N+gFwiZ5f 8bdKFAhEObsYv3CeqhncbkoCBTgZGGVn2PF/RkIk7P5SiVkztjjRi6FCVFbwhUCKjmk0 QCWc6e97qmdgQEYORRx2BINnM0FqousWu4BtYm2wI62ycOdl8ooRBW1N4lPGu9/Yz+SV 7tFg== X-Gm-Message-State: APf1xPA6AMMJKy/e4yEYz55WYGIHjzJdkwF18Z1uaj39Zyynyt+q0qnz 5Up2gzGxsIElUvev5fww7INTTKeI7y28pP448CVANQ== X-Received: by 10.31.196.131 with SMTP id u125mr11291455vkf.158.1519760866812; Tue, 27 Feb 2018 11:47:46 -0800 (PST) MIME-Version: 1.0 Received: by 10.31.242.140 with HTTP; Tue, 27 Feb 2018 11:47:46 -0800 (PST) In-Reply-To: <1519729200-16056-1-git-send-email-s.mesoraca16@gmail.com> References: <1519729200-16056-1-git-send-email-s.mesoraca16@gmail.com> From: Kees Cook Date: Tue, 27 Feb 2018 11:47:46 -0800 X-Google-Sender-Auth: Awjjgrh_J1Ki5oFIVtJRahWEJFI 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 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'll create a branch for this on git.kernel.org and see if anything surprising pops out. :) -Kees > + return -EACCES; > + } > + return 0; > +} > + > static __always_inline > const char *get_link(struct nameidata *nd) > { > @@ -3355,9 +3405,14 @@ static int do_last(struct nameidata *nd, > 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, nd->last.name, inode); > + if (unlikely(error)) > + goto out; > + } > error = -ENOTDIR; > if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) > goto out; > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 2a81556..9bf4e5c 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -72,6 +72,8 @@ > 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; > > typedef __kernel_rwf_t rwf_t; > > diff --git a/kernel/sysctl.c b/kernel/sysctl.c > index f98f28c..295f528 100644 > --- a/kernel/sysctl.c > +++ b/kernel/sysctl.c > @@ -1794,6 +1794,24 @@ static int sysrq_sysctl_handler(struct ctl_table *table, int write, > .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), > -- > 1.9.1 > -- Kees Cook Pixel Security