Re: [RFC v7 20/41] richacl: acl editing helper functions
From: J. Bruce Fields
Date: Fri Sep 18 2015 - 14:54:14 EST
On Sat, Sep 05, 2015 at 12:27:15PM +0200, Andreas Gruenbacher wrote:
> The file masks in richacls make chmod and creating new files more
> efficient than having to apply file permission bits to the acl directly.
> They also allow us to regain permissions from an acl even after a
> restrictive chmod, because the permissions in the acl itself are not
> being destroyed. In POSIX ACLs, the mask entry has a similar function.
>
> Protocols like nfsv4 do not understand file masks. For those protocols,
> we need to compute nfs4 acls which represent the effective permissions
> granted by a richacl: we need to "apply" the file masks to the acl.
>
> This is the first in a series of richacl transformation patches; it
> implements basic richacl editing functions. The following patches
> implement algorithms for transforming a richacl so that it can be
> evaluated as a plain nfs4 acl, with identical permission check results.
Reviewed-by: J. Bruce Fields <bfields@xxxxxxxxxx>
Looks nicely done.--b.
>
> Signed-off-by: Andreas Gruenbacher <agruen@xxxxxxxxxx>
> ---
> fs/Makefile | 3 +-
> fs/richacl_compat.c | 155 +++++++++++++++++++++++++++++++++++++++++
> include/linux/richacl_compat.h | 40 +++++++++++
> 3 files changed, 197 insertions(+), 1 deletion(-)
> create mode 100644 fs/richacl_compat.c
> create mode 100644 include/linux/richacl_compat.h
>
> diff --git a/fs/Makefile b/fs/Makefile
> index baf385a..2d08c70 100644
> --- a/fs/Makefile
> +++ b/fs/Makefile
> @@ -48,7 +48,8 @@ obj-$(CONFIG_SYSCTL) += drop_caches.o
>
> obj-$(CONFIG_FHANDLE) += fhandle.o
> obj-$(CONFIG_FS_RICHACL) += richacl.o
> -richacl-y := richacl_base.o richacl_inode.o richacl_xattr.o
> +richacl-y := richacl_base.o richacl_inode.o \
> + richacl_xattr.o richacl_compat.o
>
> obj-y += quota/
>
> diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
> new file mode 100644
> index 0000000..341e429
> --- /dev/null
> +++ b/fs/richacl_compat.c
> @@ -0,0 +1,155 @@
> +/*
> + * Copyright (C) 2006, 2010 Novell, Inc.
> + * Copyright (C) 2015 Red Hat, Inc.
> + * Written by Andreas Gruenbacher <agruen@xxxxxxxxxx>
> + *
> + * 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/module.h>
> +#include <linux/fs.h>
> +#include <linux/slab.h>
> +#include <linux/richacl_compat.h>
> +
> +/**
> + * richacl_prepare - allocate richacl being constructed
> + *
> + * Allocate a richacl which can hold @count entries but which is initially
> + * empty.
> + */
> +struct richacl *richacl_prepare(struct richacl_alloc *alloc, unsigned int count)
> +{
> + alloc->acl = richacl_alloc(count, GFP_KERNEL);
> + if (!alloc->acl)
> + return NULL;
> + alloc->acl->a_count = 0;
> + alloc->count = count;
> + return alloc->acl;
> +}
> +EXPORT_SYMBOL_GPL(richacl_prepare);
> +
> +/**
> + * richacl_delete_entry - delete an entry in an acl
> + * @alloc: acl and number of allocated entries
> + * @ace: an entry in @alloc->acl
> + *
> + * Updates @ace so that it points to the entry before the deleted entry
> + * on return. (When deleting the first entry, @ace will point to the
> + * (non-existent) entry before the first entry). This behavior is the
> + * expected behavior when deleting entries while forward iterating over
> + * an acl.
> + */
> +void
> +richacl_delete_entry(struct richacl_alloc *alloc, struct richace **ace)
> +{
> + void *end = alloc->acl->a_entries + alloc->acl->a_count;
> +
> + memmove(*ace, *ace + 1, end - (void *)(*ace + 1));
> + (*ace)--;
> + alloc->acl->a_count--;
> +}
> +EXPORT_SYMBOL_GPL(richacl_delete_entry);
> +
> +/**
> + * richacl_insert_entry - insert an entry in an acl
> + * @alloc: acl and number of allocated entries
> + * @ace: entry before which the new entry shall be inserted
> + *
> + * Insert a new entry in @alloc->acl at position @ace and zero-initialize
> + * it. This may require reallocating @alloc->acl.
> + */
> +int
> +richacl_insert_entry(struct richacl_alloc *alloc, struct richace **ace)
> +{
> + struct richacl *acl = alloc->acl;
> + unsigned int index = *ace - acl->a_entries;
> + size_t tail_size = (acl->a_count - index) * sizeof(struct richace);
> +
> + if (alloc->count == acl->a_count) {
> + size_t new_size = sizeof(struct richacl) +
> + (acl->a_count + 1) * sizeof(struct richace);
> +
> + acl = krealloc(acl, new_size, GFP_KERNEL);
> + if (!acl)
> + return -1;
> + *ace = acl->a_entries + index;
> + alloc->acl = acl;
> + alloc->count++;
> + }
> +
> + memmove(*ace + 1, *ace, tail_size);
> + memset(*ace, 0, sizeof(**ace));
> + acl->a_count++;
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(richacl_insert_entry);
> +
> +/**
> + * richacl_append_entry - append an entry to an acl
> + * @alloc: acl and number of allocated entries
> + *
> + * This may require reallocating @alloc->acl.
> + */
> +struct richace *richacl_append_entry(struct richacl_alloc *alloc)
> +{
> + struct richacl *acl = alloc->acl;
> + struct richace *ace = acl->a_entries + acl->a_count;
> +
> + if (alloc->count > alloc->acl->a_count) {
> + acl->a_count++;
> + return ace;
> + }
> + return richacl_insert_entry(alloc, &ace) ? NULL : ace;
> +}
> +EXPORT_SYMBOL_GPL(richacl_append_entry);
> +
> +/**
> + * richace_change_mask - set the mask of @ace to @mask
> + * @alloc: acl and number of allocated entries
> + * @ace: entry to modify
> + * @mask: new mask for @ace
> + *
> + * If @ace is inheritable, a inherit-only ace is inserted before @ace which
> + * includes the inheritable permissions of @ace and the inheritance flags of
> + * @ace are cleared before changing the mask.
> + *
> + * If @mask is 0, the original ace is turned into an inherit-only entry if
> + * there are any inheritable permissions, and removed otherwise.
> + *
> + * The returned @ace points to the modified or inserted effective-only acl
> + * entry if that entry exists, to the entry that has become inheritable-only,
> + * or else to the previous entry in the acl.
> + */
> +static int
> +richace_change_mask(struct richacl_alloc *alloc, struct richace **ace,
> + unsigned int mask)
> +{
> + if (mask && (*ace)->e_mask == mask)
> + (*ace)->e_flags &= ~RICHACE_INHERIT_ONLY_ACE;
> + else if (mask & ~RICHACE_POSIX_ALWAYS_ALLOWED) {
> + if (richace_is_inheritable(*ace)) {
> + if (richacl_insert_entry(alloc, ace))
> + return -1;
> + richace_copy(*ace, *ace + 1);
> + (*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
> + (*ace)++;
> + (*ace)->e_flags &= ~RICHACE_INHERITANCE_FLAGS |
> + RICHACE_INHERITED_ACE;
> + }
> + (*ace)->e_mask = mask;
> + } else {
> + if (richace_is_inheritable(*ace))
> + (*ace)->e_flags |= RICHACE_INHERIT_ONLY_ACE;
> + else
> + richacl_delete_entry(alloc, ace);
> + }
> + return 0;
> +}
> diff --git a/include/linux/richacl_compat.h b/include/linux/richacl_compat.h
> new file mode 100644
> index 0000000..a9ff630
> --- /dev/null
> +++ b/include/linux/richacl_compat.h
> @@ -0,0 +1,40 @@
> +/*
> + * Copyright (C) 2015 Red Hat, Inc.
> + * Written by Andreas Gruenbacher <agruenba@xxxxxxxxxx>
> + *
> + * 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_COMPAT_H
> +#define __RICHACL_COMPAT_H
> +
> +#include <linux/richacl.h>
> +
> +/**
> + * struct richacl_alloc - remember how many entries are actually allocated
> + * @acl: acl with a_count <= @count
> + * @count: the actual number of entries allocated in @acl
> + *
> + * We pass around this structure while modifying an acl so that we do
> + * not have to reallocate when we remove existing entries followed by
> + * adding new entries.
> + */
> +struct richacl_alloc {
> + struct richacl *acl;
> + unsigned int count;
> +};
> +
> +struct richacl *richacl_prepare(struct richacl_alloc *, unsigned int);
> +struct richace *richacl_append_entry(struct richacl_alloc *);
> +int richacl_insert_entry(struct richacl_alloc *, struct richace **);
> +void richacl_delete_entry(struct richacl_alloc *, struct richace **);
> +
> +#endif /* __RICHACL_COMPAT_H */
> --
> 2.4.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/