From patchwork Wed Apr 1 21:39:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Colascione X-Patchwork-Id: 11469573 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CA8331805 for ; Wed, 1 Apr 2020 21:39:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9DCEE20772 for ; Wed, 1 Apr 2020 21:39:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="HxNEkkJW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733230AbgDAVjR (ORCPT ); Wed, 1 Apr 2020 17:39:17 -0400 Received: from mail-pj1-f73.google.com ([209.85.216.73]:37477 "EHLO mail-pj1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733145AbgDAVjQ (ORCPT ); Wed, 1 Apr 2020 17:39:16 -0400 Received: by mail-pj1-f73.google.com with SMTP id d9so1374708pjs.2 for ; Wed, 01 Apr 2020 14:39:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=YscA6Q2kVGFH1HcouLoCM3aSD8oDJbRIEKtVaQfAjvc=; b=HxNEkkJW57bngbpunni/nBN68oGx9Jk1oR8bT8TaxxsfN6UE5XlCMGp8B8G/8qpFHN mWiJmKNww3fp2vAVCu1Eq4KptGDaloPVraWXiOziSCTp+AUKIpi9V9Cue0gNKfzKR0qi UrbwHShuv4eBtA3ZrTSJ2CDw2TENj3o6pM1hm6g/mJRA3uuvxWFGNZB4CEdWpdg+3zlU q8PLQN5SMzbWfOOvd/6e4m5UmQh4qXm+AJxgSD8IkUSyJDGIKwJMUzDT+imovohlgS4E 1Gx6Nq3cwDMfgRcIZnUglk5alJOpmTeb62Ux0nhoBQI7iHCsYw0MQ+VwlQET6eywUcKA vNIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=YscA6Q2kVGFH1HcouLoCM3aSD8oDJbRIEKtVaQfAjvc=; b=K6P8KWE7wkS9I3/yJwAzlT2e/HCZma4Ce8asPTAzNnaG5Tw+kHawGY2uHfJOb1nLIP J2yMwlwNXSAYffkWoImjw5vr7kWVul/v4roFjoiddwQjraRO1Vac4bIhNL7AKjMw7jYL lOPLcc66SsN7egse3wniD6CuifYvaLx2YdCC7qy0qqMkP0uFSJ3tFgEv0CUIrOkL+I6X x+BFJVlbyKm6zgwjLOhJj5rokqkomSWW6MZibbDJvkVpQJQE0eqEKv+5KJRnh4GCAaoM GHomnJM/OhtZE84szG6LI1pqDVVFSNePRiJlE+w2o/9DvFiOkztTGI2cXYDzhIsX2ma2 u5IQ== X-Gm-Message-State: AGi0PuaC3hEBnSt3tSFyL5BVrHpmgUw9hEFP5EZRe1zt4NebnlM4XerT EfbvXhSYdNCvvulXSDBmsyqGEjEn+OY= X-Google-Smtp-Source: APiQypJuo8aeRmGJ4byP6CTvKUFIfWx8pqjZ6dBD9ad0ON5qSiHMKr9nsy8NzdNxdNSGqmuTyTe+36UsNos= X-Received: by 2002:a17:90a:1b22:: with SMTP id q31mr15047pjq.109.1585777154601; Wed, 01 Apr 2020 14:39:14 -0700 (PDT) Date: Wed, 1 Apr 2020 14:39:01 -0700 In-Reply-To: <20200401213903.182112-1-dancol@google.com> Message-Id: <20200401213903.182112-2-dancol@google.com> Mime-Version: 1.0 References: <20200326200634.222009-1-dancol@google.com> <20200401213903.182112-1-dancol@google.com> X-Mailer: git-send-email 2.26.0.rc2.310.g2932bb562d-goog Subject: [PATCH v5 1/3] Add a new LSM-supporting anonymous inode interface From: Daniel Colascione To: timmurray@google.com, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, viro@zeniv.linux.org.uk, paul@paul-moore.com, nnk@google.com, sds@tycho.nsa.gov, lokeshgidra@google.com, jmorris@namei.org Cc: Daniel Colascione Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This change adds two new functions, anon_inode_getfile_secure and anon_inode_getfd_secure, that create anonymous-node files with individual non-S_PRIVATE inodes to which security modules can apply policy. Existing callers continue using the original singleton-inode kind of anonymous-inode file. We can transition anonymous inode users to the new kind of anonymous inode in individual patches for the sake of bisection and review. The new functions accept an optional context_inode parameter that callers can use to provide additional contextual information to security modules, e.g., indicating that one anonymous struct file is a logical child of another, allowing a security model to propagate security information from one to the other. Signed-off-by: Daniel Colascione --- fs/anon_inodes.c | 191 ++++++++++++++++++++++++++++-------- include/linux/anon_inodes.h | 13 +++ include/linux/lsm_hooks.h | 11 +++ include/linux/security.h | 3 + security/security.c | 9 ++ 5 files changed, 186 insertions(+), 41 deletions(-) diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 89714308c25b..f87f221167cf 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -55,61 +55,108 @@ static struct file_system_type anon_inode_fs_type = { .kill_sb = kill_anon_super, }; -/** - * anon_inode_getfile - creates a new file instance by hooking it up to an - * anonymous inode, and a dentry that describe the "class" - * of the file - * - * @name: [in] name of the "class" of the new file - * @fops: [in] file operations for the new file - * @priv: [in] private data for the new file (will be file's private_data) - * @flags: [in] flags - * - * Creates a new file by hooking it on a single inode. This is useful for files - * that do not need to have a full-fledged inode in order to operate correctly. - * All the files created with anon_inode_getfile() will share a single inode, - * hence saving memory and avoiding code duplication for the file/inode/dentry - * setup. Returns the newly created file* or an error pointer. - */ -struct file *anon_inode_getfile(const char *name, - const struct file_operations *fops, - void *priv, int flags) +static struct inode *anon_inode_make_secure_inode( + const char *name, + const struct inode *context_inode) +{ + struct inode *inode; + const struct qstr qname = QSTR_INIT(name, strlen(name)); + int error; + + inode = alloc_anon_inode(anon_inode_mnt->mnt_sb); + if (IS_ERR(inode)) + return inode; + inode->i_flags &= ~S_PRIVATE; + error = security_inode_init_security_anon( + inode, &qname, context_inode); + if (error) { + iput(inode); + return ERR_PTR(error); + } + return inode; +} + +struct file *_anon_inode_getfile(const char *name, + const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode, + bool secure) { + struct inode *inode; struct file *file; - if (IS_ERR(anon_inode_inode)) - return ERR_PTR(-ENODEV); + if (secure) { + inode = anon_inode_make_secure_inode( + name, context_inode); + if (IS_ERR(inode)) + return ERR_PTR(PTR_ERR(inode)); + } else { + inode = anon_inode_inode; + if (IS_ERR(inode)) + return ERR_PTR(-ENODEV); + /* + * We know the anon_inode inode count is always + * greater than zero, so ihold() is safe. + */ + ihold(inode); + } - if (fops->owner && !try_module_get(fops->owner)) - return ERR_PTR(-ENOENT); + if (fops->owner && !try_module_get(fops->owner)) { + file = ERR_PTR(-ENOENT); + goto err; + } - /* - * We know the anon_inode inode count is always greater than zero, - * so ihold() is safe. - */ - ihold(anon_inode_inode); - file = alloc_file_pseudo(anon_inode_inode, anon_inode_mnt, name, + file = alloc_file_pseudo(inode, anon_inode_mnt, name, flags & (O_ACCMODE | O_NONBLOCK), fops); if (IS_ERR(file)) goto err; - file->f_mapping = anon_inode_inode->i_mapping; + file->f_mapping = inode->i_mapping; file->private_data = priv; return file; err: - iput(anon_inode_inode); + iput(inode); module_put(fops->owner); return file; } -EXPORT_SYMBOL_GPL(anon_inode_getfile); /** - * anon_inode_getfd - creates a new file instance by hooking it up to an - * anonymous inode, and a dentry that describe the "class" - * of the file + * anon_inode_getfile_secure - creates a new file instance by hooking + * it up to a new anonymous inode and a + * dentry that describe the "class" of the + * file. Make it possible to use security + * modules to control access to the + * new file. + * + * @name: [in] name of the "class" of the new file + * @fops: [in] file operations for the new file + * @priv: [in] private data for the new file (will be file's private_data) + * @flags: [in] flags + * + * Creates a new file by hooking it on an unspecified inode. This is + * useful for files that do not need to have a full-fledged filesystem + * to operate correctly. All the files created with + * anon_inode_getfile_secure() will have distinct inodes, avoiding + * code duplication for the file/inode/dentry setup. Returns the + * newly created file* or an error pointer. + */ +struct file *anon_inode_getfile_secure(const char *name, + const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode) +{ + return _anon_inode_getfile( + name, fops, priv, flags, context_inode, true); +} +EXPORT_SYMBOL_GPL(anon_inode_getfile_secure); + +/** + * anon_inode_getfile - creates a new file instance by hooking it up to an + * anonymous inode, and a dentry that describe the "class" + * of the file * * @name: [in] name of the "class" of the new file * @fops: [in] file operations for the new file @@ -118,12 +165,23 @@ EXPORT_SYMBOL_GPL(anon_inode_getfile); * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly. - * All the files created with anon_inode_getfd() will share a single inode, + * All the files created with anon_inode_getfile() will share a single inode, * hence saving memory and avoiding code duplication for the file/inode/dentry - * setup. Returns new descriptor or an error code. + * setup. Returns the newly created file* or an error pointer. */ -int anon_inode_getfd(const char *name, const struct file_operations *fops, - void *priv, int flags) +struct file *anon_inode_getfile(const char *name, + const struct file_operations *fops, + void *priv, int flags) +{ + return _anon_inode_getfile(name, fops, priv, flags, NULL, false); +} +EXPORT_SYMBOL_GPL(anon_inode_getfile); + +static int _anon_inode_getfd(const char *name, + const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode, + bool secure) { int error, fd; struct file *file; @@ -133,7 +191,8 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops, return error; fd = error; - file = anon_inode_getfile(name, fops, priv, flags); + file = _anon_inode_getfile(name, fops, priv, flags, context_inode, + secure); if (IS_ERR(file)) { error = PTR_ERR(file); goto err_put_unused_fd; @@ -146,6 +205,57 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops, put_unused_fd(fd); return error; } + +/** + * anon_inode_getfd_secure - creates a new file instance by hooking it + * up to a new anonymous inode and a dentry + * that describe the "class" of the file. + * Make it possible to use security modules + * to control access to the new file. + * + * @name: [in] name of the "class" of the new file + * @fops: [in] file operations for the new file + * @priv: [in] private data for the new file (will be file's private_data) + * @flags: [in] flags + * + * Creates a new file by hooking it on an unspecified inode. This is + * useful for files that do not need to have a full-fledged filesystem + * to operate correctly. All the files created with + * anon_inode_getfile_secure() will have distinct inodes, avoiding + * code duplication for the file/inode/dentry setup. Returns a newly + * created file descriptor or an error code. + */ +int anon_inode_getfd_secure(const char *name, const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode) +{ + return _anon_inode_getfd(name, fops, priv, flags, + context_inode, true); +} +EXPORT_SYMBOL_GPL(anon_inode_getfd_secure); + +/** + * anon_inode_getfd - creates a new file instance by hooking it up to + * an anonymous inode and a dentry that describe + * the "class" of the file + * + * @name: [in] name of the "class" of the new file + * @fops: [in] file operations for the new file + * @priv: [in] private data for the new file (will be file's private_data) + * @flags: [in] flags + * + * Creates a new file by hooking it on a single inode. This is + * useful for files that do not need to have a full-fledged inode in + * order to operate correctly. All the files created with + * anon_inode_getfile() will use the same singleton inode, reducing + * memory use and avoiding code duplication for the file/inode/dentry + * setup. Returns a newly created file descriptor or an error code. + */ +int anon_inode_getfd(const char *name, const struct file_operations *fops, + void *priv, int flags) +{ + return _anon_inode_getfd(name, fops, priv, flags, NULL, false); +} EXPORT_SYMBOL_GPL(anon_inode_getfd); static int __init anon_inode_init(void) @@ -162,4 +272,3 @@ static int __init anon_inode_init(void) } fs_initcall(anon_inode_init); - diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h index d0d7d96261ad..67bd85d92dca 100644 --- a/include/linux/anon_inodes.h +++ b/include/linux/anon_inodes.h @@ -10,12 +10,25 @@ #define _LINUX_ANON_INODES_H struct file_operations; +struct inode; + +struct file *anon_inode_getfile_secure(const char *name, + const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode); struct file *anon_inode_getfile(const char *name, const struct file_operations *fops, void *priv, int flags); + +int anon_inode_getfd_secure(const char *name, + const struct file_operations *fops, + void *priv, int flags, + const struct inode *context_inode); + int anon_inode_getfd(const char *name, const struct file_operations *fops, void *priv, int flags); + #endif /* _LINUX_ANON_INODES_H */ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 20d8cf194fb7..5434c1d285b2 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -215,6 +215,13 @@ * Returns 0 if @name and @value have been successfully set, * -EOPNOTSUPP if no security attribute is needed, or * -ENOMEM on memory allocation failure. + * @inode_init_security_anon: + * Set up a secure anonymous inode. + * @inode contains the inode structure + * @name name of the anonymous inode class + * @context_inode optional related inode + * Returns 0 on success. Returns -EPERM if the security module denies + * the creation of this inode. * @inode_create: * Check permission to create a regular file. * @dir contains inode structure of the parent of the new file. @@ -1552,6 +1559,9 @@ union security_list_options { const struct qstr *qstr, const char **name, void **value, size_t *len); + int (*inode_init_security_anon)(struct inode *inode, + const struct qstr *name, + const struct inode *context_inode); int (*inode_create)(struct inode *dir, struct dentry *dentry, umode_t mode); int (*inode_link)(struct dentry *old_dentry, struct inode *dir, @@ -1884,6 +1894,7 @@ struct security_hook_heads { struct hlist_head inode_alloc_security; struct hlist_head inode_free_security; struct hlist_head inode_init_security; + struct hlist_head inode_init_security_anon; struct hlist_head inode_create; struct hlist_head inode_link; struct hlist_head inode_unlink; diff --git a/include/linux/security.h b/include/linux/security.h index 64b19f050343..2108c3ce0666 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -320,6 +320,9 @@ void security_inode_free(struct inode *inode); int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, initxattrs initxattrs, void *fs_data); +int security_inode_init_security_anon(struct inode *inode, + const struct qstr *name, + const struct inode *context_inode); int security_old_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const char **name, void **value, size_t *len); diff --git a/security/security.c b/security/security.c index 565bc9b67276..70bfebada024 100644 --- a/security/security.c +++ b/security/security.c @@ -1033,6 +1033,15 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, } EXPORT_SYMBOL(security_inode_init_security); +int +security_inode_init_security_anon(struct inode *inode, + const struct qstr *name, + const struct inode *context_inode) +{ + return call_int_hook(inode_init_security_anon, 0, inode, name, + context_inode); +} + int security_old_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const char **name, void **value, size_t *len) From patchwork Wed Apr 1 21:39:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Colascione X-Patchwork-Id: 11469599 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B2675912 for ; Wed, 1 Apr 2020 21:39:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 86B3D206E9 for ; Wed, 1 Apr 2020 21:39:33 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="hotdlW0v" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733233AbgDAVjV (ORCPT ); Wed, 1 Apr 2020 17:39:21 -0400 Received: from mail-pf1-f202.google.com ([209.85.210.202]:56950 "EHLO mail-pf1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733220AbgDAVjU (ORCPT ); Wed, 1 Apr 2020 17:39:20 -0400 Received: by mail-pf1-f202.google.com with SMTP id s8so872688pfd.23 for ; Wed, 01 Apr 2020 14:39:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=6jHUkktZYnLJuOeQ47HqdKglnmNwVQppeyvzohEh60E=; b=hotdlW0vSo7Oc3YxuZoamTSPRrrrCvU+Z/v14Y5TkSuQsHiFXXabwUoA4+ordhQ+yY u+mtyjvIbg9v2Ot3PDkqXjTHa2iEo0J9ObAgkbbzSl9p9j2aK9u2mg8Qq6j6keVwuGy1 PI5+B5+KEI7XCrqDtNZOh48toONEbTskQx/DIzDE5EiBFSrXEolidC9r3D8u3rsgwsDS JZjj4nkITZsbKM/AURXIzmjOhbmgscw5me/yZJZupSNHAZFDco3sglkfZXWOSbuErxSj mqYYWH1AEGQEFZe+lb3nZbnwk4Q46t+nE9Rt88CyOSFS6m+XADbiYLljjNdFjlhYlIRy Bnxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=6jHUkktZYnLJuOeQ47HqdKglnmNwVQppeyvzohEh60E=; b=sjOWkHzfsM7E7xm+OxRpwb68gQrKph+ftYY9qua0iXXgNAqr/+iHmkgdpWVALegRsn ShYK6+L0skVmvuoTwIxUbhxqBN4drT7LJ2V8Vyeyu8xP4YcHkdUNOO7nlozKedncOz9k QMHCSQYIYtn/F1XXJGF8D7tI9Ri+QCgv6vvSeVQ9FZvf3PjveHfWpJvhaGqeiZOAdjp8 SocZ0P3LpjNbz0NuWOy9xFT9sztz2TUaemxaK+k5QptV8+HbC4lzB0CcPnqW/J56Bm7E uPKjFbBSVZnC45D60R1KxfqfnSySqYcOtBXnAQKH1RWrfhWRjdKdr/FMfBGZvgDkZB8r ZoQQ== X-Gm-Message-State: AGi0PuZDErhGPrsjaHrnfKFk0PEOjqsCEZJ365SgMIO7m6ZNP2B05pnm 2Dev3KC8io31p8ScUBDRGbScytFXXc0= X-Google-Smtp-Source: APiQypKviZ9567+jlzh79cNJ6g2InF7Sdo6NYY3WsjYqgIh8KYFj7B9dbw3YAfWPvDLTzocuUWrG0tnX9aM= X-Received: by 2002:a17:90a:cc10:: with SMTP id b16mr32757pju.29.1585777157804; Wed, 01 Apr 2020 14:39:17 -0700 (PDT) Date: Wed, 1 Apr 2020 14:39:02 -0700 In-Reply-To: <20200401213903.182112-1-dancol@google.com> Message-Id: <20200401213903.182112-3-dancol@google.com> Mime-Version: 1.0 References: <20200326200634.222009-1-dancol@google.com> <20200401213903.182112-1-dancol@google.com> X-Mailer: git-send-email 2.26.0.rc2.310.g2932bb562d-goog Subject: [PATCH v5 2/3] Teach SELinux about anonymous inodes From: Daniel Colascione To: timmurray@google.com, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, viro@zeniv.linux.org.uk, paul@paul-moore.com, nnk@google.com, sds@tycho.nsa.gov, lokeshgidra@google.com, jmorris@namei.org Cc: Daniel Colascione Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This change uses the anon_inodes and LSM infrastructure introduced in the previous patch to give SELinux the ability to control anonymous-inode files that are created using the new _secure() anon_inodes functions. A SELinux policy author detects and controls these anonymous inodes by adding a name-based type_transition rule that assigns a new security type to anonymous-inode files created in some domain. The name used for the name-based transition is the name associated with the anonymous inode for file listings --- e.g., "[userfaultfd]" or "[perf_event]". Example: type uffd_t; type_transition sysadm_t sysadm_t : anon_inode uffd_t "[userfaultfd]"; allow sysadm_t uffd_t:anon_inode { create }; (The next patch in this series is necessary for making userfaultfd support this new interface. The example above is just for exposition.) Signed-off-by: Daniel Colascione --- security/selinux/hooks.c | 53 +++++++++++++++++++++++++++++ security/selinux/include/classmap.h | 2 ++ 2 files changed, 55 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 1659b59fb5d7..6f7222d2e404 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2915,6 +2915,58 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, return 0; } +static int selinux_inode_init_security_anon(struct inode *inode, + const struct qstr *name, + const struct inode *context_inode) +{ + const struct task_security_struct *tsec = selinux_cred(current_cred()); + struct common_audit_data ad; + struct inode_security_struct *isec; + int rc; + + if (unlikely(!selinux_state.initialized)) + return 0; + + isec = selinux_inode(inode); + + /* + * We only get here once per ephemeral inode. The inode has + * been initialized via inode_alloc_security but is otherwise + * untouched. + */ + + if (context_inode) { + struct inode_security_struct *context_isec = + selinux_inode(context_inode); + isec->sclass = context_isec->sclass; + isec->sid = context_isec->sid; + } else { + isec->sclass = SECCLASS_ANON_INODE; + rc = security_transition_sid( + &selinux_state, tsec->sid, tsec->sid, + isec->sclass, name, &isec->sid); + if (rc) + return rc; + } + + isec->initialized = LABEL_INITIALIZED; + + /* + * Now that we've initialized security, check whether we're + * allowed to actually create this type of anonymous inode. + */ + + ad.type = LSM_AUDIT_DATA_INODE; + ad.u.inode = inode; + + return avc_has_perm(&selinux_state, + tsec->sid, + isec->sid, + isec->sclass, + FILE__CREATE, + &ad); +} + static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode) { return may_create(dir, dentry, SECCLASS_FILE); @@ -6923,6 +6975,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security), LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security), + LSM_HOOK_INIT(inode_init_security_anon, selinux_inode_init_security_anon), LSM_HOOK_INIT(inode_create, selinux_inode_create), LSM_HOOK_INIT(inode_link, selinux_inode_link), LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink), diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 986f3ac14282..263750b6aaac 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -248,6 +248,8 @@ struct security_class_mapping secclass_map[] = { {"open", "cpu", "kernel", "tracepoint", "read", "write"} }, { "lockdown", { "integrity", "confidentiality", NULL } }, + { "anon_inode", + { COMMON_FILE_PERMS, NULL } }, { NULL } }; From patchwork Wed Apr 1 21:39:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Colascione X-Patchwork-Id: 11469595 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8909281 for ; Wed, 1 Apr 2020 21:39:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6623E206E9 for ; Wed, 1 Apr 2020 21:39:28 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="FeWGGGhw" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733287AbgDAVj0 (ORCPT ); Wed, 1 Apr 2020 17:39:26 -0400 Received: from mail-pf1-f202.google.com ([209.85.210.202]:44877 "EHLO mail-pf1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733252AbgDAVjX (ORCPT ); Wed, 1 Apr 2020 17:39:23 -0400 Received: by mail-pf1-f202.google.com with SMTP id b204so896146pfb.11 for ; Wed, 01 Apr 2020 14:39:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=DdrdrRerOMvkv7vzgvI3ttukeUZ2OpdhnLu+un2eV2s=; b=FeWGGGhwmXwPYJI7fgk1nXVyU38RCP6BF6eOwbkfauA5Lh/S0K7Nc0SIi0FDfzLZf/ bBZtA01Z+mycAmiPQF6sdgjk5IWYb+EIHKaBqeFr9fpHlHKvNDviHMxgwnRIyxJ2QR+m FhGsIQS2Qu6FM71Bw7dEx5OsIbtQDambyY4fI9IepQU+Cs0Psa6YkBsLcX8FD8WIcBtp vBLKQP3cpYILo3x9L44bcB2+wn09ds8LLHXl7JYuY3kZHmAMRAlkc7Jl2jKOzPh1N4mo qnZvGI1i19BxSMYD89r0zKAZ5tBFZPiVCrcqrSEvreR+Eu5kKl7jbxfQkEj6DqoueZO0 AaSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=DdrdrRerOMvkv7vzgvI3ttukeUZ2OpdhnLu+un2eV2s=; b=KL1xDtLdowroOfPFCz2PSbg0tJkGL1ahnLS1Eh7NZa2oamm/D0DmUinjzJRG8ZS2fn Wzprjvg4pG2brzYSvTcCDL3GNOCBpG98xlJkXRP6bjy9e8GnCS1PjJ635RFdfRphokNw LC9TbpHCV3k108sC5Jv4FG+So6PntdO0NHdZL2gR9x05HF5zLZaW6Bwaz7us5y7KH6YM 0Pz6Gs07cBHWJoc2RBvrlsaWYgmNeAZRNVAunUk4Yz51sY53bNv9aLKIBcqdQM1y75W4 osLpI4NJcuWy3NHAeW9WrVZAOnhznr2q3u0xLJnOPCYrhs5Xozc4A3UkcjEK8FVoyKnz gfuQ== X-Gm-Message-State: AGi0PuY52kYdIP0xUF7Y276L8PYOtdnf5WTe8CIeZ2I4aVUHPi16xjVU HKti9lrY9Mj1bqsBzokp+LravSXvS/8= X-Google-Smtp-Source: APiQypJjIzb/5kmrh3RqCS3HOgTi/GT8cY+ji3kV8XKRQ+4eFtBDnifNrAYKZFtkDdm/KNfMZ+0y3mX+CAA= X-Received: by 2002:a17:90a:2147:: with SMTP id a65mr41318pje.176.1585777160964; Wed, 01 Apr 2020 14:39:20 -0700 (PDT) Date: Wed, 1 Apr 2020 14:39:03 -0700 In-Reply-To: <20200401213903.182112-1-dancol@google.com> Message-Id: <20200401213903.182112-4-dancol@google.com> Mime-Version: 1.0 References: <20200326200634.222009-1-dancol@google.com> <20200401213903.182112-1-dancol@google.com> X-Mailer: git-send-email 2.26.0.rc2.310.g2932bb562d-goog Subject: [PATCH v5 3/3] Wire UFFD up to SELinux From: Daniel Colascione To: timmurray@google.com, selinux@vger.kernel.org, linux-security-module@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, viro@zeniv.linux.org.uk, paul@paul-moore.com, nnk@google.com, sds@tycho.nsa.gov, lokeshgidra@google.com, jmorris@namei.org Cc: Daniel Colascione Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org This change gives userfaultfd file descriptors a real security context, allowing policy to act on them. Signed-off-by: Daniel Colascione --- fs/userfaultfd.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 37df7c9eedb1..78ff5d898733 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -76,6 +76,8 @@ struct userfaultfd_ctx { bool mmap_changing; /* mm with one ore more vmas attached to this userfaultfd_ctx */ struct mm_struct *mm; + /* The inode that owns this context --- not a strong reference. */ + const struct inode *owner; }; struct userfaultfd_fork_ctx { @@ -1022,8 +1024,10 @@ static int resolve_userfault_fork(struct userfaultfd_ctx *ctx, { int fd; - fd = anon_inode_getfd("[userfaultfd]", &userfaultfd_fops, new, - O_RDWR | (new->flags & UFFD_SHARED_FCNTL_FLAGS)); + fd = anon_inode_getfd_secure( + "[userfaultfd]", &userfaultfd_fops, new, + O_RDWR | (new->flags & UFFD_SHARED_FCNTL_FLAGS), + ctx->owner); if (fd < 0) return fd; @@ -1945,6 +1949,7 @@ static void init_once_userfaultfd_ctx(void *mem) SYSCALL_DEFINE1(userfaultfd, int, flags) { + struct file *file; struct userfaultfd_ctx *ctx; int fd; @@ -1974,8 +1979,25 @@ SYSCALL_DEFINE1(userfaultfd, int, flags) /* prevent the mm struct to be freed */ mmgrab(ctx->mm); - fd = anon_inode_getfd("[userfaultfd]", &userfaultfd_fops, ctx, - O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS)); + file = anon_inode_getfile_secure( + "[userfaultfd]", &userfaultfd_fops, ctx, + O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS), + NULL); + if (IS_ERR(file)) { + fd = PTR_ERR(file); + goto out; + } + + fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); + if (fd < 0) { + fput(file); + goto out; + } + + ctx->owner = file_inode(file); + fd_install(fd, file); + +out: if (fd < 0) { mmdrop(ctx->mm); kmem_cache_free(userfaultfd_ctx_cachep, ctx);