Linux-Fsdevel Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH v13 0/4] SELinux support for anonymous inodes and UFFD
@ 2020-11-12  1:53 Lokesh Gidra
  2020-11-12  1:53 ` [PATCH v13 1/4] security: add inode_init_security_anon() LSM hook Lokesh Gidra
                   ` (3 more replies)
  0 siblings, 4 replies; 19+ messages in thread
From: Lokesh Gidra @ 2020-11-12  1:53 UTC (permalink / raw)
  To: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Paul Moore
  Cc: Serge E. Hallyn, Eric Paris, Lokesh Gidra, Daniel Colascione,
	Kees Cook, Eric W. Biederman, KP Singh, David Howells,
	Anders Roxell, Sami Tolvanen, Matthew Garrett, Aaron Goidel,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch

Userfaultfd in unprivileged contexts could be potentially very
useful. We'd like to harden userfaultfd to make such unprivileged use
less risky. This patch series allows SELinux to manage userfaultfd
file descriptors and in the future, other kinds of
anonymous-inode-based file descriptor.  SELinux policy authors can
apply policy types to anonymous inodes by providing name-based
transition rules keyed off the anonymous inode internal name (
"[userfaultfd]" in the case of userfaultfd(2) file descriptors) and
applying policy to the new SIDs thus produced.

With SELinux managed userfaultfd, an admin can control creation and
movement of the file descriptors. In particular, handling of
a userfaultfd descriptor by a different process is essentially a
ptrace access into the process, without any of the corresponding
security_ptrace_access_check() checks. For privacy, the admin may
want to deny such accesses, which is possible with SELinux support.

Inside the kernel, a new anon_inode interface, anon_inode_getfd_secure,
allows callers to opt into this SELinux management. In this new "secure"
mode, anon_inodes create new ephemeral inodes for anonymous file objects
instead of reusing the normal anon_inodes singleton dummy inode. A new
LSM hook gives security modules an opportunity to configure and veto
these ephemeral inodes.

This patch series is one of two fork of [1] and is an
alternative to [2].

The primary difference between the two patch series is that this
partch series creates a unique inode for each "secure" anonymous
inode, while the other patch series ([2]) continues using the
singleton dummy anonymous inode and adds a way to attach SELinux
security information directly to file objects.

I prefer the approach in this patch series because 1) it's a smaller
patch than [2], and 2) it produces a more regular security
architecture: in this patch series, secure anonymous inodes aren't
S_PRIVATE and they maintain the SELinux property that the label for a
file is in its inode. We do need an additional inode per anonymous
file, but per-struct-file inode creation doesn't seem to be a problem
for pipes and sockets.

The previous version of this feature ([1]) created a new SELinux
security class for userfaultfd file descriptors. This version adopts
the generic transition-based approach of [2].

This patch series also differs from [2] in that it doesn't affect all
anonymous inodes right away --- instead requiring anon_inodes callers
to opt in --- but this difference isn't one of basic approach. The
important question to resolve is whether we should be creating new
inodes or enhancing per-file data.

Changes from the first version of the patch:

  - Removed some error checks
  - Defined a new anon_inode SELinux class to resolve the
    ambiguity in [3]
  - Inherit sclass as well as descriptor from context inode

Changes from the second version of the patch:

  - Fixed example policy in the commit message to reflect the use of
    the new anon_inode class.

Changes from the third version of the patch:

  - Dropped the fops parameter to the LSM hook
  - Documented hook parameters
  - Fixed incorrect class used for SELinux transition
  - Removed stray UFFD changed early in the series
  - Removed a redundant ERR_PTR(PTR_ERR())

Changes from the fourth version of the patch:

  - Removed an unused parameter from an internal function
  - Fixed function documentation

Changes from the fifth version of the patch:

  - Fixed function documentation in fs/anon_inodes.c and
    include/linux/lsm_hooks.h
  - Used anon_inode_getfd_secure() in userfaultfd() syscall and removed
    owner from userfaultfd_ctx.

Changes from the sixth version of the patch:

  - Removed definition of anon_inode_getfile_secure() as there are no
    callers.
  - Simplified function description of anon_inode_getfd_secure().
  - Elaborated more on the purpose of 'context_inode' in commit message.

Changes from the seventh version of the patch:

  - Fixed error handling in _anon_inode_getfile().
  - Fixed minor comment and indentation related issues.

Changes from the eighth version of the patch:

  - Replaced selinux_state.initialized with selinux_state.initialized

Changes from the ninth version of the patch:

  - Fixed function names in fs/anon_inodes.c
  - Fixed comment of anon_inode_getfd_secure()
  - Fixed name of the patch wherein userfaultfd code uses
    anon_inode_getfd_secure()

Changes from the tenth version of the patch:

  - Split first patch into VFS and LSM specific patches
  - Fixed comments in fs/anon_inodes.c
  - Fixed comment of alloc_anon_inode()

Changes from the eleventh version of the patch:

  - Removed comment of alloc_anon_inode() for consistency with the code
  - Fixed explanation of LSM hook in the commit message

Changes from the twelfth version of the patch:
  - Replaced FILE__CREATE with ANON_INODE__CREATE while initializing
    anon-inode's SELinux security struct.
  - Check context_inode's SELinux label and return -EACCES if it's
    invalid.

[1] https://lore.kernel.org/lkml/20200211225547.235083-1-dancol@google.com/
[2] https://lore.kernel.org/linux-fsdevel/20200213194157.5877-1-sds@tycho.nsa.gov/
[3] https://lore.kernel.org/lkml/23f725ca-5b5a-5938-fcc8-5bbbfc9ba9bc@tycho.nsa.gov/

Daniel Colascione (3):
  fs: add LSM-supporting anon-inode interface
  selinux: teach SELinux about anonymous inodes
  userfaultfd: use secure anon inodes for userfaultfd

Lokesh Gidra (1):
  security: add inode_init_security_anon() LSM hook

 fs/anon_inodes.c                    | 150 ++++++++++++++++++++--------
 fs/libfs.c                          |   5 -
 fs/userfaultfd.c                    |  19 ++--
 include/linux/anon_inodes.h         |   5 +
 include/linux/lsm_hook_defs.h       |   2 +
 include/linux/lsm_hooks.h           |   9 ++
 include/linux/security.h            |  10 ++
 security/security.c                 |   8 ++
 security/selinux/hooks.c            |  56 +++++++++++
 security/selinux/include/classmap.h |   2 +
 10 files changed, 212 insertions(+), 54 deletions(-)

-- 
2.29.2.299.gdc1121823c-goog


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v13 1/4] security: add inode_init_security_anon() LSM hook
  2020-11-12  1:53 [PATCH v13 0/4] SELinux support for anonymous inodes and UFFD Lokesh Gidra
@ 2020-11-12  1:53 ` Lokesh Gidra
  2020-11-12  1:53 ` [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface Lokesh Gidra
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 19+ messages in thread
From: Lokesh Gidra @ 2020-11-12  1:53 UTC (permalink / raw)
  To: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Paul Moore
  Cc: Serge E. Hallyn, Eric Paris, Lokesh Gidra, Daniel Colascione,
	Kees Cook, Eric W. Biederman, KP Singh, David Howells,
	Anders Roxell, Sami Tolvanen, Matthew Garrett, Aaron Goidel,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Eric Biggers

This change adds a new LSM hook, inode_init_security_anon(), that will
be used while creating secure anonymous inodes. The hook allows/denies
its creation and assigns a security context to the inode.

The new hook accepts an optional context_inode parameter that callers
can use to provide additional contextual information to security modules
for granting/denying permission to create an anon-inode of the same type.
This context_inode's security_context can also be used to initialize the
newly created anon-inode's security_context.

Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
---
 include/linux/lsm_hook_defs.h |  2 ++
 include/linux/lsm_hooks.h     |  9 +++++++++
 include/linux/security.h      | 10 ++++++++++
 security/security.c           |  8 ++++++++
 4 files changed, 29 insertions(+)

diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index 32a940117e7a..435a2e22ff95 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -113,6 +113,8 @@ LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode)
 LSM_HOOK(int, 0, inode_init_security, struct inode *inode,
 	 struct inode *dir, const struct qstr *qstr, const char **name,
 	 void **value, size_t *len)
+LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
+	 const struct qstr *name, const struct inode *context_inode)
 LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
 	 umode_t mode)
 LSM_HOOK(int, 0, inode_link, struct dentry *old_dentry, struct inode *dir,
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index c503f7ab8afb..3af055b7ee1f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -233,6 +233,15 @@
  *	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 the incore security field for the new anonymous inode
+ *      and return whether the inode creation is permitted by the security
+ *      module or not.
+ *      @inode contains the inode structure
+ *      @name name of the anonymous inode class
+ *      @context_inode optional related inode
+ *	Returns 0 on success, -EACCES if the security module denies the
+ *	creation of this inode, or another -errno upon other errors.
  * @inode_create:
  *	Check permission to create a regular file.
  *	@dir contains inode structure of the parent of the new file.
diff --git a/include/linux/security.h b/include/linux/security.h
index bc2725491560..7494a93b9ed9 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -323,6 +323,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);
@@ -737,6 +740,13 @@ static inline int security_inode_init_security(struct inode *inode,
 	return 0;
 }
 
+static inline int security_inode_init_security_anon(struct inode *inode,
+						    const struct qstr *name,
+						    const struct inode *context_inode)
+{
+	return 0;
+}
+
 static inline int security_old_inode_init_security(struct inode *inode,
 						   struct inode *dir,
 						   const struct qstr *qstr,
diff --git a/security/security.c b/security/security.c
index a28045dc9e7f..8989ba6af4f6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1058,6 +1058,14 @@ 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)
-- 
2.29.2.299.gdc1121823c-goog


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface
  2020-11-12  1:53 [PATCH v13 0/4] SELinux support for anonymous inodes and UFFD Lokesh Gidra
  2020-11-12  1:53 ` [PATCH v13 1/4] security: add inode_init_security_anon() LSM hook Lokesh Gidra
@ 2020-11-12  1:53 ` Lokesh Gidra
  2021-01-07  2:09   ` Paul Moore
  2020-11-12  1:53 ` [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes Lokesh Gidra
  2020-11-12  1:53 ` [PATCH v13 4/4] userfaultfd: use secure anon inodes for userfaultfd Lokesh Gidra
  3 siblings, 1 reply; 19+ messages in thread
From: Lokesh Gidra @ 2020-11-12  1:53 UTC (permalink / raw)
  To: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Paul Moore
  Cc: Serge E. Hallyn, Eric Paris, Lokesh Gidra, Daniel Colascione,
	Kees Cook, Eric W. Biederman, KP Singh, David Howells,
	Anders Roxell, Sami Tolvanen, Matthew Garrett, Aaron Goidel,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Daniel Colascione, Eric Biggers

From: Daniel Colascione <dancol@google.com>

This change adds a new function, anon_inode_getfd_secure, that creates
anonymous-node file with individual non-S_PRIVATE inode 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 function accepts an optional context_inode parameter that callers
can use to provide additional contextual information to security modules.
For example, in case of userfaultfd, the created inode is a 'logical child'
of the context_inode (userfaultfd inode of the parent process) in the sense
that it provides the security context required during creation of the child
process' userfaultfd inode.

Signed-off-by: Daniel Colascione <dancol@google.com>

[Delete obsolete comments to alloc_anon_inode()]
[Add context_inode description in comments to anon_inode_getfd_secure()]
[Remove definition of anon_inode_getfile_secure() as there are no callers]
[Make __anon_inode_getfile() static]
[Use correct error cast in __anon_inode_getfile()]
[Fix error handling in __anon_inode_getfile()]

Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
---
 fs/anon_inodes.c            | 150 ++++++++++++++++++++++++++----------
 fs/libfs.c                  |   5 --
 include/linux/anon_inodes.h |   5 ++
 3 files changed, 115 insertions(+), 45 deletions(-)

diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 89714308c25b..023337d65a03 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -55,61 +55,79 @@ 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 file *file;
+	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;
+}
 
-	if (IS_ERR(anon_inode_inode))
-		return ERR_PTR(-ENODEV);
+static 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 (fops->owner && !try_module_get(fops->owner))
 		return ERR_PTR(-ENOENT);
 
-	/*
-	 * 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,
+	if (secure) {
+		inode =	anon_inode_make_secure_inode(name, context_inode);
+		if (IS_ERR(inode)) {
+			file = ERR_CAST(inode);
+			goto err;
+		}
+	} else {
+		inode =	anon_inode_inode;
+		if (IS_ERR(inode)) {
+			file = ERR_PTR(-ENODEV);
+			goto err;
+		}
+		/*
+		 * We know the anon_inode inode count is always
+		 * greater than zero, so ihold() is safe.
+		 */
+		ihold(inode);
+	}
+
+	file = alloc_file_pseudo(inode, anon_inode_mnt, name,
 				 flags & (O_ACCMODE | O_NONBLOCK), fops);
 	if (IS_ERR(file))
-		goto err;
+		goto err_iput;
 
-	file->f_mapping = anon_inode_inode->i_mapping;
+	file->f_mapping = inode->i_mapping;
 
 	file->private_data = priv;
 
 	return file;
 
+err_iput:
+	iput(inode);
 err:
-	iput(anon_inode_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 - 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 +136,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 +162,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,8 +176,48 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
 	put_unused_fd(fd);
 	return error;
 }
+
+/**
+ * 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_getfd() 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);
 
+/**
+ * Like anon_inode_getfd(), but creates a new !S_PRIVATE anon inode rather than
+ * reuse the singleton anon inode, and calls the inode_init_security_anon() LSM
+ * hook. This allows the inode to have its own security context and for a LSM
+ * to reject creation of the inode.  An optional @context_inode argument is
+ * also added to provide the logical relationship with the new inode.  The LSM
+ * may use @context_inode in inode_init_security_anon(), but a reference to it
+ * is not held.
+ */
+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);
+
 static int __init anon_inode_init(void)
 {
 	anon_inode_mnt = kern_mount(&anon_inode_fs_type);
diff --git a/fs/libfs.c b/fs/libfs.c
index fc34361c1489..51c19c72e563 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1212,11 +1212,6 @@ static int anon_set_page_dirty(struct page *page)
 	return 0;
 };
 
-/*
- * A single inode exists for all anon_inode files. Contrary to pipes,
- * anon_inode inodes have no associated per-instance data, so we need
- * only allocate one of them.
- */
 struct inode *alloc_anon_inode(struct super_block *s)
 {
 	static const struct address_space_operations anon_aops = {
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
index d0d7d96261ad..71881a2b6f78 100644
--- a/include/linux/anon_inodes.h
+++ b/include/linux/anon_inodes.h
@@ -10,12 +10,17 @@
 #define _LINUX_ANON_INODES_H
 
 struct file_operations;
+struct inode;
 
 struct file *anon_inode_getfile(const char *name,
 				const struct file_operations *fops,
 				void *priv, int flags);
 int anon_inode_getfd(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);
 
 #endif /* _LINUX_ANON_INODES_H */
 
-- 
2.29.2.299.gdc1121823c-goog


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2020-11-12  1:53 [PATCH v13 0/4] SELinux support for anonymous inodes and UFFD Lokesh Gidra
  2020-11-12  1:53 ` [PATCH v13 1/4] security: add inode_init_security_anon() LSM hook Lokesh Gidra
  2020-11-12  1:53 ` [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface Lokesh Gidra
@ 2020-11-12  1:53 ` Lokesh Gidra
  2021-01-07  3:03   ` Paul Moore
  2020-11-12  1:53 ` [PATCH v13 4/4] userfaultfd: use secure anon inodes for userfaultfd Lokesh Gidra
  3 siblings, 1 reply; 19+ messages in thread
From: Lokesh Gidra @ 2020-11-12  1:53 UTC (permalink / raw)
  To: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Paul Moore
  Cc: Serge E. Hallyn, Eric Paris, Lokesh Gidra, Daniel Colascione,
	Kees Cook, Eric W. Biederman, KP Singh, David Howells,
	Anders Roxell, Sami Tolvanen, Matthew Garrett, Aaron Goidel,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Daniel Colascione

From: Daniel Colascione <dancol@google.com>

This change uses the anon_inodes and LSM infrastructure introduced in
the previous patches to give SELinux the ability to control
anonymous-inode files that are created using the new
anon_inode_getfd_secure() function.

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 <dancol@google.com>
Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
---
 security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
 security/selinux/include/classmap.h |  2 ++
 2 files changed, 58 insertions(+)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 6b1826fc3658..d092aa512868 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
+		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);
+		if (context_isec->initialized != LABEL_INITIALIZED)
+			return -EACCES;
+
+		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,
+			    ANON_INODE__CREATE,
+			    &ad);
+}
+
 static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
 {
 	return may_create(dir, dentry, SECCLASS_FILE);
@@ -6992,6 +7047,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 40cebde62856..ba2e01a6955c 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -249,6 +249,8 @@ struct security_class_mapping secclass_map[] = {
 	  {"open", "cpu", "kernel", "tracepoint", "read", "write"} },
 	{ "lockdown",
 	  { "integrity", "confidentiality", NULL } },
+	{ "anon_inode",
+	  { COMMON_FILE_PERMS, NULL } },
 	{ NULL }
   };
 
-- 
2.29.2.299.gdc1121823c-goog


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v13 4/4] userfaultfd: use secure anon inodes for userfaultfd
  2020-11-12  1:53 [PATCH v13 0/4] SELinux support for anonymous inodes and UFFD Lokesh Gidra
                   ` (2 preceding siblings ...)
  2020-11-12  1:53 ` [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes Lokesh Gidra
@ 2020-11-12  1:53 ` Lokesh Gidra
  3 siblings, 0 replies; 19+ messages in thread
From: Lokesh Gidra @ 2020-11-12  1:53 UTC (permalink / raw)
  To: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Paul Moore
  Cc: Serge E. Hallyn, Eric Paris, Lokesh Gidra, Daniel Colascione,
	Kees Cook, Eric W. Biederman, KP Singh, David Howells,
	Anders Roxell, Sami Tolvanen, Matthew Garrett, Aaron Goidel,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Daniel Colascione, Eric Biggers

From: Daniel Colascione <dancol@google.com>

This change gives userfaultfd file descriptors a real security
context, allowing policy to act on them.

Signed-off-by: Daniel Colascione <dancol@google.com>

[Remove owner inode from userfaultfd_ctx]
[Use anon_inode_getfd_secure() instead of anon_inode_getfile_secure()
 in userfaultfd syscall]
[Use inode of file in userfaultfd_read() in resolve_userfault_fork()]

Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
Reviewed-by: Eric Biggers <ebiggers@google.com>
---
 fs/userfaultfd.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c
index 000b457ad087..dd78daf06de6 100644
--- a/fs/userfaultfd.c
+++ b/fs/userfaultfd.c
@@ -972,14 +972,14 @@ static __poll_t userfaultfd_poll(struct file *file, poll_table *wait)
 
 static const struct file_operations userfaultfd_fops;
 
-static int resolve_userfault_fork(struct userfaultfd_ctx *ctx,
-				  struct userfaultfd_ctx *new,
+static int resolve_userfault_fork(struct userfaultfd_ctx *new,
+				  struct inode *inode,
 				  struct uffd_msg *msg)
 {
 	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), inode);
 	if (fd < 0)
 		return fd;
 
@@ -989,7 +989,7 @@ static int resolve_userfault_fork(struct userfaultfd_ctx *ctx,
 }
 
 static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
-				    struct uffd_msg *msg)
+				    struct uffd_msg *msg, struct inode *inode)
 {
 	ssize_t ret;
 	DECLARE_WAITQUEUE(wait, current);
@@ -1100,7 +1100,7 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait,
 	spin_unlock_irq(&ctx->fd_wqh.lock);
 
 	if (!ret && msg->event == UFFD_EVENT_FORK) {
-		ret = resolve_userfault_fork(ctx, fork_nctx, msg);
+		ret = resolve_userfault_fork(fork_nctx, inode, msg);
 		spin_lock_irq(&ctx->event_wqh.lock);
 		if (!list_empty(&fork_event)) {
 			/*
@@ -1160,6 +1160,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf,
 	ssize_t _ret, ret = 0;
 	struct uffd_msg msg;
 	int no_wait = file->f_flags & O_NONBLOCK;
+	struct inode *inode = file_inode(file);
 
 	if (ctx->state == UFFD_STATE_WAIT_API)
 		return -EINVAL;
@@ -1167,7 +1168,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf,
 	for (;;) {
 		if (count < sizeof(msg))
 			return ret ? ret : -EINVAL;
-		_ret = userfaultfd_ctx_read(ctx, no_wait, &msg);
+		_ret = userfaultfd_ctx_read(ctx, no_wait, &msg, inode);
 		if (_ret < 0)
 			return ret ? ret : _ret;
 		if (copy_to_user((__u64 __user *) buf, &msg, sizeof(msg)))
@@ -1985,8 +1986,8 @@ 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));
+	fd = anon_inode_getfd_secure("[userfaultfd]", &userfaultfd_fops, ctx,
+			O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS), NULL);
 	if (fd < 0) {
 		mmdrop(ctx->mm);
 		kmem_cache_free(userfaultfd_ctx_cachep, ctx);
-- 
2.29.2.299.gdc1121823c-goog


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface
  2020-11-12  1:53 ` [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface Lokesh Gidra
@ 2021-01-07  2:09   ` Paul Moore
  2021-01-07  2:42     ` dancol
  2021-01-07  2:43     ` Lokesh Gidra
  0 siblings, 2 replies; 19+ messages in thread
From: Paul Moore @ 2021-01-07  2:09 UTC (permalink / raw)
  To: Lokesh Gidra
  Cc: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Daniel Colascione, Eric Biggers

On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> From: Daniel Colascione <dancol@google.com>
>
> This change adds a new function, anon_inode_getfd_secure, that creates
> anonymous-node file with individual non-S_PRIVATE inode 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 function accepts an optional context_inode parameter that callers
> can use to provide additional contextual information to security modules.
> For example, in case of userfaultfd, the created inode is a 'logical child'
> of the context_inode (userfaultfd inode of the parent process) in the sense
> that it provides the security context required during creation of the child
> process' userfaultfd inode.
>
> Signed-off-by: Daniel Colascione <dancol@google.com>
>
> [Delete obsolete comments to alloc_anon_inode()]
> [Add context_inode description in comments to anon_inode_getfd_secure()]
> [Remove definition of anon_inode_getfile_secure() as there are no callers]
> [Make __anon_inode_getfile() static]
> [Use correct error cast in __anon_inode_getfile()]
> [Fix error handling in __anon_inode_getfile()]

Lokesh, I'm assuming you made the changes in the brackets above?  If
so they should include your initials or some other means of
attributing them to you, e.g. "[LG: Fix error ...]".

> Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> Reviewed-by: Eric Biggers <ebiggers@google.com>
> ---
>  fs/anon_inodes.c            | 150 ++++++++++++++++++++++++++----------
>  fs/libfs.c                  |   5 --
>  include/linux/anon_inodes.h |   5 ++
>  3 files changed, 115 insertions(+), 45 deletions(-)
>
> diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
> index 89714308c25b..023337d65a03 100644
> --- a/fs/anon_inodes.c
> +++ b/fs/anon_inodes.c
> @@ -55,61 +55,79 @@ 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 file *file;
> +       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;
> +}
>
> -       if (IS_ERR(anon_inode_inode))
> -               return ERR_PTR(-ENODEV);
> +static struct file *__anon_inode_getfile(const char *name,
> +                                        const struct file_operations *fops,
> +                                        void *priv, int flags,
> +                                        const struct inode *context_inode,
> +                                        bool secure)

Is it necessary to pass both the context_inode pointer and the secure
boolean?  It seems like if context_inode is non-NULL then one could
assume that a secure anonymous inode was requested; is there ever
going to be a case where this is not true?

> +{
> +       struct inode *inode;
> +       struct file *file;
>
>         if (fops->owner && !try_module_get(fops->owner))
>                 return ERR_PTR(-ENOENT);
>
> -       /*
> -        * 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,
> +       if (secure) {
> +               inode = anon_inode_make_secure_inode(name, context_inode);
> +               if (IS_ERR(inode)) {
> +                       file = ERR_CAST(inode);
> +                       goto err;
> +               }
> +       } else {
> +               inode = anon_inode_inode;
> +               if (IS_ERR(inode)) {
> +                       file = ERR_PTR(-ENODEV);
> +                       goto err;
> +               }
> +               /*
> +                * We know the anon_inode inode count is always
> +                * greater than zero, so ihold() is safe.
> +                */
> +               ihold(inode);
> +       }
> +
> +       file = alloc_file_pseudo(inode, anon_inode_mnt, name,
>                                  flags & (O_ACCMODE | O_NONBLOCK), fops);
>         if (IS_ERR(file))
> -               goto err;
> +               goto err_iput;
>
> -       file->f_mapping = anon_inode_inode->i_mapping;
> +       file->f_mapping = inode->i_mapping;
>
>         file->private_data = priv;
>
>         return file;
>
> +err_iput:
> +       iput(inode);
>  err:
> -       iput(anon_inode_inode);
>         module_put(fops->owner);
>         return file;
>  }
> -EXPORT_SYMBOL_GPL(anon_inode_getfile);

--
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface
  2021-01-07  2:09   ` Paul Moore
@ 2021-01-07  2:42     ` dancol
  2021-01-07  3:05       ` Paul Moore
  2021-01-07  2:43     ` Lokesh Gidra
  1 sibling, 1 reply; 19+ messages in thread
From: dancol @ 2021-01-07  2:42 UTC (permalink / raw)
  To: Paul Moore
  Cc: Lokesh Gidra, Andrea Arcangeli, Alexander Viro, James Morris,
	Stephen Smalley, Casey Schaufler, Eric Biggers, Serge E. Hallyn,
	Eric Paris, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Daniel Colascione, Eric Biggers

On 2021-01-06 21:09, Paul Moore wrote:
> Is it necessary to pass both the context_inode pointer and the secure
> boolean?  It seems like if context_inode is non-NULL then one could
> assume that a secure anonymous inode was requested; is there ever
> going to be a case where this is not true?

The converse isn't true though: it makes sense to ask for a secure inode 
with a NULL context inode.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface
  2021-01-07  2:09   ` Paul Moore
  2021-01-07  2:42     ` dancol
@ 2021-01-07  2:43     ` Lokesh Gidra
  2021-01-07  3:08       ` Paul Moore
  1 sibling, 1 reply; 19+ messages in thread
From: Lokesh Gidra @ 2021-01-07  2:43 UTC (permalink / raw)
  To: Paul Moore
  Cc: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, Linux FS Devel,
	linux-kernel, LSM List, SElinux list, Kalesh Singh,
	Calin Juravle, Suren Baghdasaryan, Jeffrey Vander Stoep,
	Cc: Android Kernel, open list:MEMORY MANAGEMENT, Andrew Morton,
	hch, Daniel Colascione, Eric Biggers

On Wed, Jan 6, 2021 at 6:10 PM Paul Moore <paul@paul-moore.com> wrote:
>
> On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > From: Daniel Colascione <dancol@google.com>
> >
> > This change adds a new function, anon_inode_getfd_secure, that creates
> > anonymous-node file with individual non-S_PRIVATE inode 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 function accepts an optional context_inode parameter that callers
> > can use to provide additional contextual information to security modules.
> > For example, in case of userfaultfd, the created inode is a 'logical child'
> > of the context_inode (userfaultfd inode of the parent process) in the sense
> > that it provides the security context required during creation of the child
> > process' userfaultfd inode.
> >
> > Signed-off-by: Daniel Colascione <dancol@google.com>
> >
> > [Delete obsolete comments to alloc_anon_inode()]
> > [Add context_inode description in comments to anon_inode_getfd_secure()]
> > [Remove definition of anon_inode_getfile_secure() as there are no callers]
> > [Make __anon_inode_getfile() static]
> > [Use correct error cast in __anon_inode_getfile()]
> > [Fix error handling in __anon_inode_getfile()]
>
> Lokesh, I'm assuming you made the changes in the brackets above?  If
> so they should include your initials or some other means of
> attributing them to you, e.g. "[LG: Fix error ...]".

Thanks for reviewing the patch. Sorry for missing this. If it's
critical then I can upload another version of the patches to fix this.
Kindly let me know.
>
> > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > Reviewed-by: Eric Biggers <ebiggers@google.com>
> > ---
> >  fs/anon_inodes.c            | 150 ++++++++++++++++++++++++++----------
> >  fs/libfs.c                  |   5 --
> >  include/linux/anon_inodes.h |   5 ++
> >  3 files changed, 115 insertions(+), 45 deletions(-)
> >
> > diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
> > index 89714308c25b..023337d65a03 100644
> > --- a/fs/anon_inodes.c
> > +++ b/fs/anon_inodes.c
> > @@ -55,61 +55,79 @@ 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 file *file;
> > +       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;
> > +}
> >
> > -       if (IS_ERR(anon_inode_inode))
> > -               return ERR_PTR(-ENODEV);
> > +static struct file *__anon_inode_getfile(const char *name,
> > +                                        const struct file_operations *fops,
> > +                                        void *priv, int flags,
> > +                                        const struct inode *context_inode,
> > +                                        bool secure)
>
> Is it necessary to pass both the context_inode pointer and the secure
> boolean?  It seems like if context_inode is non-NULL then one could
> assume that a secure anonymous inode was requested; is there ever
> going to be a case where this is not true?

Yes, it is necessary as there are scenarios where a secure anon-inode
is to be created but there is no context_inode available. For
instance, in patch 4/4 of this series you'll see that when a secure
anon-inode is created in the userfaultfd syscall, context_inode isn't
available.
>
> > +{
> > +       struct inode *inode;
> > +       struct file *file;
> >
> >         if (fops->owner && !try_module_get(fops->owner))
> >                 return ERR_PTR(-ENOENT);
> >
> > -       /*
> > -        * 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,
> > +       if (secure) {
> > +               inode = anon_inode_make_secure_inode(name, context_inode);
> > +               if (IS_ERR(inode)) {
> > +                       file = ERR_CAST(inode);
> > +                       goto err;
> > +               }
> > +       } else {
> > +               inode = anon_inode_inode;
> > +               if (IS_ERR(inode)) {
> > +                       file = ERR_PTR(-ENODEV);
> > +                       goto err;
> > +               }
> > +               /*
> > +                * We know the anon_inode inode count is always
> > +                * greater than zero, so ihold() is safe.
> > +                */
> > +               ihold(inode);
> > +       }
> > +
> > +       file = alloc_file_pseudo(inode, anon_inode_mnt, name,
> >                                  flags & (O_ACCMODE | O_NONBLOCK), fops);
> >         if (IS_ERR(file))
> > -               goto err;
> > +               goto err_iput;
> >
> > -       file->f_mapping = anon_inode_inode->i_mapping;
> > +       file->f_mapping = inode->i_mapping;
> >
> >         file->private_data = priv;
> >
> >         return file;
> >
> > +err_iput:
> > +       iput(inode);
> >  err:
> > -       iput(anon_inode_inode);
> >         module_put(fops->owner);
> >         return file;
> >  }
> > -EXPORT_SYMBOL_GPL(anon_inode_getfile);
>
> --
> paul moore
> www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2020-11-12  1:53 ` [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes Lokesh Gidra
@ 2021-01-07  3:03   ` Paul Moore
  2021-01-07  3:55     ` Lokesh Gidra
  2021-01-08 19:35     ` Stephen Smalley
  0 siblings, 2 replies; 19+ messages in thread
From: Paul Moore @ 2021-01-07  3:03 UTC (permalink / raw)
  To: Lokesh Gidra
  Cc: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Daniel Colascione

On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> From: Daniel Colascione <dancol@google.com>
>
> This change uses the anon_inodes and LSM infrastructure introduced in
> the previous patches to give SELinux the ability to control
> anonymous-inode files that are created using the new
> anon_inode_getfd_secure() function.
>
> 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 <dancol@google.com>
> Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> ---
>  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
>  security/selinux/include/classmap.h |  2 ++
>  2 files changed, 58 insertions(+)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 6b1826fc3658..d092aa512868 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> +               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);
> +               if (context_isec->initialized != LABEL_INITIALIZED)
> +                       return -EACCES;
> +
> +               isec->sclass = context_isec->sclass;

Taking the object class directly from the context_inode is
interesting, and I suspect problematic.  In the case below where no
context_inode is supplied the object class is set to
SECCLASS_ANON_INODE, which is correct, but when a context_inode is
supplied there is no guarantee that the object class will be set to
SECCLASS_ANON_INODE.  This could both pose a problem for policy
writers (how do you distinguish the anon inode from other normal file
inodes in this case?) as well as an outright fault later in this
function when we try to check the ANON_INODE__CREATE on an object
other than a SECCLASS_ANON_INODE object.

It works in the userfaultfd case because the context_inode is
originally created with this function so the object class is correctly
set to SECCLASS_ANON_INODE, but can we always guarantee that to be the
case?  Do we ever need or want to support using a context_inode that
is not SECCLASS_ANON_INODE?

> +               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,
> +                           ANON_INODE__CREATE,
> +                           &ad);
> +}

-- 
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface
  2021-01-07  2:42     ` dancol
@ 2021-01-07  3:05       ` Paul Moore
  0 siblings, 0 replies; 19+ messages in thread
From: Paul Moore @ 2021-01-07  3:05 UTC (permalink / raw)
  To: dancol
  Cc: Lokesh Gidra, Andrea Arcangeli, Alexander Viro, James Morris,
	Stephen Smalley, Casey Schaufler, Eric Biggers, Serge E. Hallyn,
	Eric Paris, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, linux-fsdevel,
	linux-kernel, linux-security-module, selinux, kaleshsingh, calin,
	surenb, jeffv, kernel-team, linux-mm, Andrew Morton, hch,
	Daniel Colascione, Eric Biggers

On Wed, Jan 6, 2021 at 9:42 PM dancol <dancol@dancol.org> wrote:
>
> On 2021-01-06 21:09, Paul Moore wrote:
> > Is it necessary to pass both the context_inode pointer and the secure
> > boolean?  It seems like if context_inode is non-NULL then one could
> > assume that a secure anonymous inode was requested; is there ever
> > going to be a case where this is not true?
>
> The converse isn't true though: it makes sense to ask for a secure inode
> with a NULL context inode.

Having looked at patch 3/4 and 4/4 I just realized that and was coming
back to update my comments :)

-- 
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface
  2021-01-07  2:43     ` Lokesh Gidra
@ 2021-01-07  3:08       ` Paul Moore
  0 siblings, 0 replies; 19+ messages in thread
From: Paul Moore @ 2021-01-07  3:08 UTC (permalink / raw)
  To: Lokesh Gidra
  Cc: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, Linux FS Devel,
	linux-kernel, LSM List, SElinux list, Kalesh Singh,
	Calin Juravle, Suren Baghdasaryan, Jeffrey Vander Stoep,
	Cc: Android Kernel, open list:MEMORY MANAGEMENT, Andrew Morton,
	hch, Daniel Colascione, Eric Biggers

On Wed, Jan 6, 2021 at 9:44 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> On Wed, Jan 6, 2021 at 6:10 PM Paul Moore <paul@paul-moore.com> wrote:
> >
> > On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > > From: Daniel Colascione <dancol@google.com>
> > >
> > > This change adds a new function, anon_inode_getfd_secure, that creates
> > > anonymous-node file with individual non-S_PRIVATE inode 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 function accepts an optional context_inode parameter that callers
> > > can use to provide additional contextual information to security modules.
> > > For example, in case of userfaultfd, the created inode is a 'logical child'
> > > of the context_inode (userfaultfd inode of the parent process) in the sense
> > > that it provides the security context required during creation of the child
> > > process' userfaultfd inode.
> > >
> > > Signed-off-by: Daniel Colascione <dancol@google.com>
> > >
> > > [Delete obsolete comments to alloc_anon_inode()]
> > > [Add context_inode description in comments to anon_inode_getfd_secure()]
> > > [Remove definition of anon_inode_getfile_secure() as there are no callers]
> > > [Make __anon_inode_getfile() static]
> > > [Use correct error cast in __anon_inode_getfile()]
> > > [Fix error handling in __anon_inode_getfile()]
> >
> > Lokesh, I'm assuming you made the changes in the brackets above?  If
> > so they should include your initials or some other means of
> > attributing them to you, e.g. "[LG: Fix error ...]".
>
> Thanks for reviewing the patch. Sorry for missing this. If it's
> critical then I can upload another version of the patches to fix this.
> Kindly let me know.

Normally that is something I could fix during a merge with your
approval, but see my comments to patch 3/4; I think this patchset
still needs some work.

> > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > > Reviewed-by: Eric Biggers <ebiggers@google.com>
> > > ---
> > >  fs/anon_inodes.c            | 150 ++++++++++++++++++++++++++----------
> > >  fs/libfs.c                  |   5 --
> > >  include/linux/anon_inodes.h |   5 ++
> > >  3 files changed, 115 insertions(+), 45 deletions(-)

...

> > > +static struct file *__anon_inode_getfile(const char *name,
> > > +                                        const struct file_operations *fops,
> > > +                                        void *priv, int flags,
> > > +                                        const struct inode *context_inode,
> > > +                                        bool secure)
> >
> > Is it necessary to pass both the context_inode pointer and the secure
> > boolean?  It seems like if context_inode is non-NULL then one could
> > assume that a secure anonymous inode was requested; is there ever
> > going to be a case where this is not true?
>
> Yes, it is necessary as there are scenarios where a secure anon-inode
> is to be created but there is no context_inode available. For
> instance, in patch 4/4 of this series you'll see that when a secure
> anon-inode is created in the userfaultfd syscall, context_inode isn't
> available.

My mistake, I didn't realize this until I got further in the patchset.

-- 
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-07  3:03   ` Paul Moore
@ 2021-01-07  3:55     ` Lokesh Gidra
  2021-01-07 22:30       ` Paul Moore
  2021-01-08 19:35     ` Stephen Smalley
  1 sibling, 1 reply; 19+ messages in thread
From: Lokesh Gidra @ 2021-01-07  3:55 UTC (permalink / raw)
  To: Paul Moore
  Cc: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov, Adrian Reber,
	Aleksa Sarai, Linux FS Devel, linux-kernel, LSM List,
	SElinux list, Kalesh Singh, Calin Juravle, Suren Baghdasaryan,
	Jeffrey Vander Stoep, Cc: Android Kernel,
	open list:MEMORY MANAGEMENT, Andrew Morton, hch

On Wed, Jan 6, 2021 at 7:03 PM Paul Moore <paul@paul-moore.com> wrote:
>
> On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > From: Daniel Colascione <dancol@google.com>
> >
> > This change uses the anon_inodes and LSM infrastructure introduced in
> > the previous patches to give SELinux the ability to control
> > anonymous-inode files that are created using the new
> > anon_inode_getfd_secure() function.
> >
> > 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 <dancol@google.com>
> > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > ---
> >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> >  security/selinux/include/classmap.h |  2 ++
> >  2 files changed, 58 insertions(+)
> >
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 6b1826fc3658..d092aa512868 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > +               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);
> > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > +                       return -EACCES;
> > +
> > +               isec->sclass = context_isec->sclass;
>
> Taking the object class directly from the context_inode is
> interesting, and I suspect problematic.  In the case below where no
> context_inode is supplied the object class is set to
> SECCLASS_ANON_INODE, which is correct, but when a context_inode is
> supplied there is no guarantee that the object class will be set to
> SECCLASS_ANON_INODE.  This could both pose a problem for policy
> writers (how do you distinguish the anon inode from other normal file
> inodes in this case?) as well as an outright fault later in this
> function when we try to check the ANON_INODE__CREATE on an object
> other than a SECCLASS_ANON_INODE object.
>
Thanks for catching this. I'll initialize 'sclass' unconditionally to
SECCLASS_ANON_INODE in the next version. Also, do you think I should
add a check that context_inode's sclass must be SECCLASS_ANON_INODE to
confirm that we never receive a regular inode as context_inode?

> It works in the userfaultfd case because the context_inode is
> originally created with this function so the object class is correctly
> set to SECCLASS_ANON_INODE, but can we always guarantee that to be the
> case?  Do we ever need or want to support using a context_inode that
> is not SECCLASS_ANON_INODE?
>

I don't think there is any requirement of supporting context_inode
which isn't anon-inode. And even if there is, as you described
earlier, for ANON_INODE__CREATE to work the sclass has to be
SECCLASS_ANON_INODE. I'll appreciate comments on this from others,
particularly Daniel and Stephen who originally discussed and
implemented this patch.


> > +               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,
> > +                           ANON_INODE__CREATE,
> > +                           &ad);
> > +}
>
> --
> paul moore
> www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-07  3:55     ` Lokesh Gidra
@ 2021-01-07 22:30       ` Paul Moore
  2021-01-07 22:40         ` Lokesh Gidra
  0 siblings, 1 reply; 19+ messages in thread
From: Paul Moore @ 2021-01-07 22:30 UTC (permalink / raw)
  To: Lokesh Gidra
  Cc: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov, Adrian Reber,
	Aleksa Sarai, Linux FS Devel, linux-kernel, LSM List,
	SElinux list, Kalesh Singh, Calin Juravle, Suren Baghdasaryan,
	Jeffrey Vander Stoep, Cc: Android Kernel,
	open list:MEMORY MANAGEMENT, Andrew Morton, hch

On Wed, Jan 6, 2021 at 10:55 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> On Wed, Jan 6, 2021 at 7:03 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > > From: Daniel Colascione <dancol@google.com>
> > >
> > > This change uses the anon_inodes and LSM infrastructure introduced in
> > > the previous patches to give SELinux the ability to control
> > > anonymous-inode files that are created using the new
> > > anon_inode_getfd_secure() function.
> > >
> > > 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 <dancol@google.com>
> > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > > ---
> > >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> > >  security/selinux/include/classmap.h |  2 ++
> > >  2 files changed, 58 insertions(+)
> > >
> > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > index 6b1826fc3658..d092aa512868 100644
> > > --- a/security/selinux/hooks.c
> > > +++ b/security/selinux/hooks.c
> > > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > > +               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);
> > > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > > +                       return -EACCES;
> > > +
> > > +               isec->sclass = context_isec->sclass;
> >
> > Taking the object class directly from the context_inode is
> > interesting, and I suspect problematic.  In the case below where no
> > context_inode is supplied the object class is set to
> > SECCLASS_ANON_INODE, which is correct, but when a context_inode is
> > supplied there is no guarantee that the object class will be set to
> > SECCLASS_ANON_INODE.  This could both pose a problem for policy
> > writers (how do you distinguish the anon inode from other normal file
> > inodes in this case?) as well as an outright fault later in this
> > function when we try to check the ANON_INODE__CREATE on an object
> > other than a SECCLASS_ANON_INODE object.
> >
> Thanks for catching this. I'll initialize 'sclass' unconditionally to
> SECCLASS_ANON_INODE in the next version. Also, do you think I should
> add a check that context_inode's sclass must be SECCLASS_ANON_INODE to
> confirm that we never receive a regular inode as context_inode?

This is one of the reasons why I was asking if you ever saw the need
to use a regular inode here.  It seems much safer to me to add a check
to ensure that context_inode is SECCLASS_ANON_INODE and return an
error otherwise; I would also suggest emitting an error using pr_err()
with something along the lines of "SELinux:  initializing anonymous
inode with inappropriate inode" (or something similar).

If something changes in the future we can always reconsider this restriction.

> > It works in the userfaultfd case because the context_inode is
> > originally created with this function so the object class is correctly
> > set to SECCLASS_ANON_INODE, but can we always guarantee that to be the
> > case?  Do we ever need or want to support using a context_inode that
> > is not SECCLASS_ANON_INODE?
>
> I don't think there is any requirement of supporting context_inode
> which isn't anon-inode. And even if there is, as you described
> earlier, for ANON_INODE__CREATE to work the sclass has to be
> SECCLASS_ANON_INODE. I'll appreciate comments on this from others,
> particularly Daniel and Stephen who originally discussed and
> implemented this patch.

I would encourage you not to wait too long for additional feedback
before sending the next revision.

-- 
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-07 22:30       ` Paul Moore
@ 2021-01-07 22:40         ` Lokesh Gidra
  0 siblings, 0 replies; 19+ messages in thread
From: Lokesh Gidra @ 2021-01-07 22:40 UTC (permalink / raw)
  To: Paul Moore
  Cc: Andrea Arcangeli, Alexander Viro, James Morris, Stephen Smalley,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov, Adrian Reber,
	Aleksa Sarai, Linux FS Devel, linux-kernel, LSM List,
	SElinux list, Kalesh Singh, Calin Juravle, Suren Baghdasaryan,
	Jeffrey Vander Stoep, Cc: Android Kernel,
	open list:MEMORY MANAGEMENT, Andrew Morton, hch

On Thu, Jan 7, 2021 at 2:30 PM Paul Moore <paul@paul-moore.com> wrote:
>
> On Wed, Jan 6, 2021 at 10:55 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > On Wed, Jan 6, 2021 at 7:03 PM Paul Moore <paul@paul-moore.com> wrote:
> > > On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > > > From: Daniel Colascione <dancol@google.com>
> > > >
> > > > This change uses the anon_inodes and LSM infrastructure introduced in
> > > > the previous patches to give SELinux the ability to control
> > > > anonymous-inode files that are created using the new
> > > > anon_inode_getfd_secure() function.
> > > >
> > > > 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 <dancol@google.com>
> > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > > > ---
> > > >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> > > >  security/selinux/include/classmap.h |  2 ++
> > > >  2 files changed, 58 insertions(+)
> > > >
> > > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > > index 6b1826fc3658..d092aa512868 100644
> > > > --- a/security/selinux/hooks.c
> > > > +++ b/security/selinux/hooks.c
> > > > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > > > +               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);
> > > > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > > > +                       return -EACCES;
> > > > +
> > > > +               isec->sclass = context_isec->sclass;
> > >
> > > Taking the object class directly from the context_inode is
> > > interesting, and I suspect problematic.  In the case below where no
> > > context_inode is supplied the object class is set to
> > > SECCLASS_ANON_INODE, which is correct, but when a context_inode is
> > > supplied there is no guarantee that the object class will be set to
> > > SECCLASS_ANON_INODE.  This could both pose a problem for policy
> > > writers (how do you distinguish the anon inode from other normal file
> > > inodes in this case?) as well as an outright fault later in this
> > > function when we try to check the ANON_INODE__CREATE on an object
> > > other than a SECCLASS_ANON_INODE object.
> > >
> > Thanks for catching this. I'll initialize 'sclass' unconditionally to
> > SECCLASS_ANON_INODE in the next version. Also, do you think I should
> > add a check that context_inode's sclass must be SECCLASS_ANON_INODE to
> > confirm that we never receive a regular inode as context_inode?
>
> This is one of the reasons why I was asking if you ever saw the need
> to use a regular inode here.  It seems much safer to me to add a check
> to ensure that context_inode is SECCLASS_ANON_INODE and return an
> error otherwise; I would also suggest emitting an error using pr_err()
> with something along the lines of "SELinux:  initializing anonymous
> inode with inappropriate inode" (or something similar).
>
Thanks. I'll do that.

> If something changes in the future we can always reconsider this restriction.
>
> > > It works in the userfaultfd case because the context_inode is
> > > originally created with this function so the object class is correctly
> > > set to SECCLASS_ANON_INODE, but can we always guarantee that to be the
> > > case?  Do we ever need or want to support using a context_inode that
> > > is not SECCLASS_ANON_INODE?
> >
> > I don't think there is any requirement of supporting context_inode
> > which isn't anon-inode. And even if there is, as you described
> > earlier, for ANON_INODE__CREATE to work the sclass has to be
> > SECCLASS_ANON_INODE. I'll appreciate comments on this from others,
> > particularly Daniel and Stephen who originally discussed and
> > implemented this patch.
>
> I would encourage you not to wait too long for additional feedback
> before sending the next revision.

Certainly. I'll send next version in a day or two.
>
> --
> paul moore
> www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-07  3:03   ` Paul Moore
  2021-01-07  3:55     ` Lokesh Gidra
@ 2021-01-08 19:35     ` Stephen Smalley
  2021-01-08 20:17       ` Lokesh Gidra
  2021-01-08 20:58       ` Paul Moore
  1 sibling, 2 replies; 19+ messages in thread
From: Stephen Smalley @ 2021-01-08 19:35 UTC (permalink / raw)
  To: Paul Moore
  Cc: Lokesh Gidra, Andrea Arcangeli, Alexander Viro, James Morris,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, Linux FS Devel,
	linux-kernel, LSM List, SElinux list, kaleshsingh, Calin Juravle,
	Suren Baghdasaryan, Jeffrey Vander Stoep, kernel-team, linux-mm,
	Andrew Morton, Christoph Hellwig, Daniel Colascione

On Wed, Jan 6, 2021 at 10:03 PM Paul Moore <paul@paul-moore.com> wrote:
>
> On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > From: Daniel Colascione <dancol@google.com>
> >
> > This change uses the anon_inodes and LSM infrastructure introduced in
> > the previous patches to give SELinux the ability to control
> > anonymous-inode files that are created using the new
> > anon_inode_getfd_secure() function.
> >
> > 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 <dancol@google.com>
> > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > ---
> >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> >  security/selinux/include/classmap.h |  2 ++
> >  2 files changed, 58 insertions(+)
> >
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 6b1826fc3658..d092aa512868 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > +               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);
> > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > +                       return -EACCES;
> > +
> > +               isec->sclass = context_isec->sclass;
>
> Taking the object class directly from the context_inode is
> interesting, and I suspect problematic.  In the case below where no
> context_inode is supplied the object class is set to
> SECCLASS_ANON_INODE, which is correct, but when a context_inode is
> supplied there is no guarantee that the object class will be set to
> SECCLASS_ANON_INODE.  This could both pose a problem for policy
> writers (how do you distinguish the anon inode from other normal file
> inodes in this case?) as well as an outright fault later in this
> function when we try to check the ANON_INODE__CREATE on an object
> other than a SECCLASS_ANON_INODE object.
>
> It works in the userfaultfd case because the context_inode is
> originally created with this function so the object class is correctly
> set to SECCLASS_ANON_INODE, but can we always guarantee that to be the
> case?  Do we ever need or want to support using a context_inode that
> is not SECCLASS_ANON_INODE?

Sorry, I haven't been following this.  IIRC, the original reason for
passing a context_inode was to support the /dev/kvm or similar use
cases where the driver is creating anonymous inodes to represent
specific objects/interfaces derived from the device node and we want
to be able to control subsequent ioctl operations on those anonymous
inodes in the same manner as for the device node.  For example, ioctl
operations on /dev/kvm can end up returning file descriptors for
anonymous inodes representing a specific VM or VCPU or similar.  If we
propagate the security class and SID from the /dev/kvm inode (the
context inode) to the new anonymous inode, we can write a single
policy rule over all ioctl operations related to /dev/kvm.  That's
also why we used the FILE__CREATE permission here originally; that was
also intentional.  All the file-related classes including anon_inode
inherit a common set of file permissions including create and thus we
often use the FILE__<permission> in common code when checking
permission against any potentially derived class.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-08 19:35     ` Stephen Smalley
@ 2021-01-08 20:17       ` Lokesh Gidra
  2021-01-08 21:23         ` Stephen Smalley
  2021-01-08 20:58       ` Paul Moore
  1 sibling, 1 reply; 19+ messages in thread
From: Lokesh Gidra @ 2021-01-08 20:17 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: Paul Moore, Andrea Arcangeli, Alexander Viro, James Morris,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, Linux FS Devel,
	linux-kernel, LSM List, SElinux list, Kalesh Singh,
	Calin Juravle, Suren Baghdasaryan, Jeffrey Vander Stoep,
	Cc: Android Kernel, open list:MEMORY MANAGEMENT, Andrew Morton,
	Christoph Hellwig, Daniel Colascione

On Fri, Jan 8, 2021 at 11:35 AM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
>
> On Wed, Jan 6, 2021 at 10:03 PM Paul Moore <paul@paul-moore.com> wrote:
> >
> > On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > > From: Daniel Colascione <dancol@google.com>
> > >
> > > This change uses the anon_inodes and LSM infrastructure introduced in
> > > the previous patches to give SELinux the ability to control
> > > anonymous-inode files that are created using the new
> > > anon_inode_getfd_secure() function.
> > >
> > > 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 <dancol@google.com>
> > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > > ---
> > >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> > >  security/selinux/include/classmap.h |  2 ++
> > >  2 files changed, 58 insertions(+)
> > >
> > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > index 6b1826fc3658..d092aa512868 100644
> > > --- a/security/selinux/hooks.c
> > > +++ b/security/selinux/hooks.c
> > > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > > +               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);
> > > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > > +                       return -EACCES;
Stephen, as per your explanation below, is this check also
problematic? I mean is it possible that /dev/kvm context_inode may not
have its label initialized? If so, then v12 of the patch series can be
used as is. Otherwise, I will send the next version which rollbacks
v14 and v13, except for this check. Kindly confirm.

> > > +
> > > +               isec->sclass = context_isec->sclass;
> >
> > Taking the object class directly from the context_inode is
> > interesting, and I suspect problematic.  In the case below where no
> > context_inode is supplied the object class is set to
> > SECCLASS_ANON_INODE, which is correct, but when a context_inode is
> > supplied there is no guarantee that the object class will be set to
> > SECCLASS_ANON_INODE.  This could both pose a problem for policy
> > writers (how do you distinguish the anon inode from other normal file
> > inodes in this case?) as well as an outright fault later in this
> > function when we try to check the ANON_INODE__CREATE on an object
> > other than a SECCLASS_ANON_INODE object.
> >
> > It works in the userfaultfd case because the context_inode is
> > originally created with this function so the object class is correctly
> > set to SECCLASS_ANON_INODE, but can we always guarantee that to be the
> > case?  Do we ever need or want to support using a context_inode that
> > is not SECCLASS_ANON_INODE?
>
> Sorry, I haven't been following this.  IIRC, the original reason for
> passing a context_inode was to support the /dev/kvm or similar use
> cases where the driver is creating anonymous inodes to represent
> specific objects/interfaces derived from the device node and we want
> to be able to control subsequent ioctl operations on those anonymous
> inodes in the same manner as for the device node.  For example, ioctl
> operations on /dev/kvm can end up returning file descriptors for
> anonymous inodes representing a specific VM or VCPU or similar.  If we
> propagate the security class and SID from the /dev/kvm inode (the
> context inode) to the new anonymous inode, we can write a single
> policy rule over all ioctl operations related to /dev/kvm.  That's
> also why we used the FILE__CREATE permission here originally; that was
> also intentional.  All the file-related classes including anon_inode
> inherit a common set of file permissions including create and thus we
> often use the FILE__<permission> in common code when checking
> permission against any potentially derived class.

Thanks a lot for the explanation.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-08 19:35     ` Stephen Smalley
  2021-01-08 20:17       ` Lokesh Gidra
@ 2021-01-08 20:58       ` Paul Moore
  1 sibling, 0 replies; 19+ messages in thread
From: Paul Moore @ 2021-01-08 20:58 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: Lokesh Gidra, Andrea Arcangeli, Alexander Viro, James Morris,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, Linux FS Devel,
	linux-kernel, LSM List, SElinux list, kaleshsingh, Calin Juravle,
	Suren Baghdasaryan, Jeffrey Vander Stoep, kernel-team, linux-mm,
	Andrew Morton, Christoph Hellwig, Daniel Colascione

On Fri, Jan 8, 2021 at 2:35 PM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
> On Wed, Jan 6, 2021 at 10:03 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > > From: Daniel Colascione <dancol@google.com>
> > >
> > > This change uses the anon_inodes and LSM infrastructure introduced in
> > > the previous patches to give SELinux the ability to control
> > > anonymous-inode files that are created using the new
> > > anon_inode_getfd_secure() function.
> > >
> > > 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 <dancol@google.com>
> > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > > ---
> > >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> > >  security/selinux/include/classmap.h |  2 ++
> > >  2 files changed, 58 insertions(+)
> > >
> > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > index 6b1826fc3658..d092aa512868 100644
> > > --- a/security/selinux/hooks.c
> > > +++ b/security/selinux/hooks.c
> > > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > > +               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);
> > > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > > +                       return -EACCES;
> > > +
> > > +               isec->sclass = context_isec->sclass;
> >
> > Taking the object class directly from the context_inode is
> > interesting, and I suspect problematic.  In the case below where no
> > context_inode is supplied the object class is set to
> > SECCLASS_ANON_INODE, which is correct, but when a context_inode is
> > supplied there is no guarantee that the object class will be set to
> > SECCLASS_ANON_INODE.  This could both pose a problem for policy
> > writers (how do you distinguish the anon inode from other normal file
> > inodes in this case?) as well as an outright fault later in this
> > function when we try to check the ANON_INODE__CREATE on an object
> > other than a SECCLASS_ANON_INODE object.
> >
> > It works in the userfaultfd case because the context_inode is
> > originally created with this function so the object class is correctly
> > set to SECCLASS_ANON_INODE, but can we always guarantee that to be the
> > case?  Do we ever need or want to support using a context_inode that
> > is not SECCLASS_ANON_INODE?
>
> Sorry, I haven't been following this.  IIRC, the original reason for
> passing a context_inode was to support the /dev/kvm or similar use
> cases where the driver is creating anonymous inodes to represent
> specific objects/interfaces derived from the device node and we want
> to be able to control subsequent ioctl operations on those anonymous
> inodes in the same manner as for the device node.  For example, ioctl
> operations on /dev/kvm can end up returning file descriptors for
> anonymous inodes representing a specific VM or VCPU or similar.  If we
> propagate the security class and SID from the /dev/kvm inode (the
> context inode) to the new anonymous inode, we can write a single
> policy rule over all ioctl operations related to /dev/kvm.

Thanks for the background, and the /dev/kvm example, that is what I was missing.

> That's
> also why we used the FILE__CREATE permission here originally; that was
> also intentional.  All the file-related classes including anon_inode
> inherit a common set of file permissions including create and thus we
> often use the FILE__<permission> in common code when checking
> permission against any potentially derived class.

Yes, if all of the anonymous inodes are not going to fall into the
anon_inode object class then FILE__CREATE makes the most sense.

Thanks Stephen.

-- 
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-08 20:17       ` Lokesh Gidra
@ 2021-01-08 21:23         ` Stephen Smalley
  2021-01-08 21:31           ` Lokesh Gidra
  0 siblings, 1 reply; 19+ messages in thread
From: Stephen Smalley @ 2021-01-08 21:23 UTC (permalink / raw)
  To: Lokesh Gidra
  Cc: Paul Moore, Andrea Arcangeli, Alexander Viro, James Morris,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, Linux FS Devel,
	linux-kernel, LSM List, SElinux list, Kalesh Singh,
	Calin Juravle, Suren Baghdasaryan, Jeffrey Vander Stoep,
	Cc: Android Kernel, open list:MEMORY MANAGEMENT, Andrew Morton,
	Christoph Hellwig, Daniel Colascione

On Fri, Jan 8, 2021 at 3:17 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
>
> On Fri, Jan 8, 2021 at 11:35 AM Stephen Smalley
> <stephen.smalley.work@gmail.com> wrote:
> >
> > On Wed, Jan 6, 2021 at 10:03 PM Paul Moore <paul@paul-moore.com> wrote:
> > >
> > > On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > > > From: Daniel Colascione <dancol@google.com>
> > > >
> > > > This change uses the anon_inodes and LSM infrastructure introduced in
> > > > the previous patches to give SELinux the ability to control
> > > > anonymous-inode files that are created using the new
> > > > anon_inode_getfd_secure() function.
> > > >
> > > > 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 <dancol@google.com>
> > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > > > ---
> > > >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> > > >  security/selinux/include/classmap.h |  2 ++
> > > >  2 files changed, 58 insertions(+)
> > > >
> > > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > > index 6b1826fc3658..d092aa512868 100644
> > > > --- a/security/selinux/hooks.c
> > > > +++ b/security/selinux/hooks.c
> > > > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > > > +               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);
> > > > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > > > +                       return -EACCES;
> Stephen, as per your explanation below, is this check also
> problematic? I mean is it possible that /dev/kvm context_inode may not
> have its label initialized? If so, then v12 of the patch series can be
> used as is. Otherwise, I will send the next version which rollbacks
> v14 and v13, except for this check. Kindly confirm.

The context_inode should always be initialized already.  I'm not fond
though of silently returning -EACCES here.  At the least we should
have a pr_err() or pr_warn() here.  In reality, this could only occur
in the case of a kernel bug or memory corruption so it used to be a
candidate for WARN_ON() or BUG_ON() or similar but I know that
BUG_ON() at least is frowned upon these days.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes
  2021-01-08 21:23         ` Stephen Smalley
@ 2021-01-08 21:31           ` Lokesh Gidra
  0 siblings, 0 replies; 19+ messages in thread
From: Lokesh Gidra @ 2021-01-08 21:31 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: Paul Moore, Andrea Arcangeli, Alexander Viro, James Morris,
	Casey Schaufler, Eric Biggers, Serge E. Hallyn, Eric Paris,
	Daniel Colascione, Kees Cook, Eric W. Biederman, KP Singh,
	David Howells, Anders Roxell, Sami Tolvanen, Matthew Garrett,
	Aaron Goidel, Randy Dunlap, Joel Fernandes (Google),
	YueHaibing, Christian Brauner, Alexei Starovoitov,
	Alexey Budankov, Adrian Reber, Aleksa Sarai, Linux FS Devel,
	linux-kernel, LSM List, SElinux list, Kalesh Singh,
	Calin Juravle, Suren Baghdasaryan, Jeffrey Vander Stoep,
	Cc: Android Kernel, open list:MEMORY MANAGEMENT, Andrew Morton,
	Christoph Hellwig, Daniel Colascione

On Fri, Jan 8, 2021 at 1:24 PM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
>
> On Fri, Jan 8, 2021 at 3:17 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> >
> > On Fri, Jan 8, 2021 at 11:35 AM Stephen Smalley
> > <stephen.smalley.work@gmail.com> wrote:
> > >
> > > On Wed, Jan 6, 2021 at 10:03 PM Paul Moore <paul@paul-moore.com> wrote:
> > > >
> > > > On Wed, Nov 11, 2020 at 8:54 PM Lokesh Gidra <lokeshgidra@google.com> wrote:
> > > > > From: Daniel Colascione <dancol@google.com>
> > > > >
> > > > > This change uses the anon_inodes and LSM infrastructure introduced in
> > > > > the previous patches to give SELinux the ability to control
> > > > > anonymous-inode files that are created using the new
> > > > > anon_inode_getfd_secure() function.
> > > > >
> > > > > 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 <dancol@google.com>
> > > > > Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
> > > > > ---
> > > > >  security/selinux/hooks.c            | 56 +++++++++++++++++++++++++++++
> > > > >  security/selinux/include/classmap.h |  2 ++
> > > > >  2 files changed, 58 insertions(+)
> > > > >
> > > > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > > > index 6b1826fc3658..d092aa512868 100644
> > > > > --- a/security/selinux/hooks.c
> > > > > +++ b/security/selinux/hooks.c
> > > > > @@ -2927,6 +2927,61 @@ 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_initialized(&selinux_state)))
> > > > > +               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);
> > > > > +               if (context_isec->initialized != LABEL_INITIALIZED)
> > > > > +                       return -EACCES;
> > Stephen, as per your explanation below, is this check also
> > problematic? I mean is it possible that /dev/kvm context_inode may not
> > have its label initialized? If so, then v12 of the patch series can be
> > used as is. Otherwise, I will send the next version which rollbacks
> > v14 and v13, except for this check. Kindly confirm.
>
> The context_inode should always be initialized already.  I'm not fond
> though of silently returning -EACCES here.  At the least we should
> have a pr_err() or pr_warn() here.  In reality, this could only occur
> in the case of a kernel bug or memory corruption so it used to be a
> candidate for WARN_ON() or BUG_ON() or similar but I know that
> BUG_ON() at least is frowned upon these days.

Got it. I'll add a pr_err(). Thanks a lot.

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2021-01-08 21:32 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-12  1:53 [PATCH v13 0/4] SELinux support for anonymous inodes and UFFD Lokesh Gidra
2020-11-12  1:53 ` [PATCH v13 1/4] security: add inode_init_security_anon() LSM hook Lokesh Gidra
2020-11-12  1:53 ` [PATCH v13 2/4] fs: add LSM-supporting anon-inode interface Lokesh Gidra
2021-01-07  2:09   ` Paul Moore
2021-01-07  2:42     ` dancol
2021-01-07  3:05       ` Paul Moore
2021-01-07  2:43     ` Lokesh Gidra
2021-01-07  3:08       ` Paul Moore
2020-11-12  1:53 ` [PATCH v13 3/4] selinux: teach SELinux about anonymous inodes Lokesh Gidra
2021-01-07  3:03   ` Paul Moore
2021-01-07  3:55     ` Lokesh Gidra
2021-01-07 22:30       ` Paul Moore
2021-01-07 22:40         ` Lokesh Gidra
2021-01-08 19:35     ` Stephen Smalley
2021-01-08 20:17       ` Lokesh Gidra
2021-01-08 21:23         ` Stephen Smalley
2021-01-08 21:31           ` Lokesh Gidra
2021-01-08 20:58       ` Paul Moore
2020-11-12  1:53 ` [PATCH v13 4/4] userfaultfd: use secure anon inodes for userfaultfd Lokesh Gidra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).