[PATCH v8 16/41] richacl: xattr mapping functions

2015-09-27 Thread Andreas Gruenbacher
Map between "system.richacl" xattrs and the in-kernel representation.

Signed-off-by: Andreas Gruenbacher 
---
 fs/Makefile   |   2 +-
 fs/richacl_xattr.c| 220 ++
 fs/xattr.c|  34 +--
 include/linux/richacl_xattr.h |  62 
 include/uapi/linux/xattr.h|   2 +
 5 files changed, 313 insertions(+), 7 deletions(-)
 create mode 100644 fs/richacl_xattr.c
 create mode 100644 include/linux/richacl_xattr.h

diff --git a/fs/Makefile b/fs/Makefile
index ec665fd..35e640d 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_inode.o
+richacl-y  := richacl_base.o richacl_inode.o 
richacl_xattr.o
 
 obj-y  += quota/
 
diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
new file mode 100644
index 000..cd9979d
--- /dev/null
+++ b/fs/richacl_xattr.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+
+MODULE_LICENSE("GPL");
+
+/**
+ * richacl_from_xattr  -  convert a richacl xattr into the in-memory 
representation
+ */
+struct richacl *
+richacl_from_xattr(struct user_namespace *user_ns,
+  const void *value, size_t size)
+{
+   const struct richacl_xattr *xattr_acl = value;
+   const struct richace_xattr *xattr_ace = (void *)(xattr_acl + 1);
+   struct richacl *acl;
+   struct richace *ace;
+   int count;
+
+   if (size < sizeof(*xattr_acl) ||
+   xattr_acl->a_version != RICHACL_XATTR_VERSION ||
+   (xattr_acl->a_flags & ~RICHACL_VALID_FLAGS))
+   return ERR_PTR(-EINVAL);
+   size -= sizeof(*xattr_acl);
+   count = le16_to_cpu(xattr_acl->a_count);
+   if (count > RICHACL_XATTR_MAX_COUNT)
+   return ERR_PTR(-EINVAL);
+   if (size != count * sizeof(*xattr_ace))
+   return ERR_PTR(-EINVAL);
+
+   acl = richacl_alloc(count, GFP_NOFS);
+   if (!acl)
+   return ERR_PTR(-ENOMEM);
+
+   acl->a_flags = xattr_acl->a_flags;
+   acl->a_owner_mask = le32_to_cpu(xattr_acl->a_owner_mask);
+   if (acl->a_owner_mask & ~RICHACE_VALID_MASK)
+   goto fail_einval;
+   acl->a_group_mask = le32_to_cpu(xattr_acl->a_group_mask);
+   if (acl->a_group_mask & ~RICHACE_VALID_MASK)
+   goto fail_einval;
+   acl->a_other_mask = le32_to_cpu(xattr_acl->a_other_mask);
+   if (acl->a_other_mask & ~RICHACE_VALID_MASK)
+   goto fail_einval;
+
+   richacl_for_each_entry(ace, acl) {
+   ace->e_type  = le16_to_cpu(xattr_ace->e_type);
+   ace->e_flags = le16_to_cpu(xattr_ace->e_flags);
+   ace->e_mask  = le32_to_cpu(xattr_ace->e_mask);
+
+   if (ace->e_flags & ~RICHACE_VALID_FLAGS)
+   goto fail_einval;
+   if (ace->e_flags & RICHACE_SPECIAL_WHO) {
+   ace->e_id.special = le32_to_cpu(xattr_ace->e_id);
+   if (ace->e_id.special > RICHACE_EVERYONE_SPECIAL_ID)
+   goto fail_einval;
+   } else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) {
+   u32 id = le32_to_cpu(xattr_ace->e_id);
+
+   ace->e_id.gid = make_kgid(user_ns, id);
+   if (!gid_valid(ace->e_id.gid))
+   goto fail_einval;
+   } else {
+   u32 id = le32_to_cpu(xattr_ace->e_id);
+
+   ace->e_id.uid = make_kuid(user_ns, id);
+   if (!uid_valid(ace->e_id.uid))
+   goto fail_einval;
+   }
+   if (ace->e_type > RICHACE_ACCESS_DENIED_ACE_TYPE ||
+   (ace->e_mask & ~RICHACE_VALID_MASK))
+   goto fail_einval;
+
+   xattr_ace++;
+   }
+
+   return acl;
+
+fail_einval:
+   richacl_put(acl);
+   return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(richacl_from_xattr);
+
+/**
+ * richacl_xattr_size  -  compute the size of the xattr representation of @acl
+ */
+size_t
+richacl_xattr_size(const struct richacl *acl)

[PATCH v8 16/41] richacl: xattr mapping functions

2015-09-27 Thread Andreas Gruenbacher
Map between "system.richacl" xattrs and the in-kernel representation.

Signed-off-by: Andreas Gruenbacher 
---
 fs/Makefile   |   2 +-
 fs/richacl_xattr.c| 220 ++
 fs/xattr.c|  34 +--
 include/linux/richacl_xattr.h |  62 
 include/uapi/linux/xattr.h|   2 +
 5 files changed, 313 insertions(+), 7 deletions(-)
 create mode 100644 fs/richacl_xattr.c
 create mode 100644 include/linux/richacl_xattr.h

diff --git a/fs/Makefile b/fs/Makefile
index ec665fd..35e640d 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_inode.o
+richacl-y  := richacl_base.o richacl_inode.o 
richacl_xattr.o
 
 obj-y  += quota/
 
diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
new file mode 100644
index 000..cd9979d
--- /dev/null
+++ b/fs/richacl_xattr.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2006, 2010  Novell, Inc.
+ * Copyright (C) 2015  Red Hat, Inc.
+ * Written by Andreas Gruenbacher 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+
+MODULE_LICENSE("GPL");
+
+/**
+ * richacl_from_xattr  -  convert a richacl xattr into the in-memory 
representation
+ */
+struct richacl *
+richacl_from_xattr(struct user_namespace *user_ns,
+  const void *value, size_t size)
+{
+   const struct richacl_xattr *xattr_acl = value;
+   const struct richace_xattr *xattr_ace = (void *)(xattr_acl + 1);
+   struct richacl *acl;
+   struct richace *ace;
+   int count;
+
+   if (size < sizeof(*xattr_acl) ||
+   xattr_acl->a_version != RICHACL_XATTR_VERSION ||
+   (xattr_acl->a_flags & ~RICHACL_VALID_FLAGS))
+   return ERR_PTR(-EINVAL);
+   size -= sizeof(*xattr_acl);
+   count = le16_to_cpu(xattr_acl->a_count);
+   if (count > RICHACL_XATTR_MAX_COUNT)
+   return ERR_PTR(-EINVAL);
+   if (size != count * sizeof(*xattr_ace))
+   return ERR_PTR(-EINVAL);
+
+   acl = richacl_alloc(count, GFP_NOFS);
+   if (!acl)
+   return ERR_PTR(-ENOMEM);
+
+   acl->a_flags = xattr_acl->a_flags;
+   acl->a_owner_mask = le32_to_cpu(xattr_acl->a_owner_mask);
+   if (acl->a_owner_mask & ~RICHACE_VALID_MASK)
+   goto fail_einval;
+   acl->a_group_mask = le32_to_cpu(xattr_acl->a_group_mask);
+   if (acl->a_group_mask & ~RICHACE_VALID_MASK)
+   goto fail_einval;
+   acl->a_other_mask = le32_to_cpu(xattr_acl->a_other_mask);
+   if (acl->a_other_mask & ~RICHACE_VALID_MASK)
+   goto fail_einval;
+
+   richacl_for_each_entry(ace, acl) {
+   ace->e_type  = le16_to_cpu(xattr_ace->e_type);
+   ace->e_flags = le16_to_cpu(xattr_ace->e_flags);
+   ace->e_mask  = le32_to_cpu(xattr_ace->e_mask);
+
+   if (ace->e_flags & ~RICHACE_VALID_FLAGS)
+   goto fail_einval;
+   if (ace->e_flags & RICHACE_SPECIAL_WHO) {
+   ace->e_id.special = le32_to_cpu(xattr_ace->e_id);
+   if (ace->e_id.special > RICHACE_EVERYONE_SPECIAL_ID)
+   goto fail_einval;
+   } else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) {
+   u32 id = le32_to_cpu(xattr_ace->e_id);
+
+   ace->e_id.gid = make_kgid(user_ns, id);
+   if (!gid_valid(ace->e_id.gid))
+   goto fail_einval;
+   } else {
+   u32 id = le32_to_cpu(xattr_ace->e_id);
+
+   ace->e_id.uid = make_kuid(user_ns, id);
+   if (!uid_valid(ace->e_id.uid))
+   goto fail_einval;
+   }
+   if (ace->e_type > RICHACE_ACCESS_DENIED_ACE_TYPE ||
+   (ace->e_mask & ~RICHACE_VALID_MASK))
+   goto fail_einval;
+
+   xattr_ace++;
+   }
+
+   return acl;
+
+fail_einval:
+   richacl_put(acl);
+   return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(richacl_from_xattr);
+
+/**
+ * richacl_xattr_size  -  compute the size of the xattr representation of @acl
+ */
+size_t