Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1584862imu; Tue, 6 Nov 2018 00:40:47 -0800 (PST) X-Google-Smtp-Source: AJdET5ef2WX4/JDyJJq+q1YWU+PRG1pbXTZLdXPOJoQbiBPS2Hgs7whj5UY0gCck5WX9qF1i6J37 X-Received: by 2002:a63:91c1:: with SMTP id l184mr20359298pge.29.1541493646971; Tue, 06 Nov 2018 00:40:46 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541493646; cv=none; d=google.com; s=arc-20160816; b=tiGxK4bwk7pNOkbWHfJI8ccve7nm7JnJp3Opa4/crYbiNiTYjsYPfmwf7dAGAaBDg+ yA6LgXWmwkZG9w617keoRBJUbltwQphVDmDiwY3bDylmeQZXRkIv/zVEshata2CKma+4 EAyOFULLisgmenV28QrlV+I2kSgedxUJZqPIm50lJwwaGVz96XHVBm4NxIuoSARoUgVH /WKQuH7HzCAj+bmZis4vAXy6T1liraOpul3AalIiB9LaZZXWekGaof9KYoLc7hBG86d/ S6+HTao3In2wvp9J6FdfXks9/+GGrmUPizBawM9Z4o3jDyhw2ouFPznsOoOG05Wo4xOG ASSQ== 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; bh=BrJ18zOyXzMhOXI7GIwUJkuli3VBFpljjKsEcPYnMNc=; b=ooKLPngfepA1Za06/m2YptKux9SOcM137L6JtLsMyGCkMoAJ5uDLC27+vTCtE+BySX 23WtV8dyfGUocqxqQXll2Gd4rIeJHcBmQ5BMqfo3YpmGy3+OpiG8YNfAGwBJE/J19obv XqayRKEKMSdW2dg2yH8F7lX/MQ4nHaY3ei2KdpgAZd4cuizQl6fUuyY4wNC3yzqib6gW fxNdVP1jmFt2br/OyYyRXTlTLVXU3JefILhAia/WqIhHaYjzlY59davtCB95TShEJoEK aikEkQysOVY35ZFdPZMUdE7U1HDjcnZtVbyykGPJHxtaJUr329yK52G8ffCicWnuEn+L lT5Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=temperror (no key for signature) header.i=@szeredi.hu header.s=google header.b=pJHuKHAE; 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 l23si15317955pgh.533.2018.11.06.00.40.31; Tue, 06 Nov 2018 00:40:46 -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=temperror (no key for signature) header.i=@szeredi.hu header.s=google header.b=pJHuKHAE; 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 S1730156AbeKFSDp (ORCPT + 99 others); Tue, 6 Nov 2018 13:03:45 -0500 Received: from mail-it1-f193.google.com ([209.85.166.193]:36273 "EHLO mail-it1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729021AbeKFSDp (ORCPT ); Tue, 6 Nov 2018 13:03:45 -0500 Received: by mail-it1-f193.google.com with SMTP id w7-v6so16590638itd.1 for ; Tue, 06 Nov 2018 00:39:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=szeredi.hu; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=BrJ18zOyXzMhOXI7GIwUJkuli3VBFpljjKsEcPYnMNc=; b=pJHuKHAEHEuV0s0p9xJ4c5x8SYMtnG155CczD2PNjE+gO4WnS56g1WimqWgQ4bxCJ/ ihQfJMNwwtqAqWhPbLUEBR1acYZZSnEGxbYgcsuQExMRuV92Eo0zEihhI4Li+kIKVieM feJCbpX4/csB8qAERn4FTPov6ZhoCZvLRyrDs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=BrJ18zOyXzMhOXI7GIwUJkuli3VBFpljjKsEcPYnMNc=; b=HjdOrmSixdH/ai7HOqqPkXOEy8gmEUuO35OFpT8JN8pd7QDFVvwfNPEU8i5q9U9zOQ BmAy4SlvllcCXQZcCPuFyb0LesMYUbCgCxlWamqzJEyKupRwswZCkXWQdFotrKz+S+QP eTZyRTq88FXqWbRuoVZCqQbZjXhx6uvKrkuRiqLkfr8ZKahkB7JZsUyI34KQ/IfTtWgJ GCsVM9v1DG5zafbR/RhrZFMx9RqFU9ZslAwtf0dmFiUGkQYY8r3snb8q1rs1IAwYLoJM RhbRR/m4tAaq8BbzIX28XV1JIqsoJTpqfkcZ/4jhA/dvS4DnTdEKPvhAvgNQfNl34I9e JgOw== X-Gm-Message-State: AGRZ1gIC6udR+/gfzkPIKAquEQZrPDi35Pn8mf7X+bfJSDMp4kskAVdA 7xdYuElvOLzgg8d5a2TugJyzxLncH9ys9UWXHdbn/g== X-Received: by 2002:a02:9951:: with SMTP id d17-v6mr22322958jak.78.1541493575876; Tue, 06 Nov 2018 00:39:35 -0800 (PST) MIME-Version: 1.0 Received: by 2002:a6b:ac42:0:0:0:0:0 with HTTP; Tue, 6 Nov 2018 00:39:35 -0800 (PST) X-Originating-IP: [94.21.144.184] In-Reply-To: References: <20181105182146.233025-1-salyzyn@android.com> <20181105182146.233025-3-salyzyn@android.com> From: Miklos Szeredi Date: Tue, 6 Nov 2018 09:39:35 +0100 Message-ID: Subject: Re: [PATCH v6 2/2] overlayfs: override_creds=off option bypass creator_cred To: Amir Goldstein Cc: Mark Salyzyn , linux-kernel , Jonathan Corbet , Vivek Goyal , "Eric W. Biederman" , Randy Dunlap , Stephen Smalley , overlayfs , linux-doc@vger.kernel.org, kernel-team@android.com 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 Mon, Nov 5, 2018 at 7:47 PM, Amir Goldstein wrote: > On Mon, Nov 5, 2018 at 8:22 PM Mark Salyzyn wrote: >> >> By default, all access to the upper, lower and work directories is the >> recorded mounter's MAC and DAC credentials. The incoming accesses are >> checked against the caller's credentials. >> >> If the principles of least privilege are applied, the mounter's >> credentials might not overlap the credentials of the caller's when >> accessing the overlayfs filesystem. For example, a file that a lower >> DAC privileged caller can execute, is MAC denied to the generally >> higher DAC privileged mounter, to prevent an attack vector. >> >> We add the option to turn off override_creds in the mount options; all >> subsequent operations after mount on the filesystem will be only the >> caller's credentials. The module boolean parameter and mount option >> override_creds is also added as a presence check for this "feature", >> existence of /sys/module/overlay/parameters/overlay_creds. >> >> Signed-off-by: Mark Salyzyn >> Cc: Miklos Szeredi >> Cc: Jonathan Corbet >> Cc: Vivek Goyal >> Cc: Eric W. Biederman >> Cc: Amir Goldstein >> Cc: Randy Dunlap >> Cc: Stephen Smalley >> Cc: linux-unionfs@vger.kernel.org >> Cc: linux-doc@vger.kernel.org >> Cc: linux-kernel@vger.kernel.org >> Cc: kernel-team@android.com >> >> v2: >> - Forward port changed attr to stat, resulting in a build error. >> - altered commit message. >> >> v3: >> - Change name from caller_credentials / creator_credentials to the >> boolean override_creds. >> - Changed from creator to mounter credentials. >> - Updated and fortified the documentation. >> - Added CONFIG_OVERLAY_FS_OVERRIDE_CREDS >> >> v4: >> - spelling and grammar errors in text >> >> v5: >> - beefed up the caveats in the Documentation >> - Is dependent on >> "overlayfs: check CAP_DAC_READ_SEARCH before issuing exportfs_decode_fh" >> "overlayfs: check CAP_MKNOD before issuing vfs_whiteout" >> - Added prwarn when override_creds=off >> >> v6: >> - Drop CONFIG_OVERLAY_FS_OVERRIDE_CREDS. >> - Do better with the documentation. >> - pr_warn message adjusted to report consequences. > > same comment about patch revision - not in commit message. > >> --- >> Documentation/filesystems/overlayfs.txt | 17 +++++++++++++++++ >> fs/overlayfs/copy_up.c | 2 +- >> fs/overlayfs/dir.c | 9 +++++---- >> fs/overlayfs/inode.c | 16 ++++++++-------- >> fs/overlayfs/namei.c | 6 +++--- >> fs/overlayfs/overlayfs.h | 1 + >> fs/overlayfs/ovl_entry.h | 1 + >> fs/overlayfs/readdir.c | 4 ++-- >> fs/overlayfs/super.c | 23 ++++++++++++++++++++++- >> fs/overlayfs/util.c | 12 ++++++++++-- >> 10 files changed, 70 insertions(+), 21 deletions(-) >> >> diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt >> index eef7d9d259e8..5cc299df4436 100644 >> --- a/Documentation/filesystems/overlayfs.txt >> +++ b/Documentation/filesystems/overlayfs.txt >> @@ -102,6 +102,23 @@ Only the lists of names from directories are merged. Other content >> such as metadata and extended attributes are reported for the upper >> directory only. These attributes of the lower directory are hidden. >> >> +credentials >> +----------- >> + >> +By default, all access to the upper, lower and work directories is the >> +recorded mounter's MAC and DAC credentials. The incoming accesses are >> +checked against the caller's credentials. >> + >> +override_creds mount flag turned off is reserved for when mounter and >> +caller MAC or DAC credentials do not overlap. Several unintended side >> +effects will occur. The caller with a lower privilege will not be >> +able to delete files or directories, create nodes, or search some >> +directories. The caller with higher privilege can perform unexpected >> +or unsecured operations. The uneven security model where upperdir >> +and workdir are opened at privilege, but accessed without, should only >> +be used with strict understanding of the side effects and of the >> +security policies. >> + >> whiteouts and opaque directories >> -------------------------------- >> >> diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c >> index 9e62dcf06fc4..dfab62ce7504 100644 >> --- a/fs/overlayfs/copy_up.c >> +++ b/fs/overlayfs/copy_up.c >> @@ -860,7 +860,7 @@ int ovl_copy_up_flags(struct dentry *dentry, int flags) >> dput(parent); >> dput(next); >> } >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> >> return err; >> } >> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c >> index c6289147c787..b7052e23c467 100644 >> --- a/fs/overlayfs/dir.c >> +++ b/fs/overlayfs/dir.c >> @@ -566,7 +566,8 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, >> override_cred->fsgid = inode->i_gid; >> if (!attr->hardlink) { >> err = security_dentry_create_files_as(dentry, >> - attr->mode, &dentry->d_name, old_cred, >> + attr->mode, &dentry->d_name, >> + old_cred ? old_cred : current_cred(), >> override_cred); >> if (err) { >> put_cred(override_cred); >> @@ -582,7 +583,7 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, >> err = ovl_create_over_whiteout(dentry, inode, attr); >> } >> out_revert_creds: >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> return err; >> } >> >> @@ -842,7 +843,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir) >> err = ovl_remove_upper(dentry, is_dir, &list); >> else >> err = ovl_remove_and_whiteout(dentry, &list); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> if (!err) { >> if (is_dir) >> clear_nlink(dentry->d_inode); >> @@ -1212,7 +1213,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, >> out_unlock: >> unlock_rename(new_upperdir, old_upperdir); >> out_revert_creds: >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> if (update_nlink) >> ovl_nlink_end(new); >> out_drop_write: >> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c >> index 6bcc9dedc342..192f5508ed45 100644 >> --- a/fs/overlayfs/inode.c >> +++ b/fs/overlayfs/inode.c >> @@ -64,7 +64,7 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr) >> inode_lock(upperdentry->d_inode); >> old_cred = ovl_override_creds(dentry->d_sb); >> err = notify_change(upperdentry, attr, NULL); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> if (!err) >> ovl_copyattr(upperdentry->d_inode, dentry->d_inode); >> inode_unlock(upperdentry->d_inode); >> @@ -260,7 +260,7 @@ int ovl_getattr(const struct path *path, struct kstat *stat, >> stat->nlink = dentry->d_inode->i_nlink; >> >> out: >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> >> return err; >> } >> @@ -303,7 +303,7 @@ int ovl_permission(struct inode *inode, int mask) >> >> old_cred = ovl_override_creds(inode->i_sb); >> err = inode_permission(realinode, mask); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> >> return err; >> } >> @@ -320,7 +320,7 @@ static const char *ovl_get_link(struct dentry *dentry, >> >> old_cred = ovl_override_creds(dentry->d_sb); >> p = vfs_get_link(ovl_dentry_real(dentry), done); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> return p; >> } >> >> @@ -363,7 +363,7 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name, >> WARN_ON(flags != XATTR_REPLACE); >> err = vfs_removexattr(realdentry, name); >> } >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> >> /* copy c/mtime */ >> ovl_copyattr(d_inode(realdentry), inode); >> @@ -384,7 +384,7 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name, >> >> old_cred = ovl_override_creds(dentry->d_sb); >> res = vfs_getxattr(realdentry, name, value, size); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> return res; >> } >> >> @@ -408,7 +408,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) >> >> old_cred = ovl_override_creds(dentry->d_sb); >> res = vfs_listxattr(realdentry, list, size); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> if (res <= 0 || size == 0) >> return res; >> >> @@ -443,7 +443,7 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type) >> >> old_cred = ovl_override_creds(inode->i_sb); >> acl = get_acl(realinode, type); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> >> return acl; >> } >> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c >> index aa012b6bd46e..b73e5f7aea2e 100644 >> --- a/fs/overlayfs/namei.c >> +++ b/fs/overlayfs/namei.c >> @@ -1074,7 +1074,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, >> goto out_free_oe; >> } >> >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> if (origin_path) { >> dput(origin_path->dentry); >> kfree(origin_path); >> @@ -1101,7 +1101,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, >> kfree(upperredirect); >> out: >> kfree(d.redirect); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> return ERR_PTR(err); >> } >> >> @@ -1155,7 +1155,7 @@ bool ovl_lower_positive(struct dentry *dentry) >> dput(this); >> } >> } >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> >> return positive; >> } >> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h >> index 5e45cb3630a0..6f8b6f9ff357 100644 >> --- a/fs/overlayfs/overlayfs.h >> +++ b/fs/overlayfs/overlayfs.h >> @@ -208,6 +208,7 @@ int ovl_want_write(struct dentry *dentry); >> void ovl_drop_write(struct dentry *dentry); >> struct dentry *ovl_workdir(struct dentry *dentry); >> const struct cred *ovl_override_creds(struct super_block *sb); >> +void ovl_revert_creds(const struct cred *oldcred); >> struct super_block *ovl_same_sb(struct super_block *sb); >> int ovl_can_decode_fh(struct super_block *sb); >> struct dentry *ovl_indexdir(struct super_block *sb); >> diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h >> index ec237035333a..e38eea8104be 100644 >> --- a/fs/overlayfs/ovl_entry.h >> +++ b/fs/overlayfs/ovl_entry.h >> @@ -20,6 +20,7 @@ struct ovl_config { >> bool nfs_export; >> int xino; >> bool metacopy; >> + bool override_creds; >> }; >> >> struct ovl_sb { >> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c >> index cc8303a806b4..ec591b49e902 100644 >> --- a/fs/overlayfs/readdir.c >> +++ b/fs/overlayfs/readdir.c >> @@ -289,7 +289,7 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd) >> } >> inode_unlock(dir->d_inode); >> } >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> >> return err; >> } >> @@ -921,7 +921,7 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) >> >> old_cred = ovl_override_creds(dentry->d_sb); >> err = ovl_dir_read_merged(dentry, list, &root); >> - revert_creds(old_cred); >> + ovl_revert_creds(old_cred); >> if (err) >> return err; >> >> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c >> index 0116735cc321..1669d4fa7ad8 100644 >> --- a/fs/overlayfs/super.c >> +++ b/fs/overlayfs/super.c >> @@ -56,6 +56,11 @@ module_param_named(xino_auto, ovl_xino_auto_def, bool, 0644); >> MODULE_PARM_DESC(ovl_xino_auto_def, >> "Auto enable xino feature"); >> >> +static bool __read_mostly ovl_default_override_creds = true; > > Please stick to conventions - ovl_override_creds_def. > >> +module_param_named(override_creds, ovl_default_override_creds, bool, 0644); >> +MODULE_PARM_DESC(ovl_default_override_creds, >> + "Use mounter's credentials for accesses"); >> + >> static void ovl_entry_stack_free(struct ovl_entry *oe) >> { >> unsigned int i; >> @@ -362,6 +367,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) >> if (ofs->config.metacopy != ovl_metacopy_def) >> seq_printf(m, ",metacopy=%s", >> ofs->config.metacopy ? "on" : "off"); >> + seq_show_option(m, "override_creds", > > show only if != ovl_override_creds_def > >> + ofs->config.override_creds ? "on" : "off"); >> return 0; >> } >> >> @@ -401,6 +408,8 @@ enum { >> OPT_XINO_AUTO, >> OPT_METACOPY_ON, >> OPT_METACOPY_OFF, >> + OPT_OVERRIDE_CREDS_ON, >> + OPT_OVERRIDE_CREDS_OFF, >> OPT_ERR, >> }; >> >> @@ -419,6 +428,8 @@ static const match_table_t ovl_tokens = { >> {OPT_XINO_AUTO, "xino=auto"}, >> {OPT_METACOPY_ON, "metacopy=on"}, >> {OPT_METACOPY_OFF, "metacopy=off"}, >> + {OPT_OVERRIDE_CREDS_ON, "override_creds=on"}, >> + {OPT_OVERRIDE_CREDS_OFF, "override_creds=off"}, >> {OPT_ERR, NULL} >> }; >> >> @@ -477,6 +488,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) >> config->redirect_mode = kstrdup(ovl_redirect_mode_def(), GFP_KERNEL); >> if (!config->redirect_mode) >> return -ENOMEM; >> + config->override_creds = ovl_default_override_creds; >> >> while ((p = ovl_next_opt(&opt)) != NULL) { >> int token; >> @@ -557,6 +569,14 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) >> config->metacopy = false; >> break; >> >> + case OPT_OVERRIDE_CREDS_ON: >> + config->override_creds = true; >> + break; >> + >> + case OPT_OVERRIDE_CREDS_OFF: >> + config->override_creds = false; >> + break; >> + >> default: >> pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p); >> return -EINVAL; >> @@ -1549,7 +1569,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) >> ovl_dentry_lower(root_dentry), NULL); >> >> sb->s_root = root_dentry; >> - >> + if (!ofs->config.override_creds) >> + pr_warn("overlayfs: override_creds=off, caller credentials may not be enough to delete file or directories, create nodes, or search directories.\n"); > > The audience is someone that has this feature on by mistake or someone > that turn it > on without understanding what it does. I am not sure that this is > scary enough, but > I don't have a better suggestion. > Will let others state their opinion. I don't think we need any warning message, writing down the rules in the documentation should be enough. Thanks, Miklos