[PATCH v18 00/22] Richacls (Core and Ext4)

classic Classic list List threaded Threaded
59 messages Options
123
Reply | Threaded
Open this post in threaded view
|

[PATCH v18 09/22] richacl: Permission check algorithm

Andreas Gruenbacher-6
A richacl roughly grants a requested access if the NFSv4 acl in the
richacl grants the requested permissions according to the NFSv4
permission check algorithm and the file mask that applies to the process
includes the requested permissions.

Signed-off-by: Andreas Gruenbacher <[hidden email]>
Reviewed-by: "J. Bruce Fields" <[hidden email]>
---
 fs/Makefile             |   2 +-
 fs/richacl_inode.c      | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/richacl.h |   3 +
 3 files changed, 153 insertions(+), 1 deletion(-)
 create mode 100644 fs/richacl_inode.c

diff --git a/fs/Makefile b/fs/Makefile
index e5994c4..d5b45ca 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -49,7 +49,7 @@ obj-$(CONFIG_SYSCTL) += drop_caches.o
 
 obj-$(CONFIG_FHANDLE) += fhandle.o
 obj-$(CONFIG_FS_RICHACL) += richacl.o
-richacl-y := richacl_base.o
+richacl-y := richacl_base.o richacl_inode.o
 
 obj-y += quota/
 
diff --git a/fs/richacl_inode.c b/fs/richacl_inode.c
new file mode 100644
index 0000000..99b3c93
--- /dev/null
+++ b/fs/richacl_inode.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <[hidden email]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/richacl.h>
+
+/**
+ * richacl_permission  -  richacl permission check algorithm
+ * @inode: inode to check
+ * @acl: rich acl of the inode
+ * @want: requested access (MAY_* flags)
+ *
+ * Checks if the current process is granted @mask flags in @acl.
+ */
+int
+richacl_permission(struct inode *inode, const struct richacl *acl,
+   int want)
+{
+ const struct richace *ace;
+ unsigned int mask = richacl_want_to_mask(want);
+ unsigned int requested = mask, denied = 0;
+ int in_owning_group = in_group_p(inode->i_gid);
+ int in_owner_or_group_class = in_owning_group;
+
+ /*
+ * A process is
+ *   - in the owner file class if it owns the file,
+ *   - in the group file class if it is in the file's owning group or
+ *     it matches any of the user or group entries, and
+ *   - in the other file class otherwise.
+ * The file class is only relevant for determining which file mask to
+ * apply, which only happens for masked acls.
+ */
+ if (acl->a_flags & RICHACL_MASKED) {
+ if ((acl->a_flags & RICHACL_WRITE_THROUGH) &&
+    uid_eq(current_fsuid(), inode->i_uid)) {
+ denied = requested & ~acl->a_owner_mask;
+ goto out;
+ }
+ } else {
+ /*
+ * When the acl is not masked, there is no need to determine if
+ * the process is in the group class and we can break out
+ * earlier of the loop below.
+ */
+ in_owner_or_group_class = 1;
+ }
+
+ /*
+ * Check if the acl grants the requested access and determine which
+ * file class the process is in.
+ */
+ richacl_for_each_entry(ace, acl) {
+ unsigned int ace_mask = ace->e_mask;
+
+ if (richace_is_inherit_only(ace))
+ continue;
+ if (richace_is_owner(ace)) {
+ if (!uid_eq(current_fsuid(), inode->i_uid))
+ continue;
+ goto entry_matches_owner;
+ } else if (richace_is_group(ace)) {
+ if (!in_owning_group)
+ continue;
+ } else if (richace_is_unix_user(ace)) {
+ if (!uid_eq(current_fsuid(), ace->e_id.uid))
+ continue;
+ if (uid_eq(current_fsuid(), inode->i_uid))
+ goto entry_matches_owner;
+ } else if (richace_is_unix_group(ace)) {
+ if (!in_group_p(ace->e_id.gid))
+ continue;
+ } else
+ goto entry_matches_everyone;
+
+ /*
+ * Apply the group file mask to entries other than owner@ and
+ * everyone@ or user entries matching the owner.  This ensures
+ * that we grant the same permissions as the acl computed by
+ * richacl_apply_masks().
+ *
+ * Without this restriction, the following richacl would grant
+ * rw access to processes which are both the owner and in the
+ * owning group, but not to other users in the owning group,
+ * which could not be represented without masks:
+ *
+ *  owner:rw::mask
+ *  group@:rw::allow
+ */
+ if ((acl->a_flags & RICHACL_MASKED) && richace_is_allow(ace))
+ ace_mask &= acl->a_group_mask;
+
+entry_matches_owner:
+ /* The process is in the owner or group file class. */
+ in_owner_or_group_class = 1;
+
+entry_matches_everyone:
+ /* Check which mask flags the ACE allows or denies. */
+ if (richace_is_deny(ace))
+ denied |= ace_mask & mask;
+ mask &= ~ace_mask;
+
+ /*
+ * Keep going until we know which file class
+ * the process is in.
+ */
+ if (!mask && in_owner_or_group_class)
+ break;
+ }
+ denied |= mask;
+
+ if (acl->a_flags & RICHACL_MASKED) {
+ /*
+ * The file class a process is in determines which file mask
+ * applies.  Check if that file mask also grants the requested
+ * access.
+ */
+ if (uid_eq(current_fsuid(), inode->i_uid))
+ denied |= requested & ~acl->a_owner_mask;
+ else if (in_owner_or_group_class)
+ denied |= requested & ~acl->a_group_mask;
+ else {
+ if (acl->a_flags & RICHACL_WRITE_THROUGH)
+ denied = requested & ~acl->a_other_mask;
+ else
+ denied |= requested & ~acl->a_other_mask;
+ }
+ }
+
+out:
+ return denied ? -EACCES : 0;
+}
+EXPORT_SYMBOL_GPL(richacl_permission);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 3559b2c..1d9f5f7 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -180,4 +180,7 @@ extern unsigned int richacl_mode_to_mask(umode_t);
 extern unsigned int richacl_want_to_mask(unsigned int);
 extern void richacl_compute_max_masks(struct richacl *);
 
+/* richacl_inode.c */
+extern int richacl_permission(struct inode *, const struct richacl *, int);
+
 #endif /* __RICHACL_H */
--
2.4.3

Reply | Threaded
Open this post in threaded view
|

[PATCH v18 07/22] richacl: Permission mapping functions

Andreas Gruenbacher-6
In reply to this post by Andreas Gruenbacher-6
We need to map from POSIX permissions to NFSv4 permissions when a
chmod() is done, from NFSv4 permissions to POSIX permissions when an acl
is set (which implicitly sets the file permission bits), and from the
MAY_READ/MAY_WRITE/MAY_EXEC/MAY_APPEND flags to NFSv4 permissions when
doing an access check in a richacl.

Signed-off-by: Andreas Gruenbacher <[hidden email]>
Reviewed-by: J. Bruce Fields <[hidden email]>
---
 fs/richacl_base.c            | 118 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/richacl.h      |   3 ++
 include/uapi/linux/richacl.h |  44 ++++++++++++++++
 3 files changed, 165 insertions(+)

diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index c3ec928..a393001 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -65,3 +65,121 @@ richace_copy(struct richace *to, const struct richace *from)
 {
  memcpy(to, from, sizeof(struct richace));
 }
+
+/*
+ * richacl_mask_to_mode  -  compute the file permission bits from mask
+ * @mask: %RICHACE_* permission mask
+ *
+ * Compute the file permission bits corresponding to a particular set of
+ * richacl permissions.
+ *
+ * See richacl_masks_to_mode().
+ */
+static int
+richacl_mask_to_mode(unsigned int mask)
+{
+ int mode = 0;
+
+ if (mask & RICHACE_POSIX_MODE_READ)
+ mode |= S_IROTH;
+ if (mask & RICHACE_POSIX_MODE_WRITE)
+ mode |= S_IWOTH;
+ if (mask & RICHACE_POSIX_MODE_EXEC)
+ mode |= S_IXOTH;
+
+ return mode;
+}
+
+/**
+ * richacl_masks_to_mode  -  compute file permission bits from file masks
+ *
+ * When setting a richacl, we set the file permission bits to indicate maximum
+ * permissions: for example, we set the Write permission when a mask contains
+ * RICHACE_APPEND_DATA even if it does not also contain RICHACE_WRITE_DATA.
+ *
+ * Permissions which are not in RICHACE_POSIX_MODE_READ,
+ * RICHACE_POSIX_MODE_WRITE, or RICHACE_POSIX_MODE_EXEC cannot be represented
+ * in the file permission bits.  Such permissions can still be effective, but
+ * not for new files or after a chmod(); they must be explicitly enabled in the
+ * richacl.
+ */
+int
+richacl_masks_to_mode(const struct richacl *acl)
+{
+ return richacl_mask_to_mode(acl->a_owner_mask) << 6 |
+       richacl_mask_to_mode(acl->a_group_mask) << 3 |
+       richacl_mask_to_mode(acl->a_other_mask);
+}
+EXPORT_SYMBOL_GPL(richacl_masks_to_mode);
+
+/**
+ * richacl_mode_to_mask  - compute a file mask from the lowest three mode bits
+ * @mode: mode to convert to richacl permissions
+ *
+ * When the file permission bits of a file are set with chmod(), this specifies
+ * the maximum permissions that processes will get.  All permissions beyond
+ * that will be removed from the file masks, and become ineffective.
+ */
+unsigned int
+richacl_mode_to_mask(umode_t mode)
+{
+ unsigned int mask = 0;
+
+ if (mode & S_IROTH)
+ mask |= RICHACE_POSIX_MODE_READ;
+ if (mode & S_IWOTH)
+ mask |= RICHACE_POSIX_MODE_WRITE;
+ if (mode & S_IXOTH)
+ mask |= RICHACE_POSIX_MODE_EXEC;
+
+ return mask;
+}
+
+/**
+ * richacl_want_to_mask  - convert the iop->permission want argument to a mask
+ * @want: @want argument of the permission inode operation
+ *
+ * When checking for append, @want is (MAY_WRITE | MAY_APPEND).
+ *
+ * Richacls use the iop->may_create and iop->may_delete hooks which are used
+ * for checking if creating and deleting files is allowed.  These hooks do not
+ * use richacl_want_to_mask(), so we do not have to deal with mapping MAY_WRITE
+ * to RICHACE_ADD_FILE, RICHACE_ADD_SUBDIRECTORY, and RICHACE_DELETE_CHILD
+ * here.
+ */
+unsigned int
+richacl_want_to_mask(unsigned int want)
+{
+ unsigned int mask = 0;
+
+ if (want & MAY_READ)
+ mask |= RICHACE_READ_DATA;
+ if (want & MAY_DELETE_SELF)
+ mask |= RICHACE_DELETE;
+ if (want & MAY_TAKE_OWNERSHIP)
+ mask |= RICHACE_WRITE_OWNER;
+ if (want & MAY_CHMOD)
+ mask |= RICHACE_WRITE_ACL;
+ if (want & MAY_SET_TIMES)
+ mask |= RICHACE_WRITE_ATTRIBUTES;
+ if (want & MAY_EXEC)
+ mask |= RICHACE_EXECUTE;
+ /*
+ * differentiate MAY_WRITE from these request
+ */
+ if (want & (MAY_APPEND |
+    MAY_CREATE_FILE | MAY_CREATE_DIR |
+    MAY_DELETE_CHILD)) {
+ if (want & MAY_APPEND)
+ mask |= RICHACE_APPEND_DATA;
+ if (want & MAY_CREATE_FILE)
+ mask |= RICHACE_ADD_FILE;
+ if (want & MAY_CREATE_DIR)
+ mask |= RICHACE_ADD_SUBDIRECTORY;
+ if (want & MAY_DELETE_CHILD)
+ mask |= RICHACE_DELETE_CHILD;
+ } else if (want & MAY_WRITE)
+ mask |= RICHACE_WRITE_DATA;
+ return mask;
+}
+EXPORT_SYMBOL_GPL(richacl_want_to_mask);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index edb8480..9102ef0 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -175,5 +175,8 @@ richace_is_same_identifier(const struct richace *a, const struct richace *b)
 extern struct richacl *richacl_alloc(int, gfp_t);
 extern struct richacl *richacl_clone(const struct richacl *, gfp_t);
 extern void richace_copy(struct richace *, const struct richace *);
+extern int richacl_masks_to_mode(const struct richacl *);
+extern unsigned int richacl_mode_to_mask(umode_t);
+extern unsigned int richacl_want_to_mask(unsigned int);
 
 #endif /* __RICHACL_H */
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
index 08856f8..1ed48ac 100644
--- a/include/uapi/linux/richacl.h
+++ b/include/uapi/linux/richacl.h
@@ -96,4 +96,48 @@
  RICHACE_WRITE_OWNER | \
  RICHACE_SYNCHRONIZE )
 
+/*
+ * The POSIX permissions are supersets of the following richacl permissions:
+ *
+ *  - MAY_READ maps to READ_DATA or LIST_DIRECTORY, depending on the type
+ *    of the file system object.
+ *
+ *  - MAY_WRITE maps to WRITE_DATA or RICHACE_APPEND_DATA for files, and to
+ *    ADD_FILE, RICHACE_ADD_SUBDIRECTORY, or RICHACE_DELETE_CHILD for directories.
+ *
+ *  - MAY_EXECUTE maps to RICHACE_EXECUTE.
+ *
+ *  (Some of these richacl permissions have the same bit values.)
+ */
+#define RICHACE_POSIX_MODE_READ ( \
+ RICHACE_READ_DATA | \
+ RICHACE_LIST_DIRECTORY)
+#define RICHACE_POSIX_MODE_WRITE ( \
+ RICHACE_WRITE_DATA | \
+ RICHACE_ADD_FILE | \
+ RICHACE_APPEND_DATA | \
+ RICHACE_ADD_SUBDIRECTORY | \
+ RICHACE_DELETE_CHILD)
+#define RICHACE_POSIX_MODE_EXEC RICHACE_EXECUTE
+#define RICHACE_POSIX_MODE_ALL ( \
+ RICHACE_POSIX_MODE_READ | \
+ RICHACE_POSIX_MODE_WRITE | \
+ RICHACE_POSIX_MODE_EXEC)
+
+/*
+ * These permissions are always allowed no matter what the acl says.
+ */
+#define RICHACE_POSIX_ALWAYS_ALLOWED ( \
+ RICHACE_SYNCHRONIZE | \
+ RICHACE_READ_ATTRIBUTES | \
+ RICHACE_READ_ACL)
+
+/*
+ * The owner is implicitly granted these permissions under POSIX.
+ */
+#define RICHACE_POSIX_OWNER_ALLOWED ( \
+ RICHACE_WRITE_ATTRIBUTES | \
+ RICHACE_WRITE_OWNER | \
+ RICHACE_WRITE_ACL)
+
 #endif /* __UAPI_RICHACL_H */
--
2.4.3

Reply | Threaded
Open this post in threaded view
|

[PATCH v18 06/22] richacl: In-memory representation and helper functions

Andreas Gruenbacher-6
In reply to this post by Andreas Gruenbacher-6
A richacl consists of an NFSv4 acl and an owner, group, and other mask.
These three masks correspond to the owner, group, and other file
permission bits, but they contain NFSv4 permissions instead of POSIX
permissions.

Each entry in the NFSv4 acl applies to the file owner (OWNER@), the
owning group (GROUP@), everyone (EVERYONE@), or to a specific uid or
gid.

As in the standard POSIX file permission model, each process is the
owner, group, or other file class.  A richacl grants a requested access
only if the NFSv4 acl in the richacl grants the access (according to the
NFSv4 permission check algorithm), and the file mask that applies to the
process includes the requested permissions.

Signed-off-by: Andreas Gruenbacher <[hidden email]>
Reviewed-by: J. Bruce Fields <[hidden email]>
---
 fs/Makefile                  |   2 +
 fs/richacl_base.c            |  67 ++++++++++++++++
 include/linux/richacl.h      | 179 +++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/Kbuild    |   1 +
 include/uapi/linux/richacl.h |  99 ++++++++++++++++++++++++
 5 files changed, 348 insertions(+)
 create mode 100644 fs/richacl_base.c
 create mode 100644 include/linux/richacl.h
 create mode 100644 include/uapi/linux/richacl.h

diff --git a/fs/Makefile b/fs/Makefile
index 79f5225..e5994c4 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -48,6 +48,8 @@ obj-$(CONFIG_COREDUMP) += coredump.o
 obj-$(CONFIG_SYSCTL) += drop_caches.o
 
 obj-$(CONFIG_FHANDLE) += fhandle.o
+obj-$(CONFIG_FS_RICHACL) += richacl.o
+richacl-y := richacl_base.o
 
 obj-y += quota/
 
diff --git a/fs/richacl_base.c b/fs/richacl_base.c
new file mode 100644
index 0000000..c3ec928
--- /dev/null
+++ b/fs/richacl_base.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <[hidden email]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/richacl.h>
+
+MODULE_LICENSE("GPL");
+
+/**
+ * richacl_alloc  -  allocate a richacl
+ * @count: number of entries
+ */
+struct richacl *
+richacl_alloc(int count, gfp_t gfp)
+{
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
+ struct richacl *acl = kzalloc(size, gfp);
+
+ if (acl) {
+ atomic_set(&acl->a_refcount, 1);
+ acl->a_count = count;
+ }
+ return acl;
+}
+EXPORT_SYMBOL_GPL(richacl_alloc);
+
+/**
+ * richacl_clone  -  create a copy of a richacl
+ */
+struct richacl *
+richacl_clone(const struct richacl *acl, gfp_t gfp)
+{
+ int count = acl->a_count;
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
+ struct richacl *dup = kmalloc(size, gfp);
+
+ if (dup) {
+ memcpy(dup, acl, size);
+ atomic_set(&dup->a_refcount, 1);
+ }
+ return dup;
+}
+
+/**
+ * richace_copy  -  copy an acl entry
+ */
+void
+richace_copy(struct richace *to, const struct richace *from)
+{
+ memcpy(to, from, sizeof(struct richace));
+}
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
new file mode 100644
index 0000000..edb8480
--- /dev/null
+++ b/include/linux/richacl.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <[hidden email]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __RICHACL_H
+#define __RICHACL_H
+
+#include <uapi/linux/richacl.h>
+
+struct richace {
+ unsigned short e_type;
+ unsigned short e_flags;
+ unsigned int e_mask;
+ union {
+ kuid_t uid;
+ kgid_t gid;
+ unsigned int special;
+ } e_id;
+};
+
+struct richacl {
+ atomic_t a_refcount;
+ unsigned int a_owner_mask;
+ unsigned int a_group_mask;
+ unsigned int a_other_mask;
+ unsigned short a_count;
+ unsigned short a_flags;
+ struct richace a_entries[0];
+};
+
+#define richacl_for_each_entry(_ace, _acl) \
+ for (_ace = (_acl)->a_entries; \
+     _ace != (_acl)->a_entries + (_acl)->a_count; \
+     _ace++)
+
+#define richacl_for_each_entry_reverse(_ace, _acl) \
+ for (_ace = (_acl)->a_entries + (_acl)->a_count - 1; \
+     _ace != (_acl)->a_entries - 1; \
+     _ace--)
+
+/**
+ * richacl_get  -  grab another reference to a richacl handle
+ */
+static inline struct richacl *
+richacl_get(struct richacl *acl)
+{
+ if (acl)
+ atomic_inc(&acl->a_refcount);
+ return acl;
+}
+
+/**
+ * richacl_put  -  free a richacl handle
+ */
+static inline void
+richacl_put(struct richacl *acl)
+{
+ if (acl && atomic_dec_and_test(&acl->a_refcount))
+ kfree(acl);
+}
+
+/**
+ * richace_is_owner  -  check if @ace is an OWNER@ entry
+ */
+static inline bool
+richace_is_owner(const struct richace *ace)
+{
+ return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
+       ace->e_id.special == RICHACE_OWNER_SPECIAL_ID;
+}
+
+/**
+ * richace_is_group  -  check if @ace is a GROUP@ entry
+ */
+static inline bool
+richace_is_group(const struct richace *ace)
+{
+ return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
+       ace->e_id.special == RICHACE_GROUP_SPECIAL_ID;
+}
+
+/**
+ * richace_is_everyone  -  check if @ace is an EVERYONE@ entry
+ */
+static inline bool
+richace_is_everyone(const struct richace *ace)
+{
+ return (ace->e_flags & RICHACE_SPECIAL_WHO) &&
+       ace->e_id.special == RICHACE_EVERYONE_SPECIAL_ID;
+}
+
+/**
+ * richace_is_unix_user  -  check if @ace applies to a specific user
+ */
+static inline bool
+richace_is_unix_user(const struct richace *ace)
+{
+ return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
+       !(ace->e_flags & RICHACE_IDENTIFIER_GROUP);
+}
+
+/**
+ * richace_is_unix_group  -  check if @ace applies to a specific group
+ */
+static inline bool
+richace_is_unix_group(const struct richace *ace)
+{
+ return !(ace->e_flags & RICHACE_SPECIAL_WHO) &&
+       (ace->e_flags & RICHACE_IDENTIFIER_GROUP);
+}
+
+/**
+ * richace_is_inherit_only  -  check if @ace is for inheritance only
+ *
+ * ACEs with the %RICHACE_INHERIT_ONLY_ACE flag set have no effect during
+ * permission checking.
+ */
+static inline bool
+richace_is_inherit_only(const struct richace *ace)
+{
+ return ace->e_flags & RICHACE_INHERIT_ONLY_ACE;
+}
+
+/**
+ * richace_is_inheritable  -  check if @ace is inheritable
+ */
+static inline bool
+richace_is_inheritable(const struct richace *ace)
+{
+ return ace->e_flags & (RICHACE_FILE_INHERIT_ACE |
+       RICHACE_DIRECTORY_INHERIT_ACE);
+}
+
+/**
+ * richace_is_allow  -  check if @ace is an %ALLOW type entry
+ */
+static inline bool
+richace_is_allow(const struct richace *ace)
+{
+ return ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+}
+
+/**
+ * richace_is_deny  -  check if @ace is a %DENY type entry
+ */
+static inline bool
+richace_is_deny(const struct richace *ace)
+{
+ return ace->e_type == RICHACE_ACCESS_DENIED_ACE_TYPE;
+}
+
+/**
+ * richace_is_same_identifier  -  are both identifiers the same?
+ */
+static inline bool
+richace_is_same_identifier(const struct richace *a, const struct richace *b)
+{
+ return !((a->e_flags ^ b->e_flags) &
+ (RICHACE_SPECIAL_WHO | RICHACE_IDENTIFIER_GROUP)) &&
+       !memcmp(&a->e_id, &b->e_id, sizeof(a->e_id));
+}
+
+extern struct richacl *richacl_alloc(int, gfp_t);
+extern struct richacl *richacl_clone(const struct richacl *, gfp_t);
+extern void richace_copy(struct richace *, const struct richace *);
+
+#endif /* __RICHACL_H */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index ebd10e6..6e05dc8 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -351,6 +351,7 @@ header-y += reboot.h
 header-y += reiserfs_fs.h
 header-y += reiserfs_xattr.h
 header-y += resource.h
+header-y += richacl.h
 header-y += rfkill.h
 header-y += romfs_fs.h
 header-y += rose.h
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
new file mode 100644
index 0000000..08856f8
--- /dev/null
+++ b/include/uapi/linux/richacl.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher <[hidden email]>
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __UAPI_RICHACL_H
+#define __UAPI_RICHACL_H
+
+/* a_flags values */
+#define RICHACL_WRITE_THROUGH 0x40
+#define RICHACL_MASKED 0x80
+
+/* e_type values */
+#define RICHACE_ACCESS_ALLOWED_ACE_TYPE 0x0000
+#define RICHACE_ACCESS_DENIED_ACE_TYPE 0x0001
+
+/* e_flags bitflags */
+#define RICHACE_FILE_INHERIT_ACE 0x0001
+#define RICHACE_DIRECTORY_INHERIT_ACE 0x0002
+#define RICHACE_NO_PROPAGATE_INHERIT_ACE 0x0004
+#define RICHACE_INHERIT_ONLY_ACE 0x0008
+#define RICHACE_IDENTIFIER_GROUP 0x0040
+#define RICHACE_SPECIAL_WHO 0x4000
+
+/* e_mask bitflags */
+#define RICHACE_READ_DATA 0x00000001
+#define RICHACE_LIST_DIRECTORY 0x00000001
+#define RICHACE_WRITE_DATA 0x00000002
+#define RICHACE_ADD_FILE 0x00000002
+#define RICHACE_APPEND_DATA 0x00000004
+#define RICHACE_ADD_SUBDIRECTORY 0x00000004
+#define RICHACE_READ_NAMED_ATTRS 0x00000008
+#define RICHACE_WRITE_NAMED_ATTRS 0x00000010
+#define RICHACE_EXECUTE 0x00000020
+#define RICHACE_DELETE_CHILD 0x00000040
+#define RICHACE_READ_ATTRIBUTES 0x00000080
+#define RICHACE_WRITE_ATTRIBUTES 0x00000100
+#define RICHACE_WRITE_RETENTION 0x00000200
+#define RICHACE_WRITE_RETENTION_HOLD 0x00000400
+#define RICHACE_DELETE 0x00010000
+#define RICHACE_READ_ACL 0x00020000
+#define RICHACE_WRITE_ACL 0x00040000
+#define RICHACE_WRITE_OWNER 0x00080000
+#define RICHACE_SYNCHRONIZE 0x00100000
+
+/* e_id values */
+#define RICHACE_OWNER_SPECIAL_ID 0
+#define RICHACE_GROUP_SPECIAL_ID 1
+#define RICHACE_EVERYONE_SPECIAL_ID 2
+
+#define RICHACL_VALID_FLAGS ( \
+ RICHACL_WRITE_THROUGH | \
+ RICHACL_MASKED )
+
+#define RICHACE_VALID_FLAGS ( \
+ RICHACE_FILE_INHERIT_ACE | \
+ RICHACE_DIRECTORY_INHERIT_ACE | \
+ RICHACE_NO_PROPAGATE_INHERIT_ACE | \
+ RICHACE_INHERIT_ONLY_ACE | \
+ RICHACE_IDENTIFIER_GROUP | \
+ RICHACE_SPECIAL_WHO )
+
+#define RICHACE_INHERITANCE_FLAGS ( \
+ RICHACE_FILE_INHERIT_ACE | \
+ RICHACE_DIRECTORY_INHERIT_ACE | \
+ RICHACE_NO_PROPAGATE_INHERIT_ACE | \
+ RICHACE_INHERIT_ONLY_ACE )
+
+/* Valid RICHACE_* flags for directories and non-directories */
+#define RICHACE_VALID_MASK ( \
+ RICHACE_READ_DATA | RICHACE_LIST_DIRECTORY | \
+ RICHACE_WRITE_DATA | RICHACE_ADD_FILE | \
+ RICHACE_APPEND_DATA | RICHACE_ADD_SUBDIRECTORY | \
+ RICHACE_READ_NAMED_ATTRS | \
+ RICHACE_WRITE_NAMED_ATTRS | \
+ RICHACE_EXECUTE | \
+ RICHACE_DELETE_CHILD | \
+ RICHACE_READ_ATTRIBUTES | \
+ RICHACE_WRITE_ATTRIBUTES | \
+ RICHACE_WRITE_RETENTION | \
+ RICHACE_WRITE_RETENTION_HOLD | \
+ RICHACE_DELETE | \
+ RICHACE_READ_ACL | \
+ RICHACE_WRITE_ACL | \
+ RICHACE_WRITE_OWNER | \
+ RICHACE_SYNCHRONIZE )
+
+#endif /* __UAPI_RICHACL_H */
--
2.4.3

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 00/22] Richacls (Core and Ext4)

Christoph Hellwig
In reply to this post by Andreas Gruenbacher-6
On Mon, Feb 29, 2016 at 09:17:05AM +0100, Andreas Gruenbacher wrote:
> Al,
>
> could you please make sure you are happy with the current version of the
> richacl patch queue for the next merge window?

I'm still not happy.

For one I still see no reason to merge this broken ACL model at all.
It provides our actualy Linux users no benefit at all, while breaking
a lot of assumptions, especially by adding allow and deny ACE at the
same sime.

It also doesn't help with the issue that the main thing it's trying
to be compatible with (Windows) actually uses a fundamentally different
identifier to apply the ACLs to - as long as you're still limited
to users and groups and not guids we'll still have that mapping problem
anyway.

But besides that fundamental question on the purpose of it I also
don't think the code is suitable, more in the individual patches.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 10/22] posix_acl: Unexport acl_by_type and make it static

Christoph Hellwig
In reply to this post by Andreas Gruenbacher-6
Looks fine,

Reviewed-by: Christoph Hellwig <[hidden email]>
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 11/22] vfs: Cache base_acl objects in inodes

Christoph Hellwig
In reply to this post by Andreas Gruenbacher-6
On Mon, Feb 29, 2016 at 09:17:16AM +0100, Andreas Gruenbacher wrote:
> POSIX ACLs and richacls are both objects allocated by kmalloc() with a
> reference count which are freed by kfree_rcu().  An inode can either
> cache an access and a default POSIX ACL, or a richacl (richacls do not
> have default acls).  To allow an inode to cache either of the two kinds
> of acls, introduce a new base_acl type and convert i_acl and
> i_default_acl to that type. In most cases, the vfs then doesn't care which
> kind of acl an inode caches (if any).

This base_acl object is pointless.  I've asked in the past to have
a proper container for the ACLs in common code, but a union
of a refcount and a rcu head doesn't really fit that category.

But this points out that the f2fs folks really need a couple of
slaps on their hands.  Not if generic funtionality doesn't
fit your needs you are not going to blindly copy and paste it,
please talk to find a solution instead of duplicating it.

Folks, please come up with a suggestion to get rid of f2fs_acl_clone,
f2fs_acl_create_masq and f2fs_acl_create ASAP.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 00/22] Richacls (Core and Ext4)

J. Bruce Fields
In reply to this post by Christoph Hellwig
On Fri, Mar 11, 2016 at 06:01:34AM -0800, Christoph Hellwig wrote:

> On Mon, Feb 29, 2016 at 09:17:05AM +0100, Andreas Gruenbacher wrote:
> > Al,
> >
> > could you please make sure you are happy with the current version of the
> > richacl patch queue for the next merge window?
>
> I'm still not happy.
>
> For one I still see no reason to merge this broken ACL model at all.
> It provides our actualy Linux users no benefit at all, while breaking
> a lot of assumptions, especially by adding allow and deny ACE at the
> same sime.

Could you explain what you mean by "adding allow and deny ACE at the
same time"?

> It also doesn't help with the issue that the main thing it's trying
> to be compatible with (Windows) actually uses a fundamentally different
> identifier to apply the ACLs to - as long as you're still limited
> to users and groups and not guids we'll still have that mapping problem
> anyway.

Agreed, but, one step at a time?  My impression is that the Samba people
still consider this a step forward for Linux compatibility.

--b.

>
> But besides that fundamental question on the purpose of it I also
> don't think the code is suitable, more in the individual patches.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 09/22] richacl: Permission check algorithm

Christoph Hellwig
In reply to this post by Andreas Gruenbacher-6
>  fs/Makefile             |   2 +-
>  fs/richacl_inode.c      | 149 ++++++++++++++++++++++++++++++++++++++++++++++++

What's the point of a tiny separate file here?  All richacls files
together are still small, and it would be much preferably to have all
that code together.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 18/22] richacl: xattr mapping functions

Christoph Hellwig
In reply to this post by Andreas Gruenbacher-6
> +#include <linux/richacl_xattr.h>
> +
> +MODULE_LICENSE("GPL");

what's the point given that the code isn't even modolar?

> +static void
> +fix_xattr_from_user(const char *kname, void *kvalue, size_t size)
> +{
> + if (strncmp(kname, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
> + return;
> + kname += XATTR_SYSTEM_PREFIX_LEN;
> + if (!strcmp(kname, XATTR_POSIX_ACL_ACCESS) ||
> +    !strcmp(kname, XATTR_POSIX_ACL_DEFAULT))
> + posix_acl_fix_xattr_from_user(kvalue, size);
> +}
>  
>  /*
>   * Extended attribute SET operations
> @@ -329,9 +339,7 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
>   error = -EFAULT;
>   goto out;
>   }
> - if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
> -    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
> - posix_acl_fix_xattr_from_user(kvalue, size);
> + fix_xattr_from_user(kname, kvalue, size);
>   }
>  
>   error = vfs_setxattr(d, kname, kvalue, size, flags);
> @@ -396,6 +404,17 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
>   return error;
>  }
>  
> +static void
> +fix_xattr_to_user(const char *kname, void *kvalue, size_t size)
> +{
> + if (strncmp(kname, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
> + return;
> + kname += XATTR_SYSTEM_PREFIX_LEN;
> + if (!strcmp(kname, XATTR_POSIX_ACL_ACCESS) ||
> +    !strcmp(kname, XATTR_POSIX_ACL_DEFAULT))
> + posix_acl_fix_xattr_to_user(kvalue, size);
> +}
> +
>  /*
>   * Extended attribute GET operations
>   */
> @@ -426,9 +445,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
>  
>   error = vfs_getxattr(d, kname, kvalue, size);
>   if (error > 0) {
> - if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
> -    (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
> - posix_acl_fix_xattr_to_user(kvalue, size);
> + fix_xattr_to_user(kname, kvalue, size);

I don't see how this is related to the rest of the patch.

> +++ b/include/linux/richacl_xattr.h

What's the point in splitting this from the richacl.h header?

Same for the uapi versions.

> +struct richacl_xattr {
> + unsigned char a_version;
> + unsigned char a_flags;

Explicit __u8 for uapi headers, please.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 19/22] richacl: Add richacl xattr handler

Christoph Hellwig
In reply to this post by Andreas Gruenbacher-6
On Mon, Feb 29, 2016 at 09:17:24AM +0100, Andreas Gruenbacher wrote:
> Add richacl xattr handler implementing the xattr operations based on the
> get_richacl and set_richacl inode operations.

Given all the issues with Posix ACLs and selinux attributes these really
should be proper syscalls instead of abusing the xattr interface.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 19/22] richacl: Add richacl xattr handler

J. Bruce Fields
On Fri, Mar 11, 2016 at 06:17:35AM -0800, Christoph Hellwig wrote:
> On Mon, Feb 29, 2016 at 09:17:24AM +0100, Andreas Gruenbacher wrote:
> > Add richacl xattr handler implementing the xattr operations based on the
> > get_richacl and set_richacl inode operations.
>
> Given all the issues with Posix ACLs and selinux attributes these really
> should be proper syscalls instead of abusing the xattr interface.

What are those problems exactly?

--b.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 21/22] ext4: Add richacl support

Christoph Hellwig
In reply to this post by Andreas Gruenbacher-6
> +static inline int
> +ext4_acl_chmod(struct inode *inode, umode_t mode)
> +{
> + if (IS_RICHACL(inode))
> + return richacl_chmod(inode, inode->i_mode);
> + return posix_acl_chmod(inode, inode->i_mode);
> +}

Thi isn't ext4-specific and potentially duplicated in every caller.
Please provide this as a common helper.

Also while we're at it, the mode argument is ignore and the function
always uses inode->i_mode instead.

> +ext4_get_richacl(struct inode *inode)
> +{
> + const int name_index = EXT4_XATTR_INDEX_RICHACL;
> + void *value = NULL;
> + struct richacl *acl = NULL;
> + int retval;
> +
> + retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
> + if (retval > 0) {
> + value = kmalloc(retval, GFP_NOFS);
> + if (!value)
> + return ERR_PTR(-ENOMEM);
> + retval = ext4_xattr_get(inode, name_index, "", value, retval);
> + }
> + if (retval > 0) {
> + acl = richacl_from_xattr(&init_user_ns, value, retval);
> + if (acl == ERR_PTR(-EINVAL))
> + acl = ERR_PTR(-EIO);

Shouldn't richacl_from_xattr return the error pointer that ->get_richacl
callers expect?

> +static int
> +__ext4_set_richacl(handle_t *handle, struct inode *inode, struct richacl *acl)
> +{
> + const int name_index = EXT4_XATTR_INDEX_RICHACL;
> + umode_t mode = inode->i_mode;
> + int retval, size;
> + void *value;
> +
> + if (richacl_equiv_mode(acl, &mode) == 0) {
> + inode->i_ctime = ext4_current_time(inode);
> + inode->i_mode = mode;
> + ext4_mark_inode_dirty(handle, inode);
> + return __ext4_remove_richacl(handle, inode);
> + }

Should this check for a NULL acl instead of special casing that
in ext4_set_richacl?

> +int
> +ext4_init_richacl(handle_t *handle, struct inode *inode, struct inode *dir)
> +{
> + struct richacl *acl = richacl_create(&inode->i_mode, dir);
> + int error;
> +
> + error = PTR_ERR(acl);
> + if (IS_ERR(acl))
> + return error;

        if (IS_ERR(acl))
                return PTR_ERR(acl);

> + if (acl) {
> + error = __ext4_set_richacl(handle, inode, acl);
> + richacl_put(acl);
> + }

Shouldn't richacl_create return NULL if the ACL is equivalent to the
mode bits instead of letting every filesystem figure that out on it's
own?

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 00/22] Richacls (Core and Ext4)

Andreas Gruenbacher-6
In reply to this post by Christoph Hellwig
On Fri, Mar 11, 2016 at 3:01 PM, Christoph Hellwig <[hidden email]> wrote:

> On Mon, Feb 29, 2016 at 09:17:05AM +0100, Andreas Gruenbacher wrote:
>> Al,
>>
>> could you please make sure you are happy with the current version of the
>> richacl patch queue for the next merge window?
>
> I'm still not happy.
>
> For one I still see no reason to merge this broken ACL model at all.
> It provides our actualy Linux users no benefit at all,

This permission model is useful in mixed environments that involve
UNIX and Windows machines. Think of NAS boxes with Linux and Windows
clients, for example. It also fits the NFSv4 ACL model very well. If
you're not a user dealing with such environments, then the model
likely won't provide any benefits to *you*, and you're better off with
a less complicated permission model. That doesn't say anything about
other users, though.

> while breaking a lot of assumptions,

The model is designed specifically to be compliant with the POSIX
permission model. What assumptions are you talking about?

> especially by adding allow and deny ACE at the same time.

I remember from past discussions that a permission model like the
POSIX ACL model that doesn't have DENY ACEs would be more to your
liking. This argument is dead from the start though: NFSv4 ACLs
without DENY ACEs cannot represent basic file permissions like 0604
where the owning group has fewer permissions than others, for example
(see the richaclex(7) man page). We would end up with a permission
model that isn't even compatible with the traditional POSIX file
permission model, one which nobody else implements or cares about.

> It also doesn't help with the issue that the main thing it's trying
> to be compatible with (Windows) actually uses a fundamentally different
> identifier to apply the ACLs to - as long as you're still limited
> to users and groups and not guids we'll still have that mapping problem
> anyway.

Samba has been dealing with mapping between SIDs and UIDs/GIDs for a
long time, and it's working acceptably well.

We could store SIDs in ACEs, but that wouldn't make the actual
problems go away: Files on Linux have an owner and an owning group
which are identitifed by UID/GID, whereas a file is owned by a SID
which can be either a user or a group in a SID world. Also, processes
on Linux have an owner and a list of groups which are identified by
UID/GID, so any SIDs stored in filesystems would never match a
process, anyway.

(NFSv4 refers to users and groups as opposed to SIDs, and so it
doesn't have this problem.)

Thanks,
Andreas
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 11/22] vfs: Cache base_acl objects in inodes

Andreas Gruenbacher-6
In reply to this post by Christoph Hellwig
On Fri, Mar 11, 2016 at 3:07 PM, Christoph Hellwig <[hidden email]> wrote:

> On Mon, Feb 29, 2016 at 09:17:16AM +0100, Andreas Gruenbacher wrote:
>> POSIX ACLs and richacls are both objects allocated by kmalloc() with a
>> reference count which are freed by kfree_rcu().  An inode can either
>> cache an access and a default POSIX ACL, or a richacl (richacls do not
>> have default acls).  To allow an inode to cache either of the two kinds
>> of acls, introduce a new base_acl type and convert i_acl and
>> i_default_acl to that type. In most cases, the vfs then doesn't care which
>> kind of acl an inode caches (if any).
>
> This base_acl object is pointless.  I've asked in the past to have
> a proper container for the ACLs in common code, but a union
> of a refcount and a rcu head doesn't really fit that category.

POSIX ACLs and RichACLs are different objects, with different members
and different algorithms operating on them. The only commonality is
that they are both kmalloc()ed, reference counted objects, and when an
inode is destroyed, both kinds of ACLs can be put in the same way,
avoiding an unnecessary if. What kind of common-code container beyond
that are you still dreaming about?

Thanks,
Andreas
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 18/22] richacl: xattr mapping functions

Andreas Gruenbacher-6
In reply to this post by Christoph Hellwig
On Fri, Mar 11, 2016 at 3:17 PM, Christoph Hellwig <[hidden email]> wrote:
>> +#include <linux/richacl_xattr.h>
>> +
>> +MODULE_LICENSE("GPL");
>
> what's the point given that the code isn't even modolar?

A leftover, removed now.

>> +static void
>> +fix_xattr_from_user(const char *kname, void *kvalue, size_t size)
>> +{
>> +     if (strncmp(kname, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
>> +             return;
>> +     kname += XATTR_SYSTEM_PREFIX_LEN;
>> +     if (!strcmp(kname, XATTR_POSIX_ACL_ACCESS) ||
>> +         !strcmp(kname, XATTR_POSIX_ACL_DEFAULT))
>> +             posix_acl_fix_xattr_from_user(kvalue, size);
>> +}
>>
>>  /*
>>   * Extended attribute SET operations
>> @@ -329,9 +339,7 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
>>                       error = -EFAULT;
>>                       goto out;
>>               }
>> -             if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
>> -                 (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
>> -                     posix_acl_fix_xattr_from_user(kvalue, size);
>> +             fix_xattr_from_user(kname, kvalue, size);
>>       }
>>
>>       error = vfs_setxattr(d, kname, kvalue, size, flags);
>> @@ -396,6 +404,17 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
>>       return error;
>>  }
>>
>> +static void
>> +fix_xattr_to_user(const char *kname, void *kvalue, size_t size)
>> +{
>> +     if (strncmp(kname, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
>> +             return;
>> +     kname += XATTR_SYSTEM_PREFIX_LEN;
>> +     if (!strcmp(kname, XATTR_POSIX_ACL_ACCESS) ||
>> +         !strcmp(kname, XATTR_POSIX_ACL_DEFAULT))
>> +             posix_acl_fix_xattr_to_user(kvalue, size);
>> +}
>> +
>>  /*
>>   * Extended attribute GET operations
>>   */
>> @@ -426,9 +445,7 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
>>
>>       error = vfs_getxattr(d, kname, kvalue, size);
>>       if (error > 0) {
>> -             if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
>> -                 (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
>> -                     posix_acl_fix_xattr_to_user(kvalue, size);
>> +             fix_xattr_to_user(kname, kvalue, size);
>
> I don't see how this is related to the rest of the patch.

Indeed, this is unrelated now. I'll split it off.

>> +++ b/include/linux/richacl_xattr.h
>
> What's the point in splitting this from the richacl.h header?
>
> Same for the uapi versions.
>
>> +struct richacl_xattr {
>> +     unsigned char   a_version;
>> +     unsigned char   a_flags;
>
> Explicit __u8 for uapi headers, please.

Okay.

Thanks,
Andreas
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 00/22] Richacls (Core and Ext4)

Steve French-2
In reply to this post by Andreas Gruenbacher-6
On Fri, Mar 11, 2016 at 10:11 AM, Andreas Gruenbacher
<[hidden email]> wrote:

> On Fri, Mar 11, 2016 at 3:01 PM, Christoph Hellwig <[hidden email]> w
> The model is designed specifically to be compliant with the POSIX
> permission model. What assumptions are you talking about?
>
>> especially by adding allow and deny ACE at the same time.
>
> I remember from past discussions that a permission model like the
> POSIX ACL model that doesn't have DENY ACEs would be more to your
> liking. This argument is dead from the start though: NFSv4 ACLs
> without DENY ACEs cannot represent basic file permissions like 0604
> where the owning group has fewer permissions than others, for example
> (see the richaclex(7) man page). We would end up with a permission
> model that isn't even compatible with the traditional POSIX file
> permission model, one which nobody else implements or cares about.

NFSv4.1 (and later) and Samba's (and cifs.ko and NTFS-3g) ACL model are close
enough that doing a common approach that helps all three seems
very reasonable.

A loosely related question is what can be done for tools around existing
interfaces for ACLs.  I recently found out NTFS-3g has this xattr:

    static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";

which allows you to query system.ntfs_acl xattr to get their full ACL
(I hope) from NTFS but it hard to read without tools to parse
the blobs better.  I was prototyping adding this to cifs.ko for
the most current (SMB3 and later) protocol dialects at least
to allow backup and debug tools to use this to get the actual
ACL.   cifs.ko ACL should match almost exactly to NTFS-3g's but
I wish I could find some tools that use this xattr so I could try
comparing this with cacls.exe output and smbcacls (samba tool)
for display detailed ACL information.  Any idea of disk management tools
for dumping/viewing/editing ntfs ACLs on Linux for comparison?

>> It also doesn't help with the issue that the main thing it's trying
>> to be compatible with (Windows) actually uses a fundamentally different
>> identifier to apply the ACLs to - as long as you're still limited
>> to users and groups and not guids we'll still have that mapping problem
>> anyway.
>
> Samba has been dealing with mapping between SIDs and UIDs/GIDs for a
> long time, and it's working acceptably well.
>
> We could store SIDs in ACEs, but that wouldn't make the actual
> problems go away: Files on Linux have an owner and an owning group
> which are identitifed by UID/GID, whereas a file is owned by a SID
> which can be either a user or a group in a SID world. Also, processes
> on Linux have an owner and a list of groups which are identified by
> UID/GID, so any SIDs stored in filesystems would never match a
> process, anyway.

Samba's SID<->Username and SID<->UID mapping does work
acceptably well, if a bit "over-configurable" ie with
many choices for how it is done.

 (the related RFC2307 mapping needed for mapping usernames
to uids across an enterprise, which Samba's winbind can
also do is helpful much more broadly - since, unlike a uid
which is too small, the username in an NFS ACLs
are basically a one to one mapping for Samba to SIDs (there
are may samba vfs modules for different OS that already
do this, including a one for an earlier version of Linux RichACLs)

Sounds like I need to quickly rework the SMB3 ACL helper functions
for cifs.ko

Also do you know where is the current version of the corresponding
vfs_richacl for
Samba which works with the current RichACL format?


--
Thanks,

Steve
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 00/22] Richacls (Core and Ext4)

Jeremy Allison
On Fri, Mar 11, 2016 at 02:05:16PM -0600, Steve French wrote:
> Sounds like I need to quickly rework the SMB3 ACL helper functions
> for cifs.ko
>
> Also do you know where is the current version of the corresponding
> vfs_richacl for
> Samba which works with the current RichACL format?

I have a patch for a new vfs_richacl somewhere. I remember
sending it to Andreas for testing...
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 00/22] Richacls (Core and Ext4)

Simo
In reply to this post by J. Bruce Fields
On Fri, 2016-03-11 at 09:07 -0500, J. Bruce Fields wrote:

> On Fri, Mar 11, 2016 at 06:01:34AM -0800, Christoph Hellwig wrote:
> >
> > On Mon, Feb 29, 2016 at 09:17:05AM +0100, Andreas Gruenbacher
> > wrote:
> > >
> > > Al,
> > >
> > > could you please make sure you are happy with the current version
> > > of the
> > > richacl patch queue for the next merge window?
> > I'm still not happy.
> >
> > For one I still see no reason to merge this broken ACL model at
> > all.
> > It provides our actualy Linux users no benefit at all, while
> > breaking
> > a lot of assumptions, especially by adding allow and deny ACE at
> > the
> > same sime.
> Could you explain what you mean by "adding allow and deny ACE at the
> same time"?
>
> >
> > It also doesn't help with the issue that the main thing it's trying
> > to be compatible with (Windows) actually uses a fundamentally
> > different
> > identifier to apply the ACLs to - as long as you're still limited
> > to users and groups and not guids we'll still have that mapping
> > problem
> > anyway.
> Agreed, but, one step at a time?  My impression is that the Samba
> people
> still consider this a step forward for Linux compatibility.

It is a step forward, but being able to store SIDs in the ACL, would be
a much better one.

Simo.

> --b.
>
> >
> >
> > But besides that fundamental question on the purpose of it I also
> > don't think the code is suitable, more in the individual patches.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs"
> in
> the body of a message to [hidden email]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 00/22] Richacls (Core and Ext4)

Andreas Gruenbacher-6
In reply to this post by Jeremy Allison
On Sat, Mar 12, 2016 at 12:02 AM, Jeremy Allison <[hidden email]> wrote:

> On Fri, Mar 11, 2016 at 02:05:16PM -0600, Steve French wrote:
>> Sounds like I need to quickly rework the SMB3 ACL helper functions
>> for cifs.ko
>>
>> Also do you know where is the current version of the corresponding
>> vfs_richacl for
>> Samba which works with the current RichACL format?
>
> I have a patch for a new vfs_richacl somewhere. I remember
> sending it to Andreas for testing...

Ah, the patch was for testing, not resting ... how could I get that mixed up.

I've applied your patch to the latest master branch, made it compile
again, and fixed a few obvious problems. The results I get with
smbcacls look reasonable now.

The code is here:
  https://github.com/andreas-gruenbacher/samba richacl

I've used the following smb.conf:
  [richacl]
  comment = Richacl directory
  path = /mnt/ext4
  vfs objects = richacl
  writeable = yes
  browseable = yes

Is there a particular reason why you didn't make vfs_richacl a
dynamically loadable module?

Thanks,
Andreas
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v18 21/22] ext4: Add richacl support

Andreas Gruenbacher-6
In reply to this post by Christoph Hellwig
On Fri, Mar 11, 2016 at 3:27 PM, Christoph Hellwig <[hidden email]> wrote:

>> +static inline int
>> +ext4_acl_chmod(struct inode *inode, umode_t mode)
>> +{
>> +     if (IS_RICHACL(inode))
>> +             return richacl_chmod(inode, inode->i_mode);
>> +     return posix_acl_chmod(inode, inode->i_mode);
>> +}
>
> Thi isn't ext4-specific and potentially duplicated in every caller.
> Please provide this as a common helper.
>
> Also while we're at it, the mode argument is ignore and the function
> always uses inode->i_mode instead.
>
>> +ext4_get_richacl(struct inode *inode)
>> +{
>> +     const int name_index = EXT4_XATTR_INDEX_RICHACL;
>> +     void *value = NULL;
>> +     struct richacl *acl = NULL;
>> +     int retval;
>> +
>> +     retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
>> +     if (retval > 0) {
>> +             value = kmalloc(retval, GFP_NOFS);
>> +             if (!value)
>> +                     return ERR_PTR(-ENOMEM);
>> +             retval = ext4_xattr_get(inode, name_index, "", value, retval);
>> +     }
>> +     if (retval > 0) {
>> +             acl = richacl_from_xattr(&init_user_ns, value, retval);
>> +             if (acl == ERR_PTR(-EINVAL))
>> +                     acl = ERR_PTR(-EIO);
>
> Shouldn't richacl_from_xattr return the error pointer that ->get_richacl
> callers expect?

The xattr representation is the same on disk and at the xattr syscall
layer, and so richacl_from_xattr is used for converting into the
in-memory representation in both cases. The error codes are not the
same when a user supplies an invalid value via setxattr or NFS and
when an invalid xattr is read from disk though. I'll add a parameter
to richacl_from_xattr to make this more explicit.

>> +static int
>> +__ext4_set_richacl(handle_t *handle, struct inode *inode, struct richacl *acl)
>> +{
>> +     const int name_index = EXT4_XATTR_INDEX_RICHACL;
>> +     umode_t mode = inode->i_mode;
>> +     int retval, size;
>> +     void *value;
>> +
>> +     if (richacl_equiv_mode(acl, &mode) == 0) {
>> +             inode->i_ctime = ext4_current_time(inode);
>> +             inode->i_mode = mode;
>> +             ext4_mark_inode_dirty(handle, inode);
>> +             return __ext4_remove_richacl(handle, inode);
>> +     }
>
> Should this check for a NULL acl instead of special casing that
> in ext4_set_richacl?

I'm not sure I understand what you mean. When the

>> +int
>> +ext4_init_richacl(handle_t *handle, struct inode *inode, struct inode *dir)
>> +{
>> +     struct richacl *acl = richacl_create(&inode->i_mode, dir);
>> +     int error;
>> +
>> +     error = PTR_ERR(acl);
>> +     if (IS_ERR(acl))
>> +             return error;
>
>         if (IS_ERR(acl))
>                 return PTR_ERR(acl);
>
>> +     if (acl) {
>> +             error = __ext4_set_richacl(handle, inode, acl);
>> +             richacl_put(acl);
>> +     }
>
> Shouldn't richacl_create return NULL if the ACL is equivalent to the
> mode bits instead of letting every filesystem figure that out on it's
> own?
>
123