lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1456733847-17982-17-git-send-email-agruenba@redhat.com>
Date:	Mon, 29 Feb 2016 09:17:21 +0100
From:	Andreas Gruenbacher <agruenba@...hat.com>
To:	Alexander Viro <viro@...iv.linux.org.uk>
Cc:	"J. Bruce Fields" <bfields@...ldses.org>,
	linux-nfs@...r.kernel.org, "Theodore Ts'o" <tytso@....edu>,
	linux-cifs@...r.kernel.org, linux-api@...r.kernel.org,
	Trond Myklebust <trond.myklebust@...marydata.com>,
	linux-kernel@...r.kernel.org, xfs@....sgi.com,
	Christoph Hellwig <hch@...radead.org>,
	Andreas Dilger <adilger.kernel@...ger.ca>,
	linux-fsdevel@...r.kernel.org,
	Jeff Layton <jlayton@...chiereds.net>,
	linux-ext4@...r.kernel.org,
	Anna Schumaker <anna.schumaker@...app.com>
Subject: [PATCH v18 16/22] richacl: Create-time inheritance

When a new file is created, it can inherit an acl from its parent
directory; this is similar to how default acls work in POSIX ACLs.

As with POSIX ACLs, if a file inherits an acl from its parent directory,
the intersection between the create mode and the permissions granted by
the inherited acl determines the file masks and file permission bits,
and the umask is ignored.

Signed-off-by: Andreas Gruenbacher <agruenba@...hat.com>
---
 fs/richacl_base.c       | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
 fs/richacl_inode.c      | 70 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/richacl.h |  2 ++
 3 files changed, 153 insertions(+)

diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index 74e5cb5..58dffca 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -486,3 +486,84 @@ richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(richacl_equiv_mode);
+
+static inline bool
+ace_inherits_to_directory(const struct richace *ace)
+{
+	if (ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE)
+		return true;
+	if ((ace->e_flags & RICHACE_FILE_INHERIT_ACE) &&
+	    !(ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE))
+		return true;
+	return false;
+}
+
+/**
+ * richacl_inherit  -  compute the inherited acl of a new file
+ * @dir_acl:	acl of the containing directory
+ * @isdir:	inherit by a directory or non-directory?
+ *
+ * A directory can have acl entries which files and/or directories created
+ * inside the directory will inherit.  This function computes the acl for such
+ * a new file.  If there is no inheritable acl, it will return %NULL.
+ */
+struct richacl *
+richacl_inherit(const struct richacl *dir_acl, int isdir)
+{
+	const struct richace *dir_ace;
+	struct richacl *acl = NULL;
+	struct richace *ace;
+	int count = 0;
+
+	if (isdir) {
+		richacl_for_each_entry(dir_ace, dir_acl) {
+			if (!ace_inherits_to_directory(dir_ace))
+				continue;
+			count++;
+		}
+		if (!count)
+			return NULL;
+		acl = richacl_alloc(count, GFP_KERNEL);
+		if (!acl)
+			return ERR_PTR(-ENOMEM);
+		ace = acl->a_entries;
+		richacl_for_each_entry(dir_ace, dir_acl) {
+			if (!ace_inherits_to_directory(dir_ace))
+				continue;
+			richace_copy(ace, dir_ace);
+			if (dir_ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE)
+				ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
+			else if (dir_ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE)
+				ace->e_flags &= ~RICHACE_INHERIT_ONLY_ACE;
+			else
+				ace->e_flags |= RICHACE_INHERIT_ONLY_ACE;
+			ace++;
+		}
+	} else {
+		richacl_for_each_entry(dir_ace, dir_acl) {
+			if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
+				continue;
+			count++;
+		}
+		if (!count)
+			return NULL;
+		acl = richacl_alloc(count, GFP_KERNEL);
+		if (!acl)
+			return ERR_PTR(-ENOMEM);
+		ace = acl->a_entries;
+		richacl_for_each_entry(dir_ace, dir_acl) {
+			if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
+				continue;
+			richace_copy(ace, dir_ace);
+			ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS;
+			/*
+			 * RICHACE_DELETE_CHILD is meaningless for
+			 * non-directories, so clear it.
+			 */
+			ace->e_mask &= ~RICHACE_DELETE_CHILD;
+			ace++;
+		}
+	}
+
+	return acl;
+}
diff --git a/fs/richacl_inode.c b/fs/richacl_inode.c
index e329826..ec3d2c8 100644
--- a/fs/richacl_inode.c
+++ b/fs/richacl_inode.c
@@ -254,3 +254,73 @@ richacl_chmod(struct inode *inode, umode_t mode)
 	return retval;
 }
 EXPORT_SYMBOL(richacl_chmod);
+
+/*
+ * richacl_inherit_inode  -  compute inherited acl and file mode
+ * @dir_acl:	acl of the containing directory
+ * @mode_p:	mode of the new inode
+ *
+ * The file permission bits in @mode_p must be set to the create mode by the
+ * caller.
+ *
+ * If there is an inheritable acl, the maximum permissions that the acl grants
+ * are computed and the file masks of the new acl are set accordingly.
+ */
+static struct richacl *
+richacl_inherit_inode(const struct richacl *dir_acl, umode_t *mode_p)
+{
+	struct richacl *acl;
+	umode_t mode = *mode_p;
+
+	acl = richacl_inherit(dir_acl, S_ISDIR(mode));
+	if (acl) {
+		if (richacl_equiv_mode(acl, &mode) == 0) {
+			*mode_p &= mode;
+			richacl_put(acl);
+			acl = NULL;
+		} else {
+			richacl_compute_max_masks(acl);
+			/*
+			 * Ensure that the acl will not grant any permissions
+			 * beyond the create mode.
+			 */
+			acl->a_flags |= RICHACL_MASKED;
+			acl->a_owner_mask &=
+				richacl_mode_to_mask(mode >> 6);
+			acl->a_group_mask &=
+				richacl_mode_to_mask(mode >> 3);
+			acl->a_other_mask &=
+				richacl_mode_to_mask(mode);
+		}
+	} else
+		*mode_p &= ~current_umask();
+
+	return acl;
+}
+
+/**
+ * richacl_create  -  filesystem create helper
+ * @mode_p:	mode of the new inode
+ * @dir:	containing directory
+ *
+ * Compute the inherited acl for a new inode.  If there is no acl to inherit,
+ * apply the umask.  Use when creating a new inode on a richacl enabled file
+ * system.
+ */
+struct richacl *richacl_create(umode_t *mode_p, struct inode *dir)
+{
+	struct richacl *dir_acl, *acl = NULL;
+
+	if (S_ISLNK(*mode_p))
+		return NULL;
+	dir_acl = get_richacl(dir);
+	if (dir_acl) {
+		if (IS_ERR(dir_acl))
+			return dir_acl;
+		acl = richacl_inherit_inode(dir_acl, mode_p);
+		richacl_put(dir_acl);
+	} else
+		*mode_p &= ~current_umask();
+	return acl;
+}
+EXPORT_SYMBOL_GPL(richacl_create);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index b7128bf..c8fae91a 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -186,9 +186,11 @@ extern unsigned int richacl_want_to_mask(unsigned int);
 extern void richacl_compute_max_masks(struct richacl *);
 extern struct richacl *__richacl_chmod(struct richacl *, umode_t);
 extern int richacl_equiv_mode(const struct richacl *, umode_t *);
+extern struct richacl *richacl_inherit(const struct richacl *, int);
 
 /* richacl_inode.c */
 extern int richacl_permission(struct inode *, const struct richacl *, int);
 extern int richacl_chmod(struct inode *, umode_t);
+extern struct richacl *richacl_create(umode_t *, struct inode *);
 
 #endif /* __RICHACL_H */
-- 
2.4.3

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ