Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1261574 > unrolled thread
| Started by | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| First post | 2015-11-03 16:20 +0100 |
| Last post | 2015-11-03 17:20 +0100 |
| Articles | 20 on this page of 68 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH v13 00/51] Richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 08/51] richacl: Compute maximum file masks from an acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 10/51] vfs: Cache base_acl objects in inodes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
Re: [PATCH v13 10/51] vfs: Cache base_acl objects in inodes Andreas Dilger <adilger@dilger.ca> - 2015-11-03 23:40 +0100
Re: [PATCH v13 10/51] vfs: Cache base_acl objects in inodes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 23:00 +0100
[PATCH v13 07/51] richacl: Permission mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 02/51] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
Re: [PATCH v13 02/51] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:40 +0100
Re: [PATCH v13 02/51] vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 04:10 +0100
[PATCH v13 11/51] vfs: Add get_richacl and set_richacl inode operations Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 04/51] vfs: Make the inode passed to inode_change_ok non-const Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 12/51] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
Re: [PATCH v13 12/51] vfs: Cache richacl in struct inode Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:10 +0100
Re: [PATCH v13 12/51] vfs: Cache richacl in struct inode Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 23:20 +0100
[PATCH v13 05/51] vfs: Add permission flags for setting file attributes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 06/51] richacl: In-memory representation and helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:20 +0100
[PATCH v13 29/51] richacl: Move everyone@ aces down the acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 50/51] nfs: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 30/51] richacl: Propagate everyone@ permissions to other aces Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 40/51] nfsd: Add support for the MAY_CREATE_{FILE,DIR} permissions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 43/51] ext4: Don't allow unmapped identifiers in richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
Re: [PATCH v13 43/51] ext4: Don't allow unmapped identifiers in richacls Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:30 +0100
[PATCH v13 26/51] xfs: Plug memory leak in xfs_attrmulti_attr_set Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Trond Myklebust <trond.myklebust@primarydata.com> - 2015-11-03 17:30 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-05 12:10 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Trond Myklebust <trond.myklebust@primarydata.com> - 2015-11-05 17:00 +0100
Re: [PATCH v13 45/51] sunrpc: Allow to demand-allocate pages to encode into Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-08 23:20 +0100
[PATCH v13 48/51] nfs: Remove unused xdr page offsets in getacl/setacl arguments Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 51/51] nfs: Add support for the v4.1 dacl attribute Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 39/51] nfsd: Add support for the v4.1 dacl attribute Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 32/51] richacl: Set the other permissions to the other mask Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 33/51] richacl: Isolate the owner and group classes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 28/51] richacl: acl editing helper functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 47/51] nfs: Fix GETATTR bitmap verification Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
Re: [PATCH v13 47/51] nfs: Fix GETATTR bitmap verification Trond Myklebust <trond.myklebust@primarydata.com> - 2015-11-03 17:40 +0100
[PATCH v13 42/51] nfsd: Add support for unmapped richace identifiers Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 19/51] vfs: Add richacl permission checking Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 25/51] xfs: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 44/51] xfs: Don't allow unmapped identifiers in richacls Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 46/51] sunrpc: Add xdr_init_encode_pages Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 49/51] nfs: Distinguish missing users and groups from nobody Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 41/51] richacl: Add support for unmapped identifiers Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 38/51] nfsd: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 36/51] nfsd: Keep list of acls to dispose of in compoundargs Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:30 +0100
[PATCH v13 37/51] nfsd: Use richacls as internal acl representation Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:40 +0100
[PATCH v13 35/51] richacl: Create richacl from mode values Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:40 +0100
[PATCH v13 31/51] richacl: Set the owner permissions to the owner mask Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:50 +0100
[PATCH v13 34/51] richacl: Apply the file masks to a richacl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:50 +0100
[PATCH v13 27/51] xfs: Fix richacl access by ioctl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 16:50 +0100
[PATCH v13 16/51] richacl: Automatic Inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 15/51] richacl: Create-time inheritance Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 24/51] xfs: Change how listxattr generates synthetic attributes Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 21/51] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
Re: [PATCH v13 21/51] ext4: Add richacl feature flag Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:20 +0100
Re: [PATCH v13 21/51] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 03:30 +0100
Re: [PATCH v13 21/51] ext4: Add richacl feature flag Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 03:50 +0100
[PATCH v13 14/51] richacl: Check if an acl is equivalent to a file mode Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 20/51] ext4: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
Re: [PATCH v13 20/51] ext4: Add richacl support Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-04 03:20 +0100
Re: [PATCH v13 20/51] ext4: Add richacl support Andreas Dilger <adilger@dilger.ca> - 2015-11-04 03:20 +0100
[PATCH v13 18/51] richacl: Add richacl xattr handler Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 22/51] xfs: Fix error path in xfs_get_acl Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 23/51] xfs: Make xfs_set_mode non-static Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 13/51] richacl: Update the file masks in chmod() Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:00 +0100
[PATCH v13 09/51] richacl: Permission check algorithm Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:10 +0100
[PATCH v13 17/51] richacl: xattr mapping functions Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:10 +0100
[PATCH v13 03/51] vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags Andreas Gruenbacher <agruenba@redhat.com> - 2015-11-03 17:20 +0100
Page 3 of 4 — ← Prev page 1 2 [3] 4 Next page →
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 46/51] sunrpc: Add xdr_init_encode_pages |
| Message-ID | <qqLH5-4sG-59@gated-at.bofh.it> |
| In reply to | #1261574 |
Initialize xdr_stream and xdr_buf from a pages array, for encoding into
the pages.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
include/linux/sunrpc/xdr.h | 2 ++
net/sunrpc/xdr.c | 25 +++++++++++++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 70c6b92..2c99cff 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -214,6 +214,8 @@ typedef void (*kxdreproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
typedef int (*kxdrdproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern void xdr_init_encode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
+ struct page **pages, unsigned int len);
extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_commit_encode(struct xdr_stream *xdr);
extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 63c1c36..f97b96b 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -483,6 +483,31 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
EXPORT_SYMBOL_GPL(xdr_init_encode);
/**
+ * xdr_init_encode_pages - Initialize struct xdr_stream for encoding into pages
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to XDR buffer in which to encode data
+ * @pages: pages array in which to encode
+ * @len: maximum length of @buf
+ *
+ * Initialize @xdr and @buf for encoding into the @pages array. If a
+ * page in @pages is NULL, it will be allocated on demand.
+ */
+void xdr_init_encode_pages(struct xdr_stream *xdr, struct xdr_buf *buf,
+ struct page **pages, unsigned int len)
+{
+ memset(buf, 0, sizeof(*buf));
+ buf->pages = pages;
+ buf->page_len = len;
+ buf->buflen = len;
+
+ memset(xdr, 0, sizeof(*xdr));
+ xdr->buf = buf;
+ xdr->iov = buf->head;
+ xdr->page_ptr = pages - 1;
+}
+EXPORT_SYMBOL_GPL(xdr_init_encode_pages);
+
+/**
* xdr_commit_encode - Ensure all data is written to buffer
* @xdr: pointer to xdr_stream
*
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 49/51] nfs: Distinguish missing users and groups from nobody |
| Message-ID | <qqLH5-4sG-61@gated-at.bofh.it> |
| In reply to | #1261574 |
User and group names are mapped to IDs using the kernel keyring infrastructure.
When a name does not exist, it is mapped to the nobody user or group; there is
no way to tell the difference from the mapping result.
In ACLs, we need to make that distinction. For that, use the new "xuid" and
"xgid" maps: they behave like the old "uid" and "gid" maps except that the IDs
of existing users and groups are prefixed by a "+" sign.
When the "xuid" or "xgid" maps are not supported, nfs falls back to the "uid"
and "gid" maps.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/nfs/nfs4idmap.c | 57 ++++++++++++++++++++++++++++++++++++++---------
fs/nfs/nfs4xdr.c | 6 +++--
include/linux/nfs_fs_sb.h | 1 +
3 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index 2e49022..34dd404 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -100,10 +100,12 @@ static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr
{
struct nfs4_string *owner = fattr->owner_name;
kuid_t uid;
+ int ret;
if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME))
return false;
- if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) {
+ ret = nfs_map_name_to_uid(server, owner->data, owner->len, &uid);
+ if (ret == 0 || ret == -ENOENT) {
fattr->uid = uid;
fattr->valid |= NFS_ATTR_FATTR_OWNER;
}
@@ -114,10 +116,12 @@ static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr
{
struct nfs4_string *group = fattr->group_name;
kgid_t gid;
+ int ret;
if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME))
return false;
- if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) {
+ ret = nfs_map_group_to_gid(server, group->data, group->len, &gid);
+ if (ret == 0 || ret == -ENOENT) {
fattr->gid = gid;
fattr->valid |= NFS_ATTR_FATTR_GROUP;
}
@@ -351,20 +355,23 @@ static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
}
/* Name -> ID */
+/* Returns -ENOENT for unknown names (with @id set to the nobody id). */
static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
__u32 *id, struct idmap *idmap)
{
- char id_str[NFS_UINT_MAXLEN];
+ char id_str[NFS_UINT_MAXLEN + 1];
long id_long;
ssize_t data_size;
int ret = 0;
- data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
+ data_size = nfs_idmap_get_key(name, namelen, type, id_str, sizeof(id_str), idmap);
if (data_size <= 0) {
ret = -EINVAL;
} else {
ret = kstrtol(id_str, 10, &id_long);
*id = (__u32)id_long;
+ if (!ret && *id_str != '+')
+ ret = -ENOENT;
}
return ret;
}
@@ -719,9 +726,24 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
__u32 id = -1;
int ret = 0;
- if (!nfs_map_string_to_numeric(name, namelen, &id))
- ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap);
- if (ret == 0) {
+ if (!nfs_map_string_to_numeric(name, namelen, &id)) {
+ struct nfs_client *client = server->nfs_client;
+ const char *type;
+
+ for(;;) {
+ type = "xuid";
+ if (test_bit(NFS_CS_NOXUID, &client->cl_flags))
+ type = "uid";
+
+ ret = nfs_idmap_lookup_id(name, namelen, type, &id, idmap);
+ if (ret != -EINVAL || test_bit(NFS_CS_NOXUID, &client->cl_flags))
+ break;
+ printk(KERN_NOTICE "NFS: Falling back from nfsidmap "
+ "xuid/xgid to uid/gid\n");
+ set_bit(NFS_CS_NOXUID, &client->cl_flags);
+ }
+ }
+ if (ret == 0 || ret == -ENOENT) {
*uid = make_kuid(&init_user_ns, id);
if (!uid_valid(*uid))
ret = -ERANGE;
@@ -736,9 +758,24 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size
__u32 id = -1;
int ret = 0;
- if (!nfs_map_string_to_numeric(name, namelen, &id))
- ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap);
- if (ret == 0) {
+ if (!nfs_map_string_to_numeric(name, namelen, &id)) {
+ struct nfs_client *client = server->nfs_client;
+ const char *type;
+
+ for(;;) {
+ type = "xgid";
+ if (test_bit(NFS_CS_NOXUID, &client->cl_flags))
+ type = "gid";
+
+ ret = nfs_idmap_lookup_id(name, namelen, type, &id, idmap);
+ if (ret != -EINVAL || test_bit(NFS_CS_NOXUID, &client->cl_flags))
+ break;
+ printk(KERN_NOTICE "NFS: Falling back from nfsidmap "
+ "xuid/xgid to uid/gid\n");
+ set_bit(NFS_CS_NOXUID, &client->cl_flags);
+ }
+ }
+ if (ret == 0 || ret == -ENOENT) {
*gid = make_kgid(&init_user_ns, id);
if (!gid_valid(*gid))
ret = -ERANGE;
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index eefed15..adeb894 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3875,7 +3875,8 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
ret = NFS_ATTR_FATTR_OWNER_NAME;
}
} else if (len < XDR_MAX_NETOBJ) {
- if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
+ ret = nfs_map_name_to_uid(server, (char *)p, len, uid);
+ if (ret == 0 || ret == -ENOENT)
ret = NFS_ATTR_FATTR_OWNER;
else
dprintk("%s: nfs_map_name_to_uid failed!\n",
@@ -3918,7 +3919,8 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
ret = NFS_ATTR_FATTR_GROUP_NAME;
}
} else if (len < XDR_MAX_NETOBJ) {
- if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
+ ret = nfs_map_group_to_gid(server, (char *)p, len, gid);
+ if (ret == 0 || ret == -ENOENT)
ret = NFS_ATTR_FATTR_GROUP;
else
dprintk("%s: nfs_map_group_to_gid failed!\n",
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 570a7df..c7d42b7 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -36,6 +36,7 @@ struct nfs_client {
#define NFS_CS_RENEWD 3 /* - renewd started */
#define NFS_CS_STOP_RENEW 4 /* no more state to renew */
#define NFS_CS_CHECK_LEASE_TIME 5 /* need to check lease time */
+#define NFS_CS_NOXUID 6 /* don't use idmap xuid / xgid */
unsigned long cl_flags; /* behavior switches */
#define NFS_CS_NORESVPORT 0 /* - use ephemeral src port */
#define NFS_CS_DISCRTRY 1 /* - disconnect on RPC retry */
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 41/51] richacl: Add support for unmapped identifiers |
| Message-ID | <qqLH6-4sG-69@gated-at.bofh.it> |
| In reply to | #1261574 |
Some remote file systems like nfs may return user or group identifiers
that cannot be mapped to local uids / gids. Allow to represent such
unmapped identifiers in richacls. (We still cannot represent unmapped
owners and owning groups, however.)
In the in-memory representation, the richacl is followed by a list of
NUL-terminated strings, with no padding. Entries with an unmapped
identifier have the RICHACE_UNMAPPED_WHO flag set, and ace->e_id.offs
specifies the offset into this list. Multiple entries can refer to the
same offset.
The xattr representation is similar, but ace->e_id is ignored, and the
list of unmapped identifier strings contains a string for each acl entry
whose RICHACE_UNMAPPED_WHO flag is set.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/richacl_base.c | 139 ++++++++++++++++++++++++++++++++++++++++---
fs/richacl_compat.c | 18 +++---
fs/richacl_inode.c | 4 +-
fs/richacl_xattr.c | 69 +++++++++++++++++----
include/linux/richacl.h | 31 ++++++++--
include/uapi/linux/richacl.h | 2 +
6 files changed, 227 insertions(+), 36 deletions(-)
diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index 2a9c448..641b1bb 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -23,22 +23,25 @@
MODULE_LICENSE("GPL");
/**
- * richacl_alloc - allocate a richacl
+ * __richacl_alloc - allocate a richacl
* @count: number of entries
+ * @unmapped_size: size to reserve for unmapped identifiers
*/
struct richacl *
-richacl_alloc(int count, gfp_t gfp)
+__richacl_alloc(unsigned int count, size_t unmapped_size, gfp_t gfp)
{
- size_t size = sizeof(struct richacl) + count * sizeof(struct richace);
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace) +
+ unmapped_size;
struct richacl *acl = kzalloc(size, gfp);
if (acl) {
atomic_set(&acl->a_base.ba_refcount, 1);
acl->a_count = count;
+ acl->a_unmapped_size = unmapped_size;
}
return acl;
}
-EXPORT_SYMBOL_GPL(richacl_alloc);
+EXPORT_SYMBOL_GPL(__richacl_alloc);
/**
* richacl_clone - create a copy of a richacl
@@ -47,7 +50,8 @@ 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);
+ size_t size = sizeof(struct richacl) + count * sizeof(struct richace) +
+ acl->a_unmapped_size;
struct richacl *dup = kmalloc(size, gfp);
if (dup) {
@@ -59,6 +63,9 @@ richacl_clone(const struct richacl *acl, gfp_t gfp)
/**
* richace_copy - copy an acl entry
+ *
+ * If @from has an unmapped who value (from->e_flags & RICHACE_UNMAPPED_WHO),
+ * it can only be copied within the same acl!
*/
void
richace_copy(struct richace *to, const struct richace *from)
@@ -66,6 +73,82 @@ richace_copy(struct richace *to, const struct richace *from)
memcpy(to, from, sizeof(struct richace));
}
+/**
+ * richacl_add_unmapped_identifier
+ * @pacl: Pointer to an acl
+ * @pace: acl entry within @acl
+ * @who: unmapped identifier
+ * @len: length of @who
+ * @gfp: memory allocation flags
+ *
+ * Add an unmapped identifier to an acl, possibly reallocating the acl.
+ */
+int richacl_add_unmapped_identifier(struct richacl **pacl,
+ struct richace **pace,
+ const char *who,
+ unsigned int len, gfp_t gfp)
+{
+ struct richacl *acl = *pacl;
+ size_t size = sizeof(struct richacl) +
+ acl->a_count * sizeof(struct richace) +
+ acl->a_unmapped_size + len + 1;
+ unsigned int index = *pace - acl->a_entries;
+
+ acl = krealloc(*pacl, size, gfp);
+ if (acl) {
+ char *unmapped = (char *)(acl->a_entries + acl->a_count);
+ struct richace *ace = acl->a_entries + index;
+
+ ace->e_flags |= RICHACE_UNMAPPED_WHO;
+ ace->e_flags &= ~RICHACE_SPECIAL_WHO;
+ ace->e_id.offs = acl->a_unmapped_size;
+ memcpy(unmapped + ace->e_id.offs, who, len);
+ unmapped[ace->e_id.offs + len] = 0;
+ acl->a_unmapped_size += len + 1;
+ *pace = ace;
+ *pacl = acl;
+ return 0;
+ }
+ return -1;
+}
+EXPORT_SYMBOL_GPL(richacl_add_unmapped_identifier);
+
+/**
+ * richace_unmapped_identifier - get unmapped identifier
+ * @acl: acl containing @ace
+ * @ace: acl entry
+ *
+ * Get the unmapped identifier of @ace as a NUL-terminated string, or NULL if
+ * @ace doesn't have an unmapped identifier.
+ */
+const char *richace_unmapped_identifier(const struct richace *ace,
+ const struct richacl *acl)
+{
+ const char *unmapped = (char *)(acl->a_entries + acl->a_count);
+
+ if (!(ace->e_flags & RICHACE_UNMAPPED_WHO))
+ return NULL;
+ return unmapped + ace->e_id.offs;
+}
+EXPORT_SYMBOL(richace_unmapped_identifier);
+
+/**
+ * richacl_has_unmapped_identifiers
+ *
+ * Check if an acl has unmapped identifiers.
+ */
+bool richacl_has_unmapped_identifiers(struct richacl *acl)
+{
+ struct richace *ace;
+
+ richacl_for_each_entry(ace, acl) {
+ if (ace->e_flags & RICHACE_UNMAPPED_WHO)
+ return true;
+ }
+ return false;
+}
+EXPORT_SYMBOL_GPL(richacl_has_unmapped_identifiers);
+
/*
* richacl_mask_to_mode - compute the file permission bits from mask
* @mask: %RICHACE_* permission mask
@@ -214,7 +297,7 @@ static unsigned int richacl_allowed_to_who(struct richacl *acl,
richacl_for_each_entry_reverse(ace, acl) {
if (richace_is_inherit_only(ace))
continue;
- if (richace_is_same_identifier(ace, who) ||
+ if (richace_is_same_identifier(acl, ace, who) ||
richace_is_everyone(ace)) {
if (richace_is_allow(ace))
allowed |= ace->e_mask;
@@ -505,45 +588,72 @@ richacl_inherit(const struct richacl *dir_acl, int isdir)
const struct richace *dir_ace;
struct richacl *acl = NULL;
struct richace *ace;
- int count = 0;
+ unsigned int count = 0, unmapped_size = 0, offset = 0;
+ const char *dir_unmapped;
+ char *unmapped;
if (isdir) {
richacl_for_each_entry(dir_ace, dir_acl) {
if (!richace_is_inheritable(dir_ace))
continue;
+
count++;
+ dir_unmapped =
+ richace_unmapped_identifier(dir_ace, dir_acl);
+ if (dir_unmapped)
+ unmapped_size += strlen(dir_unmapped) + 1;
}
if (!count)
return NULL;
- acl = richacl_alloc(count, GFP_KERNEL);
+ acl = __richacl_alloc(count, unmapped_size, GFP_KERNEL);
if (!acl)
return ERR_PTR(-ENOMEM);
ace = acl->a_entries;
+ unmapped = (char *)(acl->a_entries + acl->a_count);
richacl_for_each_entry(dir_ace, dir_acl) {
if (!richace_is_inheritable(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;
+
+ dir_unmapped =
+ richace_unmapped_identifier(dir_ace, dir_acl);
+ if (dir_unmapped) {
+ size_t sz = strlen(dir_unmapped) + 1;
+
+ ace->e_id.offs = offset;
+ memcpy(unmapped, dir_unmapped, sz);
+ unmapped += sz;
+ offset += sz;
+ }
ace++;
}
} else {
richacl_for_each_entry(dir_ace, dir_acl) {
if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE))
continue;
+
count++;
+ dir_unmapped =
+ richace_unmapped_identifier(dir_ace, dir_acl);
+ if (dir_unmapped)
+ unmapped_size += strlen(dir_unmapped) + 1;
}
if (!count)
return NULL;
- acl = richacl_alloc(count, GFP_KERNEL);
+ acl = __richacl_alloc(count, unmapped_size, GFP_KERNEL);
if (!acl)
return ERR_PTR(-ENOMEM);
ace = acl->a_entries;
+ unmapped = (char *)(acl->a_entries + acl->a_count);
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;
/*
@@ -551,6 +661,17 @@ richacl_inherit(const struct richacl *dir_acl, int isdir)
* non-directories, so clear it.
*/
ace->e_mask &= ~RICHACE_DELETE_CHILD;
+
+ dir_unmapped =
+ richace_unmapped_identifier(dir_ace, dir_acl);
+ if (dir_unmapped) {
+ size_t sz = strlen(dir_unmapped) + 1;
+
+ ace->e_id.offs = offset;
+ memcpy(unmapped, dir_unmapped, sz);
+ unmapped += sz;
+ offset += sz;
+ }
ace++;
}
}
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 3a11773..24b5397 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -71,11 +71,13 @@ 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);
+ size_t tail_size = (acl->a_count - index) * sizeof(struct richace) +
+ acl->a_unmapped_size;
if (alloc->count == acl->a_count) {
size_t new_size = sizeof(struct richacl) +
- (acl->a_count + 1) * sizeof(struct richace);
+ (acl->a_count + 1) * sizeof(struct richace) +
+ acl->a_unmapped_size;
acl = krealloc(acl, new_size, GFP_KERNEL);
if (!acl)
@@ -103,10 +105,6 @@ 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);
@@ -261,12 +259,12 @@ __richacl_propagate_everyone(struct richacl_alloc *alloc, struct richace *who,
if (richace_is_inherit_only(ace))
continue;
if (richace_is_allow(ace)) {
- if (richace_is_same_identifier(ace, who)) {
+ if (richace_is_same_identifier(acl, ace, who)) {
allow &= ~ace->e_mask;
allow_last = ace;
}
} else if (richace_is_deny(ace)) {
- if (richace_is_same_identifier(ace, who))
+ if (richace_is_same_identifier(acl, ace, who))
allow &= ~ace->e_mask;
else if (allow & ace->e_mask)
allow_last = NULL;
@@ -613,7 +611,7 @@ __richacl_isolate_who(struct richacl_alloc *alloc, struct richace *who,
richacl_for_each_entry(ace, acl) {
if (richace_is_inherit_only(ace))
continue;
- if (richace_is_same_identifier(ace, who))
+ if (richace_is_same_identifier(acl, ace, who))
deny &= ~ace->e_mask;
}
if (!deny)
@@ -629,7 +627,7 @@ __richacl_isolate_who(struct richacl_alloc *alloc, struct richace *who,
if (richace_is_inherit_only(ace))
continue;
if (richace_is_deny(ace)) {
- if (richace_is_same_identifier(ace, who))
+ if (richace_is_same_identifier(acl, ace, who))
return richace_change_mask(alloc, &ace,
ace->e_mask | deny);
} else if (richace_is_allow(ace) &&
diff --git a/fs/richacl_inode.c b/fs/richacl_inode.c
index 24276da..026abae 100644
--- a/fs/richacl_inode.c
+++ b/fs/richacl_inode.c
@@ -161,8 +161,10 @@ richacl_permission(struct inode *inode, const struct richacl *acl,
} else if (richace_is_unix_group(ace)) {
if (!in_group_p(ace->e_id.gid))
continue;
- } else
+ } else if (richace_is_everyone(ace))
goto entry_matches_everyone;
+ else
+ continue;
/*
* Apply the group file mask to entries other than owner@ and
diff --git a/fs/richacl_xattr.c b/fs/richacl_xattr.c
index 767c1f7..09b1012 100644
--- a/fs/richacl_xattr.c
+++ b/fs/richacl_xattr.c
@@ -35,7 +35,8 @@ richacl_from_xattr(struct user_namespace *user_ns,
const struct richace_xattr *xattr_ace = (void *)(xattr_acl + 1);
struct richacl *acl;
struct richace *ace;
- int count;
+ unsigned int count, offset;
+ char *unmapped;
if (size < sizeof(*xattr_acl) ||
xattr_acl->a_version != RICHACL_XATTR_VERSION ||
@@ -45,10 +46,11 @@ richacl_from_xattr(struct user_namespace *user_ns,
count = le16_to_cpu(xattr_acl->a_count);
if (count > RICHACL_XATTR_MAX_COUNT)
return ERR_PTR(-EINVAL);
- if (size != count * sizeof(*xattr_ace))
+ if (size < count * sizeof(*xattr_ace))
return ERR_PTR(-EINVAL);
+ size -= count * sizeof(*xattr_ace);
- acl = richacl_alloc(count, GFP_NOFS);
+ acl = __richacl_alloc(count, size, GFP_NOFS);
if (!acl)
return ERR_PTR(-ENOMEM);
@@ -63,6 +65,16 @@ richacl_from_xattr(struct user_namespace *user_ns,
if (acl->a_other_mask & ~RICHACE_VALID_MASK)
goto fail_einval;
+ unmapped = (char *)(acl->a_entries + count);
+ if (size) {
+ char *xattr_unmapped = (char *)(xattr_ace + count);
+
+ if (xattr_unmapped[size - 1] != 0)
+ goto fail_einval;
+ memcpy(unmapped, xattr_unmapped, size);
+ }
+ offset = 0;
+
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);
@@ -74,6 +86,15 @@ richacl_from_xattr(struct user_namespace *user_ns,
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_UNMAPPED_WHO) {
+ size_t sz;
+
+ if (offset == size)
+ goto fail_einval;
+ ace->e_id.offs = offset;
+ sz = strlen(unmapped) + 1;
+ unmapped += sz;
+ offset += sz;
} else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) {
u32 id = le32_to_cpu(xattr_ace->e_id);
@@ -90,10 +111,12 @@ richacl_from_xattr(struct user_namespace *user_ns,
if (ace->e_type > RICHACE_ACCESS_DENIED_ACE_TYPE ||
(ace->e_mask & ~RICHACE_VALID_MASK))
goto fail_einval;
-
xattr_ace++;
}
+ if (offset != size)
+ goto fail_einval;
+
return acl;
fail_einval:
@@ -109,8 +132,15 @@ size_t
richacl_xattr_size(const struct richacl *acl)
{
size_t size = sizeof(struct richacl_xattr);
+ const struct richace *ace;
size += sizeof(struct richace_xattr) * acl->a_count;
+ richacl_for_each_entry(ace, acl) {
+ const char *unmapped = richace_unmapped_identifier(ace, acl);
+
+ if (unmapped)
+ size += strlen(unmapped) + 1;
+ }
return size;
}
EXPORT_SYMBOL_GPL(richacl_xattr_size);
@@ -129,6 +159,7 @@ richacl_to_xattr(struct user_namespace *user_ns,
struct richace_xattr *xattr_ace;
const struct richace *ace;
size_t real_size;
+ char *xattr_unmapped;
real_size = richacl_xattr_size(acl);
if (!buffer)
@@ -145,18 +176,33 @@ richacl_to_xattr(struct user_namespace *user_ns,
xattr_acl->a_other_mask = cpu_to_le32(acl->a_other_mask);
xattr_ace = (void *)(xattr_acl + 1);
+ xattr_unmapped = (char *)(xattr_ace + acl->a_count);
richacl_for_each_entry(ace, acl) {
+ const char *who;
+
xattr_ace->e_type = cpu_to_le16(ace->e_type);
xattr_ace->e_flags = cpu_to_le16(ace->e_flags);
xattr_ace->e_mask = cpu_to_le32(ace->e_mask);
if (ace->e_flags & RICHACE_SPECIAL_WHO)
xattr_ace->e_id = cpu_to_le32(ace->e_id.special);
- else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP)
- xattr_ace->e_id =
- cpu_to_le32(from_kgid(user_ns, ace->e_id.gid));
- else
- xattr_ace->e_id =
- cpu_to_le32(from_kuid(user_ns, ace->e_id.uid));
+ else {
+ who = richace_unmapped_identifier(ace, acl);
+ if (who) {
+ size_t sz = strlen(who) + 1;
+
+ xattr_ace->e_id = 0;
+ memcpy(xattr_unmapped, who, sz);
+ xattr_unmapped += sz;
+ } else if (ace->e_flags & RICHACE_IDENTIFIER_GROUP) {
+ u32 id = from_kgid(user_ns, ace->e_id.gid);
+
+ xattr_ace->e_id = cpu_to_le32(id);
+ } else {
+ u32 id = from_kuid(user_ns, ace->e_id.uid);
+
+ xattr_ace->e_id = cpu_to_le32(id);
+ }
+ }
xattr_ace++;
}
return real_size;
@@ -262,7 +308,8 @@ static void richacl_fix_xattr_userns(
return;
count = size / sizeof(*xattr_ace);
for (; count; count--, xattr_ace++) {
- if (xattr_ace->e_flags & cpu_to_le16(RICHACE_SPECIAL_WHO))
+ if (xattr_ace->e_flags & cpu_to_le16(RICHACE_SPECIAL_WHO |
+ RICHACE_UNMAPPED_WHO))
continue;
if (xattr_ace->e_flags &
cpu_to_le16(RICHACE_IDENTIFIER_GROUP)) {
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 10bfd0f..52e5c3d 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -27,6 +27,7 @@ struct richace {
kuid_t uid;
kgid_t gid;
unsigned int special;
+ unsigned short offs; /* unmapped offset */
} e_id;
};
@@ -37,6 +38,7 @@ struct richacl {
unsigned int a_other_mask;
unsigned short a_count;
unsigned short a_flags;
+ unsigned short a_unmapped_size;
struct richace a_entries[0];
};
@@ -182,14 +184,28 @@ richace_is_deny(const struct richace *ace)
* richace_is_same_identifier - are both identifiers the same?
*/
static inline bool
-richace_is_same_identifier(const struct richace *a, const struct richace *b)
+richace_is_same_identifier(const struct richacl *acl,
+ const struct richace *ace1,
+ const struct richace *ace2)
{
- return !((a->e_flags ^ b->e_flags) &
- (RICHACE_SPECIAL_WHO | RICHACE_IDENTIFIER_GROUP)) &&
- !memcmp(&a->e_id, &b->e_id, sizeof(a->e_id));
+ const char *unmapped = (char *)(acl->a_entries + acl->a_count);
+
+ return !((ace1->e_flags ^ ace2->e_flags) &
+ (RICHACE_SPECIAL_WHO |
+ RICHACE_IDENTIFIER_GROUP |
+ RICHACE_UNMAPPED_WHO)) &&
+ ((ace1->e_flags & RICHACE_UNMAPPED_WHO) ?
+ !strcmp(unmapped + ace1->e_id.offs,
+ unmapped + ace2->e_id.offs) :
+ !memcmp(&ace1->e_id, &ace2->e_id, sizeof(ace1->e_id)));
+}
+
+extern struct richacl *__richacl_alloc(unsigned int, size_t, gfp_t);
+static inline struct richacl *richacl_alloc(unsigned int count, gfp_t gfp)
+{
+ return __richacl_alloc(count, 0, gfp);
}
-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 *);
@@ -199,6 +215,11 @@ 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);
+extern int richacl_add_unmapped_identifier(struct richacl **, struct richace **,
+ const char *, unsigned int, gfp_t);
+extern const char *richace_unmapped_identifier(const struct richace *,
+ const struct richacl *);
+extern bool richacl_has_unmapped_identifiers(struct richacl *);
/* richacl_inode.c */
extern int richacl_permission(struct inode *, const struct richacl *, int);
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
index 8849a53..132fee1 100644
--- a/include/uapi/linux/richacl.h
+++ b/include/uapi/linux/richacl.h
@@ -35,6 +35,7 @@
#define RICHACE_INHERIT_ONLY_ACE 0x0008
#define RICHACE_IDENTIFIER_GROUP 0x0040
#define RICHACE_INHERITED_ACE 0x0080
+#define RICHACE_UNMAPPED_WHO 0x2000
#define RICHACE_SPECIAL_WHO 0x4000
/* e_mask bitflags */
@@ -77,6 +78,7 @@
RICHACE_INHERIT_ONLY_ACE | \
RICHACE_IDENTIFIER_GROUP | \
RICHACE_INHERITED_ACE | \
+ RICHACE_UNMAPPED_WHO | \
RICHACE_SPECIAL_WHO )
#define RICHACE_INHERITANCE_FLAGS ( \
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 38/51] nfsd: Add richacl support |
| Message-ID | <qqLH6-4sG-71@gated-at.bofh.it> |
| In reply to | #1261574 |
On file systems with richacls enabled, get and set richacls directly
instead of converting from / to posix acls.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Acked-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/acl.h | 3 +-
fs/nfsd/nfs4acl.c | 124 ++++++++++++++++++++++++++++++++++++++---------------
fs/nfsd/nfs4proc.c | 2 +-
fs/nfsd/nfs4xdr.c | 34 +++++++++++----
4 files changed, 117 insertions(+), 46 deletions(-)
diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h
index 1c5deb5..d73c664 100644
--- a/fs/nfsd/acl.h
+++ b/fs/nfsd/acl.h
@@ -53,8 +53,7 @@ __be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp,
__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp,
struct richace *ace);
-int nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
- struct richacl **acl);
+struct richacl *nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry);
__be32 nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct richacl *acl);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 6d3bb72..f017a76 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -40,6 +40,8 @@
#include <linux/nfs_fs.h>
#include <linux/richacl_compat.h>
#include <linux/nfs4acl.h>
+#include <linux/xattr.h>
+#include <linux/richacl_xattr.h>
#include "nfsfh.h"
#include "nfsd.h"
@@ -129,32 +131,28 @@ static short ace2type(struct richace *);
static void _posix_to_richacl_one(struct posix_acl *, struct richacl_alloc *,
unsigned int);
-int
-nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
- struct richacl **acl)
+static struct richacl *
+nfsd4_get_posix_acl(struct svc_rqst *rqstp, struct dentry *dentry)
{
struct inode *inode = d_inode(dentry);
- int error = 0;
struct posix_acl *pacl = NULL, *dpacl = NULL;
struct richacl_alloc alloc;
unsigned int flags = 0;
int count;
pacl = get_acl(inode, ACL_TYPE_ACCESS);
- if (!pacl)
- pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
-
- if (IS_ERR(pacl))
- return PTR_ERR(pacl);
+ if (IS_ERR_OR_NULL(pacl))
+ return (void *)pacl;
- /* allocate for worst case: one (deny, allow) pair each: */
+ /* Allocate for worst case: one (deny, allow) pair each. The resulting
+ acl will be released shortly and won't be cached. */
count = 2 * pacl->a_count;
if (S_ISDIR(inode->i_mode)) {
flags = FLAG_DIRECTORY;
dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(dpacl)) {
- error = PTR_ERR(dpacl);
+ alloc.acl = (void *)dpacl;
goto rel_pacl;
}
@@ -163,7 +161,7 @@ nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
}
if (!richacl_prepare(&alloc, count)) {
- error = -ENOMEM;
+ alloc.acl = ERR_PTR(-ENOMEM);
goto out;
}
@@ -172,13 +170,37 @@ nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
if (dpacl)
_posix_to_richacl_one(dpacl, &alloc, flags | FLAG_DEFAULT_ACL);
- *acl = alloc.acl;
-
out:
posix_acl_release(dpacl);
rel_pacl:
posix_acl_release(pacl);
- return error;
+ return alloc.acl;
+}
+
+struct richacl *
+nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry)
+{
+ struct inode *inode = d_inode(dentry);
+ struct richacl *acl;
+ int error;
+
+ if (IS_RICHACL(inode))
+ acl = get_richacl(inode);
+ else
+ acl = nfsd4_get_posix_acl(rqstp, dentry);
+ if (IS_ERR(acl))
+ return acl;
+ else if (acl == NULL) {
+ acl = richacl_from_mode(inode->i_mode);
+ if (acl == NULL)
+ acl = ERR_PTR(-ENOMEM);
+ }
+ error = richacl_apply_masks(&acl, inode->i_uid);
+ if (error) {
+ richacl_put(acl);
+ acl = ERR_PTR(error);
+ }
+ return acl;
}
struct posix_acl_summary {
@@ -744,56 +766,88 @@ out_estate:
return ret;
}
-__be32
-nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl)
+static int
+nfsd4_set_posix_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+ struct richacl *acl)
{
- __be32 error;
int host_error;
- struct dentry *dentry;
- struct inode *inode;
+ struct inode *inode = d_inode(dentry);
struct posix_acl *pacl = NULL, *dpacl = NULL;
unsigned int flags = 0;
- /* Get inode */
- error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
- if (error)
- return error;
-
- dentry = fhp->fh_dentry;
- inode = d_inode(dentry);
-
if (!inode->i_op->set_acl || !IS_POSIXACL(inode))
- return nfserr_attrnotsupp;
+ return -EOPNOTSUPP;
if (S_ISDIR(inode->i_mode))
flags = FLAG_DIRECTORY;
host_error = nfs4_richacl_to_posix(acl, &pacl, &dpacl, flags);
if (host_error == -EINVAL)
- return nfserr_attrnotsupp;
+ return -EOPNOTSUPP;
if (host_error < 0)
- goto out_nfserr;
+ return host_error;
host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS);
if (host_error < 0)
goto out_release;
- if (S_ISDIR(inode->i_mode)) {
+ if (S_ISDIR(inode->i_mode))
host_error = inode->i_op->set_acl(inode, dpacl,
ACL_TYPE_DEFAULT);
- }
out_release:
posix_acl_release(pacl);
posix_acl_release(dpacl);
-out_nfserr:
+ return host_error;
+}
+
+static int
+nfsd4_set_richacl(struct svc_rqst *rqstp, struct dentry *dentry,
+ struct richacl *acl)
+{
+ int host_error;
+ struct inode *inode = d_inode(dentry);
+ size_t size = richacl_xattr_size(acl);
+ char *buffer;
+
+ if (!inode->i_op->setxattr || !IS_RICHACL(inode))
+ return -EOPNOTSUPP;
+
+ richacl_compute_max_masks(acl);
+
+ buffer = kmalloc(size, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ richacl_to_xattr(&init_user_ns, acl, buffer, size);
+ host_error = inode->i_op->setxattr(dentry, XATTR_NAME_RICHACL,
+ buffer, size, 0);
+ kfree(buffer);
+ return host_error;
+}
+
+__be32
+nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl)
+{
+ struct dentry *dentry;
+ int host_error;
+ __be32 error;
+
+ error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
+ if (error)
+ return error;
+ dentry = fhp->fh_dentry;
+
+ if (IS_RICHACL(d_inode(dentry)))
+ host_error = nfsd4_set_richacl(rqstp, dentry, acl);
+ else
+ host_error = nfsd4_set_posix_acl(rqstp, dentry, acl);
+
if (host_error == -EOPNOTSUPP)
return nfserr_attrnotsupp;
else
return nfserrno(host_error);
}
-
static short
ace2type(struct richace *ace)
{
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 2430235..1bcfda2 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -110,7 +110,7 @@ check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
* in current environment or not.
*/
if (bmval[0] & FATTR4_WORD0_ACL) {
- if (!IS_POSIXACL(d_inode(dentry)))
+ if (!IS_ACL(d_inode(dentry)))
return nfserr_attrnotsupp;
}
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 8603f40..682a7d8 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -340,11 +340,24 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
richacl_for_each_entry(ace, *acl) {
READ_BUF(16); len += 16;
- ace->e_type = be32_to_cpup(p++);
- ace->e_flags = be32_to_cpup(p++);
- ace->e_mask = be32_to_cpup(p++);
- if (ace->e_flags & RICHACE_SPECIAL_WHO)
+
+ dummy32 = be32_to_cpup(p++);
+ if (dummy32 > RICHACE_ACCESS_DENIED_ACE_TYPE)
+ return nfserr_inval;
+ ace->e_type = dummy32;
+
+ dummy32 = be32_to_cpup(p++);
+ if (dummy32 & (~RICHACE_VALID_FLAGS |
+ RICHACE_INHERITED_ACE |
+ RICHACE_SPECIAL_WHO))
return nfserr_inval;
+ ace->e_flags = dummy32;
+
+ dummy32 = be32_to_cpup(p++);
+ if (dummy32 & ~NFS4_ACE_MASK_ALL)
+ return nfserr_inval;
+ ace->e_mask = dummy32;
+
dummy32 = be32_to_cpup(p++);
READ_BUF(dummy32);
len += XDR_QUADLEN(dummy32) << 2;
@@ -2330,7 +2343,11 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
fhp = tempfh;
}
if (bmval0 & FATTR4_WORD0_ACL) {
- err = nfsd4_get_acl(rqstp, dentry, &acl);
+ acl = nfsd4_get_acl(rqstp, dentry);
+ if (IS_ERR(acl)) {
+ err = PTR_ERR(acl);
+ acl = NULL;
+ }
if (err == -EOPNOTSUPP)
bmval0 &= ~FATTR4_WORD0_ACL;
else if (err == -EINVAL) {
@@ -2370,7 +2387,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
u32 word1 = nfsd_suppattrs1(minorversion);
u32 word2 = nfsd_suppattrs2(minorversion);
- if (!IS_POSIXACL(dentry->d_inode))
+ if (!IS_ACL(d_inode(dentry)))
word0 &= ~FATTR4_WORD0_ACL;
if (!contextsupport)
word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -2505,7 +2522,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
if (!p)
goto out_resource;
*p++ = cpu_to_be32(ace->e_type);
- *p++ = cpu_to_be32(ace->e_flags & ~RICHACE_SPECIAL_WHO);
+ *p++ = cpu_to_be32(ace->e_flags &
+ ~(RICHACE_SPECIAL_WHO | RICHACE_INHERITED_ACE));
*p++ = cpu_to_be32(ace->e_mask & NFS4_ACE_MASK_ALL);
status = nfsd4_encode_ace_who(xdr, rqstp, ace);
if (status)
@@ -2517,7 +2535,7 @@ out_acl:
p = xdr_reserve_space(xdr, 4);
if (!p)
goto out_resource;
- *p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ?
+ *p++ = cpu_to_be32(IS_ACL(d_inode(dentry)) ?
ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
}
if (bmval0 & FATTR4_WORD0_CANSETTIME) {
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:30 +0100 |
| Subject | [PATCH v13 36/51] nfsd: Keep list of acls to dispose of in compoundargs |
| Message-ID | <qqLH6-4sG-75@gated-at.bofh.it> |
| In reply to | #1261574 |
We will decode acls in requests into richacls. Even if unlikely, there
can be more than one acl in a single request; those richacls need to be
richacl_put() at the end of the request instead of kfree()d, so keep a
list of acls in compoundargs for that.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Acked-by: J. Bruce Fields <bfields@redhat.com>
---
fs/nfsd/nfs4xdr.c | 27 +++++++++++++++++++++++++++
fs/nfsd/xdr4.h | 6 ++++++
2 files changed, 33 insertions(+)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 51c9e9c..b8db5a7 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -40,6 +40,7 @@
#include <linux/utsname.h>
#include <linux/pagemap.h>
#include <linux/sunrpc/svcauth_gss.h>
+#include <linux/richacl.h>
#include "idmap.h"
#include "acl.h"
@@ -196,6 +197,24 @@ svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
return tb->buf;
}
+static struct richacl *
+svcxdr_alloc_richacl(struct nfsd4_compoundargs *argp, u32 nace)
+{
+ struct svcxdr_richacl *acls;
+
+ acls = kmalloc(sizeof(*acls), GFP_KERNEL);
+ if (!acls)
+ return NULL;
+ acls->acl = richacl_alloc(nace, GFP_KERNEL);
+ if (!acls->acl) {
+ kfree(acls);
+ return NULL;
+ }
+ acls->next = argp->acls;
+ argp->acls = acls;
+ return acls->acl;
+}
+
/*
* For xdr strings that need to be passed to other kernel api's
* as null-terminated strings.
@@ -4437,6 +4456,13 @@ int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
args->to_free = tb->next;
kfree(tb);
}
+ while (args->acls) {
+ struct svcxdr_richacl *acls = args->acls;
+
+ args->acls = acls->next;
+ richacl_put(acls->acl);
+ kfree(acls);
+ }
return 1;
}
@@ -4455,6 +4481,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_comp
args->pagelen = rqstp->rq_arg.page_len;
args->tmpp = NULL;
args->to_free = NULL;
+ args->acls = NULL;
args->ops = args->iops;
args->rqstp = rqstp;
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 9f99100..b698585 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -570,6 +570,11 @@ struct svcxdr_tmpbuf {
char buf[];
};
+struct svcxdr_richacl {
+ struct svcxdr_richacl *next;
+ struct richacl *acl;
+};
+
struct nfsd4_compoundargs {
/* scratch variables for XDR decode */
__be32 * p;
@@ -579,6 +584,7 @@ struct nfsd4_compoundargs {
__be32 tmp[8];
__be32 * tmpp;
struct svcxdr_tmpbuf *to_free;
+ struct svcxdr_richacl *acls;
struct svc_rqst *rqstp;
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:40 +0100 |
| Subject | [PATCH v13 37/51] nfsd: Use richacls as internal acl representation |
| Message-ID | <qqLQJ-4xa-1@gated-at.bofh.it> |
| In reply to | #1261574 |
When converting from NFSv4 ACLs to POSIX ACLs, nfsd so far was using
struct nfs4_acl as its internal representation. This representation is a
subset of richacls, so get rid of struct nfs4_acl. Richacls even have a
more compact in-memory representation, so a few more ACL entries can
easily be supported.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Acked-by: J. Bruce Fields <bfields@redhat.com>
---
fs/Kconfig | 6 +
fs/nfs_common/Makefile | 1 +
fs/nfs_common/nfs4acl.c | 44 ++++++
fs/nfsd/Kconfig | 1 +
fs/nfsd/acl.h | 24 ++--
fs/nfsd/nfs4acl.c | 368 ++++++++++++++++++++++--------------------------
fs/nfsd/nfs4proc.c | 15 +-
fs/nfsd/nfs4xdr.c | 64 +++------
fs/nfsd/xdr4.h | 6 +-
include/linux/nfs4.h | 23 ---
include/linux/nfs4acl.h | 7 +
11 files changed, 274 insertions(+), 285 deletions(-)
create mode 100644 fs/nfs_common/nfs4acl.c
create mode 100644 include/linux/nfs4acl.h
diff --git a/fs/Kconfig b/fs/Kconfig
index bff2879..68bc3e1 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -265,6 +265,12 @@ config NFS_COMMON
depends on NFSD || NFS_FS || LOCKD
default y
+config NFS_RICHACL
+ bool
+ depends on NFSD_V4 || NFS_V4
+ select FS_RICHACL
+ default y
+
source "net/sunrpc/Kconfig"
source "fs/ceph/Kconfig"
source "fs/cifs/Kconfig"
diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile
index d153ca3..e055139 100644
--- a/fs/nfs_common/Makefile
+++ b/fs/nfs_common/Makefile
@@ -4,5 +4,6 @@
obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o
nfs_acl-objs := nfsacl.o
+obj-$(CONFIG_NFS_RICHACL) += nfs4acl.o
obj-$(CONFIG_GRACE_PERIOD) += grace.o
diff --git a/fs/nfs_common/nfs4acl.c b/fs/nfs_common/nfs4acl.c
new file mode 100644
index 0000000..02df064
--- /dev/null
+++ b/fs/nfs_common/nfs4acl.c
@@ -0,0 +1,44 @@
+#include <linux/fs.h>
+#include <linux/richacl.h>
+#include <linux/nfs4acl.h>
+
+static struct special_id {
+ char *who;
+ int len;
+} special_who_map[] = {
+ [RICHACE_OWNER_SPECIAL_ID] = {
+ .who = "OWNER@",
+ .len = sizeof("OWNER@") - 1 },
+ [RICHACE_GROUP_SPECIAL_ID] = {
+ .who = "GROUP@",
+ .len = sizeof("GROUP@") - 1 },
+ [RICHACE_EVERYONE_SPECIAL_ID] = {
+ .who = "EVERYONE@",
+ .len = sizeof("EVERYONE@") - 1 }
+};
+
+int nfs4acl_who_to_special_id(const char *who, u32 len)
+{
+ int n;
+
+ for (n = 0; n < ARRAY_SIZE(special_who_map); n++) {
+ if (len == special_who_map[n].len &&
+ !memcmp(who, special_who_map[n].who, len))
+ return n;
+ }
+ return -1;
+}
+EXPORT_SYMBOL(nfs4acl_who_to_special_id);
+
+bool nfs4acl_special_id_to_who(unsigned int special_who,
+ const char **who, unsigned int *len)
+{
+ struct special_id *special = &special_who_map[special_who];
+
+ if (special_who > ARRAY_SIZE(special_who_map) || !special->len)
+ return false;
+ *who = special->who;
+ *len = special->len;
+ return true;
+}
+EXPORT_SYMBOL(nfs4acl_special_id_to_who);
diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig
index a0b77fc..811379a 100644
--- a/fs/nfsd/Kconfig
+++ b/fs/nfsd/Kconfig
@@ -70,6 +70,7 @@ config NFSD_V4
depends on NFSD && PROC_FS
select NFSD_V3
select FS_POSIX_ACL
+ select FS_RICHACL
select SUNRPC_GSS
select CRYPTO
select GRACE_PERIOD
diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h
index 4cd7c69..1c5deb5 100644
--- a/fs/nfsd/acl.h
+++ b/fs/nfsd/acl.h
@@ -35,25 +35,27 @@
#ifndef LINUX_NFS4_ACL_H
#define LINUX_NFS4_ACL_H
-struct nfs4_acl;
+struct richacl;
+struct richace;
struct svc_fh;
struct svc_rqst;
/*
* Maximum ACL we'll accept from a client; chosen (somewhat
* arbitrarily) so that kmalloc'ing the ACL shouldn't require a
- * high-order allocation. This allows 204 ACEs on x86_64:
+ * high-order allocation. This allows 339 ACEs on x86_64:
*/
-#define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \
- / sizeof(struct nfs4_ace))
+#define NFSD4_ACL_MAX ((PAGE_SIZE - sizeof(struct richacl)) \
+ / sizeof(struct richace))
-int nfs4_acl_bytes(int entries);
-int nfs4_acl_get_whotype(char *, u32);
-__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who);
+__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp,
+ char *who, u32 len);
+__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp,
+ struct richace *ace);
-int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
- struct nfs4_acl **acl);
-__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl);
+int nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+ struct richacl **acl);
+__be32 nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct richacl *acl);
#endif /* LINUX_NFS4_ACL_H */
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 6adabd6..6d3bb72 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -37,46 +37,50 @@
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/posix_acl.h>
+#include <linux/nfs_fs.h>
+#include <linux/richacl_compat.h>
+#include <linux/nfs4acl.h>
#include "nfsfh.h"
#include "nfsd.h"
+#include "idmap.h"
#include "acl.h"
#include "vfs.h"
-#define NFS4_ACL_TYPE_DEFAULT 0x01
-#define NFS4_ACL_DIR 0x02
-#define NFS4_ACL_OWNER 0x04
+#define FLAG_DEFAULT_ACL 0x01
+#define FLAG_DIRECTORY 0x02
+#define FLAG_OWNER 0x04
/* mode bit translations: */
-#define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
-#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)
-#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
-#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
-#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
+#define RICHACE_READ_MODE (RICHACE_READ_DATA)
+#define RICHACE_WRITE_MODE (RICHACE_WRITE_DATA | RICHACE_APPEND_DATA)
+#define RICHACE_EXECUTE_MODE RICHACE_EXECUTE
+#define RICHACE_ANYONE_MODE (RICHACE_READ_ATTRIBUTES | RICHACE_READ_ACL | RICHACE_SYNCHRONIZE)
+#define RICHACE_OWNER_MODE (RICHACE_WRITE_ATTRIBUTES | RICHACE_WRITE_ACL)
/* flags used to simulate posix default ACLs */
-#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
- | NFS4_ACE_DIRECTORY_INHERIT_ACE)
-
-#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \
- | NFS4_ACE_INHERIT_ONLY_ACE \
- | NFS4_ACE_IDENTIFIER_GROUP)
+#define RICHACE_SUPPORTED_FLAGS ( \
+ RICHACE_FILE_INHERIT_ACE | \
+ RICHACE_DIRECTORY_INHERIT_ACE | \
+ RICHACE_INHERIT_ONLY_ACE | \
+ RICHACE_IDENTIFIER_GROUP | \
+ RICHACE_SPECIAL_WHO)
static u32
mask_from_posix(unsigned short perm, unsigned int flags)
{
- int mask = NFS4_ANYONE_MODE;
+ int mask = RICHACE_ANYONE_MODE;
- if (flags & NFS4_ACL_OWNER)
- mask |= NFS4_OWNER_MODE;
+ if (flags & FLAG_OWNER)
+ mask |= RICHACE_OWNER_MODE;
if (perm & ACL_READ)
- mask |= NFS4_READ_MODE;
+ mask |= RICHACE_READ_MODE;
if (perm & ACL_WRITE)
- mask |= NFS4_WRITE_MODE;
- if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
- mask |= NFS4_ACE_DELETE_CHILD;
+ mask |= RICHACE_WRITE_MODE;
+ if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY))
+ mask |= RICHACE_DELETE_CHILD;
if (perm & ACL_EXECUTE)
- mask |= NFS4_EXECUTE_MODE;
+ mask |= RICHACE_EXECUTE_MODE;
return mask;
}
@@ -86,13 +90,13 @@ deny_mask_from_posix(unsigned short perm, u32 flags)
u32 mask = 0;
if (perm & ACL_READ)
- mask |= NFS4_READ_MODE;
+ mask |= RICHACE_READ_MODE;
if (perm & ACL_WRITE)
- mask |= NFS4_WRITE_MODE;
- if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
- mask |= NFS4_ACE_DELETE_CHILD;
+ mask |= RICHACE_WRITE_MODE;
+ if ((perm & ACL_WRITE) && (flags & FLAG_DIRECTORY))
+ mask |= RICHACE_DELETE_CHILD;
if (perm & ACL_EXECUTE)
- mask |= NFS4_EXECUTE_MODE;
+ mask |= RICHACE_EXECUTE_MODE;
return mask;
}
@@ -108,32 +112,33 @@ deny_mask_from_posix(unsigned short perm, u32 flags)
static void
low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
{
- u32 write_mode = NFS4_WRITE_MODE;
+ u32 write_mode = RICHACE_WRITE_MODE;
- if (flags & NFS4_ACL_DIR)
- write_mode |= NFS4_ACE_DELETE_CHILD;
+ if (flags & FLAG_DIRECTORY)
+ write_mode |= RICHACE_DELETE_CHILD;
*mode = 0;
- if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
+ if ((perm & RICHACE_READ_MODE) == RICHACE_READ_MODE)
*mode |= ACL_READ;
if ((perm & write_mode) == write_mode)
*mode |= ACL_WRITE;
- if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
+ if ((perm & RICHACE_EXECUTE_MODE) == RICHACE_EXECUTE_MODE)
*mode |= ACL_EXECUTE;
}
-static short ace2type(struct nfs4_ace *);
-static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
+static short ace2type(struct richace *);
+static void _posix_to_richacl_one(struct posix_acl *, struct richacl_alloc *,
unsigned int);
int
-nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
- struct nfs4_acl **acl)
+nfsd4_get_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+ struct richacl **acl)
{
struct inode *inode = d_inode(dentry);
int error = 0;
struct posix_acl *pacl = NULL, *dpacl = NULL;
+ struct richacl_alloc alloc;
unsigned int flags = 0;
- int size = 0;
+ int count;
pacl = get_acl(inode, ACL_TYPE_ACCESS);
if (!pacl)
@@ -143,10 +148,10 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
return PTR_ERR(pacl);
/* allocate for worst case: one (deny, allow) pair each: */
- size += 2 * pacl->a_count;
+ count = 2 * pacl->a_count;
if (S_ISDIR(inode->i_mode)) {
- flags = NFS4_ACL_DIR;
+ flags = FLAG_DIRECTORY;
dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
if (IS_ERR(dpacl)) {
error = PTR_ERR(dpacl);
@@ -154,20 +159,20 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
}
if (dpacl)
- size += 2 * dpacl->a_count;
+ count += 2 * dpacl->a_count;
}
- *acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL);
- if (*acl == NULL) {
+ if (!richacl_prepare(&alloc, count)) {
error = -ENOMEM;
goto out;
}
- (*acl)->naces = 0;
- _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
+ _posix_to_richacl_one(pacl, &alloc, flags);
if (dpacl)
- _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT);
+ _posix_to_richacl_one(dpacl, &alloc, flags | FLAG_DEFAULT_ACL);
+
+ *acl = alloc.acl;
out:
posix_acl_release(dpacl);
@@ -230,21 +235,22 @@ summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
/* We assume the acl has been verified with posix_acl_valid. */
static void
-_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
- unsigned int flags)
+_posix_to_richacl_one(struct posix_acl *pacl, struct richacl_alloc *alloc,
+ unsigned int flags)
{
struct posix_acl_entry *pa, *group_owner_entry;
- struct nfs4_ace *ace;
+ struct richace *ace;
struct posix_acl_summary pas;
unsigned short deny;
- int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
- NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0);
+ int e_flags = ((flags & FLAG_DEFAULT_ACL) ?
+ (RICHACE_FILE_INHERIT_ACE |
+ RICHACE_DIRECTORY_INHERIT_ACE |
+ RICHACE_INHERIT_ONLY_ACE) : 0);
BUG_ON(pacl->a_count < 3);
summarize_posix_acl(pacl, &pas);
pa = pacl->a_entries;
- ace = acl->aces + acl->naces;
/* We could deny everything not granted by the owner: */
deny = ~pas.owner;
@@ -254,42 +260,35 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
*/
deny &= pas.users | pas.group | pas.groups | pas.other;
if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_OWNER;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+ ace->e_flags = e_flags | RICHACE_SPECIAL_WHO;
+ ace->e_mask = deny_mask_from_posix(deny, flags);
+ ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
}
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
- ace->whotype = NFS4_ACL_WHO_OWNER;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = e_flags | RICHACE_SPECIAL_WHO;
+ ace->e_mask = mask_from_posix(pa->e_perm, flags | FLAG_OWNER);
+ ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
pa++;
while (pa->e_tag == ACL_USER) {
deny = ~(pa->e_perm & pas.mask);
deny &= pas.groups | pas.group | pas.other;
if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who_uid = pa->e_uid;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+ ace->e_flags = e_flags;
+ ace->e_mask = deny_mask_from_posix(deny, flags);
+ ace->e_id.uid = pa->e_uid;
}
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
- flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who_uid = pa->e_uid;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = e_flags;
+ ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags);
+ ace->e_id.uid = pa->e_uid;
pa++;
}
@@ -300,23 +299,19 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
group_owner_entry = pa;
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pas.group, flags);
- ace->whotype = NFS4_ACL_WHO_GROUP;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = e_flags | RICHACE_SPECIAL_WHO;
+ ace->e_mask = mask_from_posix(pas.group, flags);
+ ace->e_id.special = RICHACE_GROUP_SPECIAL_ID;
pa++;
while (pa->e_tag == ACL_GROUP) {
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
- ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
- flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who_gid = pa->e_gid;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP;
+ ace->e_mask = mask_from_posix(pa->e_perm & pas.mask, flags);
+ ace->e_id.gid = pa->e_gid;
pa++;
}
@@ -326,12 +321,11 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
deny = ~pas.group & pas.other;
if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_GROUP;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+ ace->e_flags = e_flags | RICHACE_SPECIAL_WHO;
+ ace->e_mask = deny_mask_from_posix(deny, flags);
+ ace->e_id.special = RICHACE_GROUP_SPECIAL_ID;
}
pa++;
@@ -339,24 +333,22 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
deny = ~(pa->e_perm & pas.mask);
deny &= pas.other;
if (deny) {
- ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
- ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
- ace->access_mask = deny_mask_from_posix(deny, flags);
- ace->whotype = NFS4_ACL_WHO_NAMED;
- ace->who_gid = pa->e_gid;
- ace++;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+ ace->e_flags = e_flags | RICHACE_IDENTIFIER_GROUP;
+ ace->e_mask = deny_mask_from_posix(deny, flags);
+ ace->e_id.gid = pa->e_gid;
}
pa++;
}
if (pa->e_tag == ACL_MASK)
pa++;
- ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
- ace->flag = eflag;
- ace->access_mask = mask_from_posix(pa->e_perm, flags);
- ace->whotype = NFS4_ACL_WHO_EVERYONE;
- acl->naces++;
+ ace = richacl_append_entry(alloc);
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = e_flags | RICHACE_SPECIAL_WHO;
+ ace->e_mask = mask_from_posix(pa->e_perm, flags);
+ ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID;
}
static bool
@@ -500,7 +492,7 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
* and effective cases: when there are no inheritable ACEs,
* calls ->set_acl with a NULL ACL structure.
*/
- if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT))
+ if (state->empty && (flags & FLAG_DEFAULT_ACL))
return NULL;
/*
@@ -619,24 +611,24 @@ static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
}
static void process_one_v4_ace(struct posix_acl_state *state,
- struct nfs4_ace *ace)
+ struct richace *ace)
{
- u32 mask = ace->access_mask;
+ u32 mask = ace->e_mask;
int i;
state->empty = 0;
switch (ace2type(ace)) {
case ACL_USER_OBJ:
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->owner, mask);
} else {
deny_bits(&state->owner, mask);
}
break;
case ACL_USER:
- i = find_uid(state, ace->who_uid);
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ i = find_uid(state, ace->e_id.uid);
+ if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->users->aces[i].perms, mask);
} else {
deny_bits(&state->users->aces[i].perms, mask);
@@ -645,7 +637,7 @@ static void process_one_v4_ace(struct posix_acl_state *state,
}
break;
case ACL_GROUP_OBJ:
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->group, mask);
} else {
deny_bits(&state->group, mask);
@@ -657,8 +649,8 @@ static void process_one_v4_ace(struct posix_acl_state *state,
}
break;
case ACL_GROUP:
- i = find_gid(state, ace->who_gid);
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ i = find_gid(state, ace->e_id.gid);
+ if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->groups->aces[i].perms, mask);
} else {
deny_bits(&state->groups->aces[i].perms, mask);
@@ -671,7 +663,7 @@ static void process_one_v4_ace(struct posix_acl_state *state,
}
break;
case ACL_OTHER:
- if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ if (ace->e_type == RICHACE_ACCESS_ALLOWED_ACE_TYPE) {
allow_bits(&state->owner, mask);
allow_bits(&state->group, mask);
allow_bits(&state->other, mask);
@@ -689,32 +681,33 @@ static void process_one_v4_ace(struct posix_acl_state *state,
}
}
-static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
+static int nfs4_richacl_to_posix(struct richacl *acl,
struct posix_acl **pacl, struct posix_acl **dpacl,
unsigned int flags)
{
struct posix_acl_state effective_acl_state, default_acl_state;
- struct nfs4_ace *ace;
+ struct richace *ace;
int ret;
- ret = init_state(&effective_acl_state, acl->naces);
+ ret = init_state(&effective_acl_state, acl->a_count);
if (ret)
return ret;
- ret = init_state(&default_acl_state, acl->naces);
+ ret = init_state(&default_acl_state, acl->a_count);
if (ret)
goto out_estate;
ret = -EINVAL;
- for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
- ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+ richacl_for_each_entry(ace, acl) {
+ if (ace->e_type != RICHACE_ACCESS_ALLOWED_ACE_TYPE &&
+ ace->e_type != RICHACE_ACCESS_DENIED_ACE_TYPE)
goto out_dstate;
- if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
+ if (ace->e_flags & ~RICHACE_SUPPORTED_FLAGS)
goto out_dstate;
- if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) {
+ if ((ace->e_flags & (RICHACE_FILE_INHERIT_ACE |
+ RICHACE_DIRECTORY_INHERIT_ACE)) == 0) {
process_one_v4_ace(&effective_acl_state, ace);
continue;
}
- if (!(flags & NFS4_ACL_DIR))
+ if (!(flags & FLAG_DIRECTORY))
goto out_dstate;
/*
* Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT
@@ -723,7 +716,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
*/
process_one_v4_ace(&default_acl_state, ace);
- if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE))
+ if (!(ace->e_flags & RICHACE_INHERIT_ONLY_ACE))
process_one_v4_ace(&effective_acl_state, ace);
}
*pacl = posix_state_to_acl(&effective_acl_state, flags);
@@ -733,7 +726,7 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
goto out_dstate;
}
*dpacl = posix_state_to_acl(&default_acl_state,
- flags | NFS4_ACL_TYPE_DEFAULT);
+ flags | FLAG_DEFAULT_ACL);
if (IS_ERR(*dpacl)) {
ret = PTR_ERR(*dpacl);
*dpacl = NULL;
@@ -752,8 +745,7 @@ out_estate:
}
__be32
-nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl)
+nfsd4_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl)
{
__be32 error;
int host_error;
@@ -774,9 +766,9 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
return nfserr_attrnotsupp;
if (S_ISDIR(inode->i_mode))
- flags = NFS4_ACL_DIR;
+ flags = FLAG_DIRECTORY;
- host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+ host_error = nfs4_richacl_to_posix(acl, &pacl, &dpacl, flags);
if (host_error == -EINVAL)
return nfserr_attrnotsupp;
if (host_error < 0)
@@ -803,82 +795,62 @@ out_nfserr:
static short
-ace2type(struct nfs4_ace *ace)
+ace2type(struct richace *ace)
{
- switch (ace->whotype) {
- case NFS4_ACL_WHO_NAMED:
- return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
- ACL_GROUP : ACL_USER);
- case NFS4_ACL_WHO_OWNER:
+ if (ace->e_flags & RICHACE_SPECIAL_WHO) {
+ switch (ace->e_id.special) {
+ case RICHACE_OWNER_SPECIAL_ID:
return ACL_USER_OBJ;
- case NFS4_ACL_WHO_GROUP:
+ case RICHACE_GROUP_SPECIAL_ID:
return ACL_GROUP_OBJ;
- case NFS4_ACL_WHO_EVERYONE:
+ case RICHACE_EVERYONE_SPECIAL_ID:
return ACL_OTHER;
+ default:
+ BUG();
+ }
}
- BUG();
- return -1;
-}
-
-/*
- * return the size of the struct nfs4_acl required to represent an acl
- * with @entries entries.
- */
-int nfs4_acl_bytes(int entries)
-{
- return sizeof(struct nfs4_acl) + entries * sizeof(struct nfs4_ace);
+ return ace->e_flags & RICHACE_IDENTIFIER_GROUP ? ACL_GROUP : ACL_USER;
}
-static struct {
- char *string;
- int stringlen;
- int type;
-} s2t_map[] = {
- {
- .string = "OWNER@",
- .stringlen = sizeof("OWNER@") - 1,
- .type = NFS4_ACL_WHO_OWNER,
- },
- {
- .string = "GROUP@",
- .stringlen = sizeof("GROUP@") - 1,
- .type = NFS4_ACL_WHO_GROUP,
- },
- {
- .string = "EVERYONE@",
- .stringlen = sizeof("EVERYONE@") - 1,
- .type = NFS4_ACL_WHO_EVERYONE,
- },
-};
-
-int
-nfs4_acl_get_whotype(char *p, u32 len)
+__be32 nfsd4_decode_ace_who(struct richace *ace, struct svc_rqst *rqstp,
+ char *who, u32 len)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
- if (s2t_map[i].stringlen == len &&
- 0 == memcmp(s2t_map[i].string, p, len))
- return s2t_map[i].type;
+ int special_id;
+
+ special_id = nfs4acl_who_to_special_id(who, len);
+ if (special_id >= 0) {
+ ace->e_flags |= RICHACE_SPECIAL_WHO;
+ ace->e_flags &= ~RICHACE_IDENTIFIER_GROUP;
+ ace->e_id.special = special_id;
+ return nfs_ok;
}
- return NFS4_ACL_WHO_NAMED;
+ if (ace->e_flags & RICHACE_IDENTIFIER_GROUP)
+ return nfsd_map_name_to_gid(rqstp, who, len, &ace->e_id.gid);
+ else
+ return nfsd_map_name_to_uid(rqstp, who, len, &ace->e_id.uid);
}
-__be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who)
+__be32 nfsd4_encode_ace_who(struct xdr_stream *xdr, struct svc_rqst *rqstp,
+ struct richace *ace)
{
- __be32 *p;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
- if (s2t_map[i].type != who)
- continue;
- p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4);
+ if (ace->e_flags & RICHACE_SPECIAL_WHO) {
+ unsigned int special_id = ace->e_id.special;
+ const char *who;
+ unsigned int len;
+ __be32 *p;
+
+ if (!nfs4acl_special_id_to_who(special_id, &who, &len)) {
+ WARN_ON_ONCE(1);
+ return nfserr_serverfault;
+ }
+ p = xdr_reserve_space(xdr, len + 4);
if (!p)
return nfserr_resource;
- p = xdr_encode_opaque(p, s2t_map[i].string,
- s2t_map[i].stringlen);
+ p = xdr_encode_opaque(p, who, len);
return 0;
}
- WARN_ON_ONCE(1);
- return nfserr_serverfault;
+ if (ace->e_flags & RICHACE_IDENTIFIER_GROUP)
+ return nfsd4_encode_group(xdr, rqstp, ace->e_id.gid);
+ else
+ return nfsd4_encode_user(xdr, rqstp, ace->e_id.uid);
}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 4ce6b97..2430235 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -159,12 +159,12 @@ is_create_with_attrs(struct nfsd4_open *open)
* in the returned attr bitmap.
*/
static void
-do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct nfs4_acl *acl, u32 *bmval)
+do_set_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, struct richacl *acl,
+ u32 *bmval)
{
__be32 status;
- status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
+ status = nfsd4_set_acl(rqstp, fhp, acl);
if (status)
/*
* We should probably fail the whole open at this point,
@@ -299,7 +299,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
goto out;
if (is_create_with_attrs(open) && open->op_acl != NULL)
- do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
+ do_set_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
accmode = NFSD_MAY_NOP;
@@ -672,8 +672,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval);
if (create->cr_acl != NULL)
- do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
- create->cr_bmval);
+ do_set_acl(rqstp, &resfh, create->cr_acl, create->cr_bmval);
fh_unlock(&cstate->current_fh);
set_change_info(&create->cr_cinfo, &cstate->current_fh);
@@ -938,8 +937,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
if (setattr->sa_acl != NULL)
- status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
- setattr->sa_acl);
+ status = nfsd4_set_acl(rqstp, &cstate->current_fh,
+ setattr->sa_acl);
if (status)
goto out;
if (setattr->sa_label.len)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index b8db5a7..8603f40 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -303,7 +303,7 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
static __be32
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
- struct iattr *iattr, struct nfs4_acl **acl,
+ struct iattr *iattr, struct richacl **acl,
struct xdr_netobj *label)
{
int expected_len, len = 0;
@@ -326,38 +326,31 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
}
if (bmval[0] & FATTR4_WORD0_ACL) {
u32 nace;
- struct nfs4_ace *ace;
+ struct richace *ace;
READ_BUF(4); len += 4;
nace = be32_to_cpup(p++);
- if (nace > NFS4_ACL_MAX)
+ if (nace > NFSD4_ACL_MAX)
return nfserr_fbig;
- *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace));
+ *acl = svcxdr_alloc_richacl(argp, nace);
if (*acl == NULL)
return nfserr_jukebox;
- (*acl)->naces = nace;
- for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
+ richacl_for_each_entry(ace, *acl) {
READ_BUF(16); len += 16;
- ace->type = be32_to_cpup(p++);
- ace->flag = be32_to_cpup(p++);
- ace->access_mask = be32_to_cpup(p++);
+ ace->e_type = be32_to_cpup(p++);
+ ace->e_flags = be32_to_cpup(p++);
+ ace->e_mask = be32_to_cpup(p++);
+ if (ace->e_flags & RICHACE_SPECIAL_WHO)
+ return nfserr_inval;
dummy32 = be32_to_cpup(p++);
READ_BUF(dummy32);
len += XDR_QUADLEN(dummy32) << 2;
READMEM(buf, dummy32);
- ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
- status = nfs_ok;
- if (ace->whotype != NFS4_ACL_WHO_NAMED)
- ;
- else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
- status = nfsd_map_name_to_gid(argp->rqstp,
- buf, dummy32, &ace->who_gid);
- else
- status = nfsd_map_name_to_uid(argp->rqstp,
- buf, dummy32, &ace->who_uid);
+ status = nfsd4_decode_ace_who(ace, argp->rqstp,
+ buf, dummy32);
if (status)
return status;
}
@@ -2148,18 +2141,6 @@ static u32 nfs4_file_type(umode_t mode)
}
static inline __be32
-nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
- struct nfs4_ace *ace)
-{
- if (ace->whotype != NFS4_ACL_WHO_NAMED)
- return nfs4_acl_write_who(xdr, ace->whotype);
- else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
- return nfsd4_encode_group(xdr, rqstp, ace->who_gid);
- else
- return nfsd4_encode_user(xdr, rqstp, ace->who_uid);
-}
-
-static inline __be32
nfsd4_encode_layout_type(struct xdr_stream *xdr, enum pnfs_layouttype layout_type)
{
__be32 *p;
@@ -2303,7 +2284,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
u32 rdattr_err = 0;
__be32 status;
int err;
- struct nfs4_acl *acl = NULL;
+ struct richacl *acl = NULL;
void *context = NULL;
int contextlen;
bool contextsupport = false;
@@ -2349,7 +2330,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
fhp = tempfh;
}
if (bmval0 & FATTR4_WORD0_ACL) {
- err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
+ err = nfsd4_get_acl(rqstp, dentry, &acl);
if (err == -EOPNOTSUPP)
bmval0 &= ~FATTR4_WORD0_ACL;
else if (err == -EINVAL) {
@@ -2504,7 +2485,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
*p++ = cpu_to_be32(rdattr_err);
}
if (bmval0 & FATTR4_WORD0_ACL) {
- struct nfs4_ace *ace;
+ struct richace *ace;
if (acl == NULL) {
p = xdr_reserve_space(xdr, 4);
@@ -2517,17 +2498,16 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
p = xdr_reserve_space(xdr, 4);
if (!p)
goto out_resource;
- *p++ = cpu_to_be32(acl->naces);
+ *p++ = cpu_to_be32(acl->a_count);
- for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
+ richacl_for_each_entry(ace, acl) {
p = xdr_reserve_space(xdr, 4*3);
if (!p)
goto out_resource;
- *p++ = cpu_to_be32(ace->type);
- *p++ = cpu_to_be32(ace->flag);
- *p++ = cpu_to_be32(ace->access_mask &
- NFS4_ACE_MASK_ALL);
- status = nfsd4_encode_aclname(xdr, rqstp, ace);
+ *p++ = cpu_to_be32(ace->e_type);
+ *p++ = cpu_to_be32(ace->e_flags & ~RICHACE_SPECIAL_WHO);
+ *p++ = cpu_to_be32(ace->e_mask & NFS4_ACE_MASK_ALL);
+ status = nfsd4_encode_ace_who(xdr, rqstp, ace);
if (status)
goto out;
}
@@ -2792,7 +2772,7 @@ out:
if (context)
security_release_secctx(context, contextlen);
#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
- kfree(acl);
+ richacl_put(acl);
if (tempfh) {
fh_put(tempfh);
kfree(tempfh);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index b698585..c311066 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -118,7 +118,7 @@ struct nfsd4_create {
u32 cr_bmval[3]; /* request */
struct iattr cr_iattr; /* request */
struct nfsd4_change_info cr_cinfo; /* response */
- struct nfs4_acl *cr_acl;
+ struct richacl *cr_acl;
struct xdr_netobj cr_label;
};
#define cr_datalen u.link.datalen
@@ -248,7 +248,7 @@ struct nfsd4_open {
struct nfs4_file *op_file; /* used during processing */
struct nfs4_ol_stateid *op_stp; /* used during processing */
struct nfs4_clnt_odstate *op_odstate; /* used during processing */
- struct nfs4_acl *op_acl;
+ struct richacl *op_acl;
struct xdr_netobj op_label;
};
@@ -332,7 +332,7 @@ struct nfsd4_setattr {
stateid_t sa_stateid; /* request */
u32 sa_bmval[3]; /* request */
struct iattr sa_iattr; /* request */
- struct nfs4_acl *sa_acl;
+ struct richacl *sa_acl;
struct xdr_netobj sa_label;
};
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 00121f2..1422fc6 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -16,29 +16,6 @@
#include <linux/uidgid.h>
#include <uapi/linux/nfs4.h>
-enum nfs4_acl_whotype {
- NFS4_ACL_WHO_NAMED = 0,
- NFS4_ACL_WHO_OWNER,
- NFS4_ACL_WHO_GROUP,
- NFS4_ACL_WHO_EVERYONE,
-};
-
-struct nfs4_ace {
- uint32_t type;
- uint32_t flag;
- uint32_t access_mask;
- int whotype;
- union {
- kuid_t who_uid;
- kgid_t who_gid;
- };
-};
-
-struct nfs4_acl {
- uint32_t naces;
- struct nfs4_ace aces[0];
-};
-
#define NFS4_MAXLABELLEN 2048
struct nfs4_label {
diff --git a/include/linux/nfs4acl.h b/include/linux/nfs4acl.h
new file mode 100644
index 0000000..db9f9a6
--- /dev/null
+++ b/include/linux/nfs4acl.h
@@ -0,0 +1,7 @@
+#ifndef __LINUX_NFS4ACL_H
+#define __LINUX_NFS4ACL_H
+
+int nfs4acl_who_to_special_id(const char *, u32);
+bool nfs4acl_special_id_to_who(unsigned int, const char **, unsigned int *);
+
+#endif
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:40 +0100 |
| Subject | [PATCH v13 35/51] richacl: Create richacl from mode values |
| Message-ID | <qqLQK-4xa-23@gated-at.bofh.it> |
| In reply to | #1261574 |
A file can have "no acl" in the sense that only the file mode permission
bits determine access. In that case, the getxattr system call fails with
errno == ENODATA (No such attribute).
Over the NFSv4 protocol, a file always has an acl, and we convert the file
mode permission bits into an equivalent acl with richacl_from_mode. Such
"trivial" acls can be converted back to a file mode with
richacl_equiv_mode.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl_compat.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 1 +
2 files changed, 89 insertions(+)
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index ea3effd..3a11773 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -827,3 +827,91 @@ richacl_apply_masks(struct richacl **acl, kuid_t owner)
return 0;
}
EXPORT_SYMBOL_GPL(richacl_apply_masks);
+
+/**
+ * richacl_from_mode - create an acl which corresponds to @mode
+ *
+ * The resulting acl doesn't have the RICHACL_MASKED flag set.
+ *
+ * @mode: file mode including the file type
+ */
+struct richacl *
+richacl_from_mode(umode_t mode)
+{
+ unsigned int owner_mask = richacl_mode_to_mask(mode >> 6);
+ unsigned int group_mask = richacl_mode_to_mask(mode >> 3);
+ unsigned int other_mask = richacl_mode_to_mask(mode);
+ unsigned int denied;
+ unsigned int entries = 0;
+ struct richacl *acl;
+ struct richace *ace;
+
+ /* RICHACE_DELETE_CHILD is meaningless for non-directories. */
+ if (!S_ISDIR(mode)) {
+ owner_mask &= ~RICHACE_DELETE_CHILD;
+ group_mask &= ~RICHACE_DELETE_CHILD;
+ other_mask &= ~RICHACE_DELETE_CHILD;
+ }
+
+ denied = ~owner_mask & (group_mask | other_mask);
+ if (denied)
+ entries++; /* owner@ deny entry needed */
+ if (owner_mask & ~(group_mask & other_mask))
+ entries++; /* owner@ allow entry needed */
+ denied = ~group_mask & other_mask;
+ if (denied)
+ entries++; /* group@ deny entry needed */
+ if (group_mask & ~other_mask)
+ entries++; /* group@ allow entry needed */
+ if (other_mask)
+ entries++; /* everyone@ allow entry needed */
+
+ acl = richacl_alloc(entries, GFP_KERNEL);
+ if (!acl)
+ return NULL;
+ acl->a_owner_mask = owner_mask;
+ acl->a_group_mask = group_mask;
+ acl->a_other_mask = other_mask;
+ ace = acl->a_entries;
+
+ denied = ~owner_mask & (group_mask | other_mask);
+ if (denied) {
+ ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+ ace->e_flags = RICHACE_SPECIAL_WHO;
+ ace->e_mask = denied;
+ ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
+ ace++;
+ }
+ if (owner_mask & ~(group_mask & other_mask)) {
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = RICHACE_SPECIAL_WHO;
+ ace->e_mask = owner_mask;
+ ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
+ ace++;
+ }
+ denied = ~group_mask & other_mask;
+ if (denied) {
+ ace->e_type = RICHACE_ACCESS_DENIED_ACE_TYPE;
+ ace->e_flags = RICHACE_SPECIAL_WHO;
+ ace->e_mask = denied;
+ ace->e_id.special = RICHACE_GROUP_SPECIAL_ID;
+ ace++;
+ }
+ if (group_mask & ~other_mask) {
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = RICHACE_SPECIAL_WHO;
+ ace->e_mask = group_mask;
+ ace->e_id.special = RICHACE_GROUP_SPECIAL_ID;
+ ace++;
+ }
+ if (other_mask) {
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = RICHACE_SPECIAL_WHO;
+ ace->e_mask = other_mask;
+ ace->e_id.special = RICHACE_EVERYONE_SPECIAL_ID;
+ ace++;
+ }
+
+ return acl;
+}
+EXPORT_SYMBOL_GPL(richacl_from_mode);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 3fdfc57..10bfd0f 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -207,5 +207,6 @@ extern struct richacl *richacl_create(umode_t *, struct inode *);
/* richacl_compat.c */
extern int richacl_apply_masks(struct richacl **, kuid_t);
+extern struct richacl *richacl_from_mode(umode_t);
#endif /* __RICHACL_H */
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:50 +0100 |
| Subject | [PATCH v13 31/51] richacl: Set the owner permissions to the owner mask |
| Message-ID | <qqM0p-4Hz-1@gated-at.bofh.it> |
| In reply to | #1261574 |
In the write-through case, change the acl so that owner@ is granted the
permissions set in the owner mask (to match what the permission check
algorithm grants the owner).
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl_compat.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index e90d57c..d9fee8b 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -416,3 +416,49 @@ richacl_propagate_everyone(struct richacl_alloc *alloc)
}
return 0;
}
+
+/**
+ * richacl_set_owner_permissions - set the owner permissions to the owner mask
+ *
+ * In the write-through case, change the acl so that owner@ is granted the
+ * permissions set in the owner mask (to match what the permission check
+ * algorithm grants the owner). This leaves at most one efective owner@ allow
+ * entry at the beginning of the acl.
+ */
+static int
+richacl_set_owner_permissions(struct richacl_alloc *alloc)
+{
+ unsigned int x = RICHACE_POSIX_ALWAYS_ALLOWED;
+ unsigned int owner_mask = alloc->acl->a_owner_mask & ~x;
+ unsigned int denied = 0;
+ struct richace *ace;
+
+ if (!((alloc->acl->a_flags & RICHACL_WRITE_THROUGH)))
+ return 0;
+
+ richacl_for_each_entry(ace, alloc->acl) {
+ if (richace_is_owner(ace)) {
+ if (richace_is_allow(ace) && !(owner_mask & denied)) {
+ richace_change_mask(alloc, &ace, owner_mask);
+ owner_mask = 0;
+ } else
+ richace_change_mask(alloc, &ace, 0);
+ } else {
+ if (richace_is_deny(ace))
+ denied |= ace->e_mask;
+ }
+ }
+
+ if (owner_mask & (denied |
+ ~alloc->acl->a_other_mask |
+ ~alloc->acl->a_group_mask)) {
+ ace = alloc->acl->a_entries;
+ if (richacl_insert_entry(alloc, &ace))
+ return -1;
+ ace->e_type = RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+ ace->e_flags = RICHACE_SPECIAL_WHO;
+ ace->e_mask = owner_mask;
+ ace->e_id.special = RICHACE_OWNER_SPECIAL_ID;
+ }
+ return 0;
+}
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:50 +0100 |
| Subject | [PATCH v13 34/51] richacl: Apply the file masks to a richacl |
| Message-ID | <qqM0q-4Hz-41@gated-at.bofh.it> |
| In reply to | #1261574 |
Put all the pieces of the acl transformation puzzle together for
computing a richacl which has the file masks "applied" so that the
standard nfsv4 access check algorithm can be used on the richacl.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl_compat.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 3 ++
2 files changed, 104 insertions(+)
diff --git a/fs/richacl_compat.c b/fs/richacl_compat.c
index 7553f1a..ea3effd 100644
--- a/fs/richacl_compat.c
+++ b/fs/richacl_compat.c
@@ -726,3 +726,104 @@ richacl_isolate_group_class(struct richacl_alloc *alloc, unsigned int deny)
}
return 0;
}
+
+/**
+ * __richacl_apply_masks - apply the file masks to all aces
+ * @alloc: acl and number of allocated entries
+ *
+ * Apply the owner mask to owner@ aces, the other mask to
+ * everyone@ aces, and the group mask to all other aces.
+ *
+ * The previous transformations have brought the acl into a
+ * form in which applying the masks will not lead to the
+ * accidental loss of permissions anymore.
+ */
+static int
+__richacl_apply_masks(struct richacl_alloc *alloc, kuid_t owner)
+{
+ struct richace *ace;
+
+ richacl_for_each_entry(ace, alloc->acl) {
+ unsigned int mask;
+
+ if (richace_is_inherit_only(ace) || !richace_is_allow(ace))
+ continue;
+ if (richace_is_owner(ace) ||
+ (richace_is_unix_user(ace) && uid_eq(owner, ace->e_id.uid)))
+ mask = alloc->acl->a_owner_mask;
+ else if (richace_is_everyone(ace))
+ mask = alloc->acl->a_other_mask;
+ else
+ mask = alloc->acl->a_group_mask;
+ if (richace_change_mask(alloc, &ace, ace->e_mask & mask))
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * richacl_apply_masks - apply the masks to the acl
+ *
+ * Transform @acl so that the standard NFSv4 permission check algorithm (which
+ * is not aware of file masks) will compute the same access decisions as the
+ * richacl permission check algorithm (which looks at the acl and the file
+ * masks).
+ *
+ * This algorithm is split into several steps:
+ *
+ * - Move everyone@ aces to the end of the acl. This simplifies the other
+ * transformations, and allows the everyone@ allow ace at the end of the
+ * acl to eventually allow permissions to the other class only.
+ *
+ * - Propagate everyone@ permissions up the acl. This transformation makes
+ * sure that the owner and group class aces won't lose any permissions when
+ * we apply the other mask to the everyone@ allow ace at the end of the acl.
+ *
+ * - Apply the file masks to all aces.
+ *
+ * - Make sure everyone is granted the other mask permissions. This step can
+ * elevate elevate permissions for the owner and group classes, which is
+ * corrected later.
+ *
+ * - Make sure that the group class is not granted any permissions from
+ * everyone@.
+ *
+ * - Make sure the owner is granted the owner mask permissions.
+ *
+ * - Make sure the owner is not granted any permissions beyond the owner
+ * mask from group class aces or from everyone@.
+ *
+ * NOTE: Depending on the acl and file masks, this algorithm can increase the
+ * number of aces by almost a factor of three in the worst case. This may make
+ * the acl too large for some purposes.
+ */
+int
+richacl_apply_masks(struct richacl **acl, kuid_t owner)
+{
+ if ((*acl)->a_flags & RICHACL_MASKED) {
+ struct richacl_alloc alloc = {
+ .acl = richacl_clone(*acl, GFP_KERNEL),
+ .count = (*acl)->a_count,
+ };
+ unsigned int added = 0;
+
+ if (!alloc.acl)
+ return -ENOMEM;
+ if (richacl_move_everyone_aces_down(&alloc) ||
+ richacl_propagate_everyone(&alloc) ||
+ __richacl_apply_masks(&alloc, owner) ||
+ richacl_set_other_permissions(&alloc, &added) ||
+ richacl_isolate_group_class(&alloc, added) ||
+ richacl_set_owner_permissions(&alloc) ||
+ richacl_isolate_owner_class(&alloc)) {
+ richacl_put(alloc.acl);
+ return -ENOMEM;
+ }
+
+ alloc.acl->a_flags &= ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED);
+ richacl_put(*acl);
+ *acl = alloc.acl;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(richacl_apply_masks);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 7cfa64d..3fdfc57 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -205,4 +205,7 @@ 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 *);
+/* richacl_compat.c */
+extern int richacl_apply_masks(struct richacl **, kuid_t);
+
#endif /* __RICHACL_H */
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 16:50 +0100 |
| Subject | [PATCH v13 27/51] xfs: Fix richacl access by ioctl |
| Message-ID | <qqM0r-4Hz-55@gated-at.bofh.it> |
| In reply to | #1261574 |
Make sure that the XFS_IOC_ATTRMULTI_BY_HANDLE ioctl exposes richacls in
the same way as the xattr interface: check for mode-equivalent richacls,
update the inode permission bits, and perform user namespace mapping.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/xfs/xfs_ioctl.c | 27 +++++++++++++++++++++++++++
fs/xfs/xfs_richacl.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++----
fs/xfs/xfs_richacl.h | 3 +++
3 files changed, 78 insertions(+), 4 deletions(-)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index e939c20..deae7df 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -40,6 +40,7 @@
#include "xfs_symlink.h"
#include "xfs_trans.h"
#include "xfs_pnfs.h"
+#include "xfs_richacl.h"
#include <linux/capability.h>
#include <linux/dcache.h>
@@ -48,6 +49,7 @@
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/exportfs.h>
+#include <linux/xattr.h>
/*
* xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
@@ -461,10 +463,20 @@ xfs_attrmulti_attr_get(
if (!kbuf)
return -ENOMEM;
+ if (flags & ATTR_ROOT) {
+ if (!strcmp(name, XATTR_RICHACL)) {
+ error = xfs_richacl_get_ioctl(inode, kbuf, (int *)len);
+ if (error)
+ goto out_kfree;
+ goto out_copy;
+ }
+ }
+
error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
if (error)
goto out_kfree;
+out_copy:
if (copy_to_user(ubuf, kbuf, *len))
error = -EFAULT;
@@ -493,7 +505,16 @@ xfs_attrmulti_attr_set(
if (IS_ERR(kbuf))
return PTR_ERR(kbuf);
+ if (flags & ATTR_ROOT) {
+ if (!strcmp(name, XATTR_RICHACL)) {
+ error = xfs_richacl_set_ioctl(inode, kbuf, len, flags);
+ goto out_kfree;
+ }
+ }
+
error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+
+out_kfree:
kfree(kbuf);
return error;
}
@@ -506,6 +527,12 @@ xfs_attrmulti_attr_remove(
{
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
+
+ if (flags & ATTR_ROOT) {
+ if (!strcmp(name, XATTR_RICHACL))
+ return xfs_richacl_set_ioctl(inode, NULL, 0, flags);
+ }
+
return xfs_attr_remove(XFS_I(inode), name, flags);
}
diff --git a/fs/xfs/xfs_richacl.c b/fs/xfs/xfs_richacl.c
index 92a036e..f8f5a62 100644
--- a/fs/xfs/xfs_richacl.c
+++ b/fs/xfs/xfs_richacl.c
@@ -67,8 +67,8 @@ xfs_remove_richacl(struct inode *inode)
return error;
}
-int
-xfs_set_richacl(struct inode *inode, struct richacl *acl)
+static int
+__xfs_set_richacl(struct inode *inode, struct richacl *acl, int xflags)
{
struct xfs_inode *ip = XFS_I(inode);
umode_t mode = inode->i_mode;
@@ -88,8 +88,7 @@ xfs_set_richacl(struct inode *inode, struct richacl *acl)
if (!value)
return -ENOMEM;
richacl_to_xattr(&init_user_ns, acl, value, size);
- error = xfs_attr_set(ip, XATTR_RICHACL, value, size,
- ATTR_ROOT);
+ error = xfs_attr_set(ip, XATTR_RICHACL, value, size, xflags);
kfree(value);
if (error)
return error;
@@ -101,3 +100,48 @@ xfs_set_richacl(struct inode *inode, struct richacl *acl)
return 0;
}
+
+int
+xfs_set_richacl(struct inode *inode, struct richacl *acl)
+{
+ return __xfs_set_richacl(inode, acl, ATTR_ROOT);
+}
+
+int
+xfs_richacl_get_ioctl(struct inode *inode, void *value, int *len)
+{
+ struct user_namespace *user_ns = current_user_ns();
+ struct richacl *acl;
+ int error;
+
+ acl = get_richacl(inode);
+ if (IS_ERR_OR_NULL(acl))
+ return PTR_ERR(acl);
+ error = richacl_to_xattr(user_ns, acl, value, *len);
+ if (error > 0) {
+ *len = error;
+ error = 0;
+ }
+ richacl_put(acl);
+ return error;
+}
+
+int
+xfs_richacl_set_ioctl(struct inode *inode, void *value, unsigned int size,
+ int xflags)
+{
+ struct user_namespace *user_ns = current_user_ns();
+ struct richacl *acl = NULL;
+ int error;
+
+ if (!IS_RICHACL(inode))
+ return -EOPNOTSUPP;
+ if (value) {
+ acl = richacl_from_xattr(user_ns, value, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ }
+ error = __xfs_set_richacl(inode, acl, xflags);
+ richacl_put(acl);
+ return error;
+}
diff --git a/fs/xfs/xfs_richacl.h b/fs/xfs/xfs_richacl.h
index 431aa25..1fd1fc1 100644
--- a/fs/xfs/xfs_richacl.h
+++ b/fs/xfs/xfs_richacl.h
@@ -20,4 +20,7 @@ struct richacl;
extern struct richacl *xfs_get_richacl(struct inode *);
extern int xfs_set_richacl(struct inode *, struct richacl *);
+extern int xfs_richacl_get_ioctl(struct inode *, void *, int *);
+extern int xfs_richacl_set_ioctl(struct inode *, void *, int, int);
+
#endif /* __FS_XFS_RICHACL_H */
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 17:00 +0100 |
| Subject | [PATCH v13 16/51] richacl: Automatic Inheritance |
| Message-ID | <qqMa6-4KZ-3@gated-at.bofh.it> |
| In reply to | #1261574 |
Automatic Inheritance (AI) allows changes to the acl of a directory to
propagate down to children.
This is mostly implemented in user space: when a process changes the
permissions of a directory and Automatic Inheritance is enabled for that
directory, the process must propagate those changes to all children,
recursively.
The kernel enables this by keeping track of which permissions have been
inherited at create time. In addition, it makes sure that permission
propagation is turned off when the permissions are set explicitly (for
example, upon create or chmod).
Automatic Inheritance works as follows:
- When the RICHACL_AUTO_INHERIT flag in the acl of a file or directory
is not set, the file or directory is not affected by AI.
- When the RICHACL_AUTO_INHERIT flag in the acl of a directory is set
and a file or subdirectory is created in that directory, the
inherited acl will have the RICHACL_AUTO_INHERIT flag set, and all
inherited aces will have the RICHACE_INHERITED_ACE flag set. This
allows user space to distinguish between aces which have been
inherited and aces which have been explicitly added.
- When the RICHACL_PROTECTED acl flag in the acl of a file or directory
is set, AI will not modify the acl. This does not affect propagation
of permissions from the file to its children (if the file is a
directory).
Linux does not have a way of creating files or directories without setting the
file permission bits, so all files created inside a directory with
RICHACL_AUTO_INHERIT set will have the RICHACL_PROTECTED flag set. This
effectively disables Automatic Inheritance.
Protocols which support creating files without specifying permissions can
explicitly clear the RICHACL_PROTECTED flag after creating a file and reset the
file masks to "undo" applying the create mode; see richacl_compute_max_masks().
They should set the RICHACL_DEFAULTED flag. (A mechanism that would allow to
indicate to the kernel to ignore the create mode in the first place when there
are inherited permissions would be nice to have.)
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl_base.c | 10 +++++++++-
fs/richacl_inode.c | 7 +++++++
include/linux/richacl.h | 12 ++++++++++++
include/uapi/linux/richacl.h | 11 ++++++++++-
4 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index 9f7d91d..2a9c448 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -366,7 +366,8 @@ __richacl_chmod(struct richacl *acl, umode_t mode)
acl->a_group_mask == group_mask &&
acl->a_other_mask == other_mask &&
(acl->a_flags & RICHACL_MASKED) &&
- (acl->a_flags & RICHACL_WRITE_THROUGH))
+ (acl->a_flags & RICHACL_WRITE_THROUGH) &&
+ (!richacl_is_auto_inherit(acl) || richacl_is_protected(acl)))
return acl;
clone = richacl_clone(acl, GFP_KERNEL);
@@ -378,6 +379,8 @@ __richacl_chmod(struct richacl *acl, umode_t mode)
clone->a_owner_mask = owner_mask;
clone->a_group_mask = group_mask;
clone->a_other_mask = other_mask;
+ if (richacl_is_auto_inherit(clone))
+ clone->a_flags |= RICHACL_PROTECTED;
return clone;
}
@@ -551,6 +554,11 @@ richacl_inherit(const struct richacl *dir_acl, int isdir)
ace++;
}
}
+ if (richacl_is_auto_inherit(dir_acl)) {
+ acl->a_flags = RICHACL_AUTO_INHERIT;
+ richacl_for_each_entry(ace, acl)
+ ace->e_flags |= RICHACE_INHERITED_ACE;
+ }
return acl;
}
diff --git a/fs/richacl_inode.c b/fs/richacl_inode.c
index d2bf076..24276da 100644
--- a/fs/richacl_inode.c
+++ b/fs/richacl_inode.c
@@ -277,6 +277,13 @@ richacl_inherit_inode(const struct richacl *dir_acl, umode_t *mode_p)
richacl_put(acl);
acl = NULL;
} else {
+ /*
+ * We need to set RICHACL_PROTECTED because we are
+ * doing an implicit chmod
+ */
+ if (richacl_is_auto_inherit(acl))
+ acl->a_flags |= RICHACL_PROTECTED;
+
richacl_compute_max_masks(acl);
/*
* Ensure that the acl will not grant any permissions
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 302872b..7cfa64d 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -76,6 +76,18 @@ extern void set_cached_richacl(struct inode *, struct richacl *);
extern void forget_cached_richacl(struct inode *);
extern struct richacl *get_richacl(struct inode *);
+static inline int
+richacl_is_auto_inherit(const struct richacl *acl)
+{
+ return acl->a_flags & RICHACL_AUTO_INHERIT;
+}
+
+static inline int
+richacl_is_protected(const struct richacl *acl)
+{
+ return acl->a_flags & RICHACL_PROTECTED;
+}
+
/**
* richace_is_owner - check if @ace is an OWNER@ entry
*/
diff --git a/include/uapi/linux/richacl.h b/include/uapi/linux/richacl.h
index 1ed48ac..8849a53 100644
--- a/include/uapi/linux/richacl.h
+++ b/include/uapi/linux/richacl.h
@@ -18,6 +18,9 @@
#define __UAPI_RICHACL_H
/* a_flags values */
+#define RICHACL_AUTO_INHERIT 0x01
+#define RICHACL_PROTECTED 0x02
+#define RICHACL_DEFAULTED 0x04
#define RICHACL_WRITE_THROUGH 0x40
#define RICHACL_MASKED 0x80
@@ -31,6 +34,7 @@
#define RICHACE_NO_PROPAGATE_INHERIT_ACE 0x0004
#define RICHACE_INHERIT_ONLY_ACE 0x0008
#define RICHACE_IDENTIFIER_GROUP 0x0040
+#define RICHACE_INHERITED_ACE 0x0080
#define RICHACE_SPECIAL_WHO 0x4000
/* e_mask bitflags */
@@ -60,6 +64,9 @@
#define RICHACE_EVERYONE_SPECIAL_ID 2
#define RICHACL_VALID_FLAGS ( \
+ RICHACL_AUTO_INHERIT | \
+ RICHACL_PROTECTED | \
+ RICHACL_DEFAULTED | \
RICHACL_WRITE_THROUGH | \
RICHACL_MASKED )
@@ -69,13 +76,15 @@
RICHACE_NO_PROPAGATE_INHERIT_ACE | \
RICHACE_INHERIT_ONLY_ACE | \
RICHACE_IDENTIFIER_GROUP | \
+ RICHACE_INHERITED_ACE | \
RICHACE_SPECIAL_WHO )
#define RICHACE_INHERITANCE_FLAGS ( \
RICHACE_FILE_INHERIT_ACE | \
RICHACE_DIRECTORY_INHERIT_ACE | \
RICHACE_NO_PROPAGATE_INHERIT_ACE | \
- RICHACE_INHERIT_ONLY_ACE )
+ RICHACE_INHERIT_ONLY_ACE | \
+ RICHACE_INHERITED_ACE )
/* Valid RICHACE_* flags for directories and non-directories */
#define RICHACE_VALID_MASK ( \
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 17:00 +0100 |
| Subject | [PATCH v13 15/51] richacl: Create-time inheritance |
| Message-ID | <qqMa6-4KZ-7@gated-at.bofh.it> |
| In reply to | #1261574 |
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 (draft)
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@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl_base.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
fs/richacl_inode.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 2 ++
3 files changed, 140 insertions(+)
diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index 56b5ad6..9f7d91d 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -486,3 +486,71 @@ richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p)
return 0;
}
EXPORT_SYMBOL_GPL(richacl_equiv_mode);
+
+/**
+ * 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 (!richace_is_inheritable(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 (!richace_is_inheritable(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;
+ 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 301f246..d2bf076 100644
--- a/fs/richacl_inode.c
+++ b/fs/richacl_inode.c
@@ -252,3 +252,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 ddd5aa6..302872b 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.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 17:00 +0100 |
| Subject | [PATCH v13 24/51] xfs: Change how listxattr generates synthetic attributes |
| Message-ID | <qqMa6-4KZ-15@gated-at.bofh.it> |
| In reply to | #1261574 |
Instead of adding the synthesized POSIX ACL attribute names after listing all
non-synthesized attributes, generate them immediately when listing the
non-synthesized attributes.
In addition, merge xfs_xattr_put_listent and xfs_xattr_put_listent_sizes to
ensure that the list size is computed correctly; the split version was
overestimating the list size for non-root users.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/xfs/xfs_acl.c | 23 ---------
fs/xfs/xfs_acl.h | 4 --
fs/xfs/xfs_xattr.c | 137 +++++++++++++++++++++++------------------------------
3 files changed, 59 insertions(+), 105 deletions(-)
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 7b03383..778a464 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -231,29 +231,6 @@ __xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
return error;
}
-static int
-xfs_acl_exists(struct inode *inode, unsigned char *name)
-{
- int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));
-
- return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
- ATTR_ROOT|ATTR_KERNOVAL) == 0);
-}
-
-int
-posix_acl_access_exists(struct inode *inode)
-{
- return xfs_acl_exists(inode, SGI_ACL_FILE);
-}
-
-int
-posix_acl_default_exists(struct inode *inode)
-{
- if (!S_ISDIR(inode->i_mode))
- return 0;
- return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
-}
-
int
xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 9ee0a0d..cf973f5 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -24,15 +24,11 @@ struct posix_acl;
#ifdef CONFIG_XFS_POSIX_ACL
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
-extern int posix_acl_access_exists(struct inode *inode);
-extern int posix_acl_default_exists(struct inode *inode);
#else
static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
{
return NULL;
}
# define xfs_set_acl NULL
-# define posix_acl_access_exists(inode) 0
-# define posix_acl_default_exists(inode) 0
#endif /* CONFIG_XFS_POSIX_ACL */
#endif /* __XFS_ACL_H__ */
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index c0368151..8428aed 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -106,47 +106,19 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
NULL
};
-static unsigned int xfs_xattr_prefix_len(int flags)
-{
- if (flags & XFS_ATTR_SECURE)
- return sizeof("security");
- else if (flags & XFS_ATTR_ROOT)
- return sizeof("trusted");
- else
- return sizeof("user");
-}
-
-static const char *xfs_xattr_prefix(int flags)
-{
- if (flags & XFS_ATTR_SECURE)
- return xfs_xattr_security_handler.prefix;
- else if (flags & XFS_ATTR_ROOT)
- return xfs_xattr_trusted_handler.prefix;
- else
- return xfs_xattr_user_handler.prefix;
-}
-
static int
-xfs_xattr_put_listent(
+__xfs_xattr_put_listent(
struct xfs_attr_list_context *context,
- int flags,
- unsigned char *name,
- int namelen,
- int valuelen,
- unsigned char *value)
+ char *prefix,
+ int prefix_len,
+ unsigned char *name,
+ int namelen)
{
- unsigned int prefix_len = xfs_xattr_prefix_len(flags);
char *offset;
int arraytop;
- ASSERT(context->count >= 0);
-
- /*
- * Only show root namespace entries if we are actually allowed to
- * see them.
- */
- if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
- return 0;
+ if (!context->alist)
+ goto compute_size;
arraytop = context->count + prefix_len + namelen + 1;
if (arraytop > context->firstu) {
@@ -154,17 +126,19 @@ xfs_xattr_put_listent(
return 1;
}
offset = (char *)context->alist + context->count;
- strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
+ strncpy(offset, prefix, prefix_len);
offset += prefix_len;
strncpy(offset, (char *)name, namelen); /* real name */
offset += namelen;
*offset = '\0';
+
+compute_size:
context->count += prefix_len + namelen + 1;
return 0;
}
static int
-xfs_xattr_put_listent_sizes(
+xfs_xattr_put_listent(
struct xfs_attr_list_context *context,
int flags,
unsigned char *name,
@@ -172,24 +146,55 @@ xfs_xattr_put_listent_sizes(
int valuelen,
unsigned char *value)
{
- context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
- return 0;
-}
+ char *prefix;
+ int prefix_len;
-static int
-list_one_attr(const char *name, const size_t len, void *data,
- size_t size, ssize_t *result)
-{
- char *p = data + *result;
+ ASSERT(context->count >= 0);
- *result += len;
- if (!size)
- return 0;
- if (*result > size)
- return -ERANGE;
+ if (flags & XFS_ATTR_ROOT) {
+#ifdef CONFIG_XFS_POSIX_ACL
+ if (namelen == SGI_ACL_FILE_SIZE &&
+ strncmp(name, SGI_ACL_FILE,
+ SGI_ACL_FILE_SIZE) == 0) {
+ int ret = __xfs_xattr_put_listent(
+ context, XATTR_SYSTEM_PREFIX,
+ XATTR_SYSTEM_PREFIX_LEN,
+ XATTR_POSIX_ACL_ACCESS,
+ strlen(XATTR_POSIX_ACL_ACCESS));
+ if (ret)
+ return ret;
+ } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
+ strncmp(name, SGI_ACL_DEFAULT,
+ SGI_ACL_DEFAULT_SIZE) == 0) {
+ int ret = __xfs_xattr_put_listent(
+ context, XATTR_SYSTEM_PREFIX,
+ XATTR_SYSTEM_PREFIX_LEN,
+ XATTR_POSIX_ACL_DEFAULT,
+ strlen(XATTR_POSIX_ACL_DEFAULT));
+ if (ret)
+ return ret;
+ }
+#endif
- strcpy(p, name);
- return 0;
+ /*
+ * Only show root namespace entries if we are actually allowed to
+ * see them.
+ */
+ if (!capable(CAP_SYS_ADMIN))
+ return 0;
+
+ prefix = XATTR_TRUSTED_PREFIX;
+ prefix_len = XATTR_TRUSTED_PREFIX_LEN;
+ } else if (flags & XFS_ATTR_SECURE) {
+ prefix = XATTR_SECURITY_PREFIX;
+ prefix_len = XATTR_SECURITY_PREFIX_LEN;
+ } else {
+ prefix = XATTR_USER_PREFIX;
+ prefix_len = XATTR_USER_PREFIX_LEN;
+ }
+
+ return __xfs_xattr_put_listent(context, prefix, prefix_len, name,
+ namelen);
}
ssize_t
@@ -198,7 +203,6 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
struct xfs_attr_list_context context;
struct attrlist_cursor_kern cursor = { 0 };
struct inode *inode = d_inode(dentry);
- int error;
/*
* First read the regular on-disk attributes.
@@ -207,37 +211,14 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
context.dp = XFS_I(inode);
context.cursor = &cursor;
context.resynch = 1;
- context.alist = data;
+ context.alist = size ? data : NULL;
context.bufsize = size;
context.firstu = context.bufsize;
-
- if (size)
- context.put_listent = xfs_xattr_put_listent;
- else
- context.put_listent = xfs_xattr_put_listent_sizes;
+ context.put_listent = xfs_xattr_put_listent;
xfs_attr_list_int(&context);
if (context.count < 0)
return -ERANGE;
- /*
- * Then add the two synthetic ACL attributes.
- */
- if (posix_acl_access_exists(inode)) {
- error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
- strlen(POSIX_ACL_XATTR_ACCESS) + 1,
- data, size, &context.count);
- if (error)
- return error;
- }
-
- if (posix_acl_default_exists(inode)) {
- error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
- strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
- data, size, &context.count);
- if (error)
- return error;
- }
-
return context.count;
}
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 17:00 +0100 |
| Subject | [PATCH v13 21/51] ext4: Add richacl feature flag |
| Message-ID | <qqMa6-4KZ-17@gated-at.bofh.it> |
| In reply to | #1261574 |
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
This feature flag selects richacl instead of posix acl support on the
file system. In addition, the "acl" mount option is needed for enabling
either of the two kinds of acls.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/ext4/ext4.h | 6 ++++--
fs/ext4/super.c | 49 ++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index fd1f28b..b97a3b1 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -991,7 +991,7 @@ struct ext4_inode_info {
#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
-#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
+#define EXT4_MOUNT_ACL 0x08000 /* Access Control Lists */
#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
@@ -1582,6 +1582,7 @@ static inline int ext4_encrypted_inode(struct inode *inode)
#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
+#define EXT4_FEATURE_INCOMPAT_RICHACL 0x20000
#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
@@ -1607,7 +1608,8 @@ static inline int ext4_encrypted_inode(struct inode *inode)
EXT4_FEATURE_INCOMPAT_FLEX_BG| \
EXT4_FEATURE_INCOMPAT_MMP | \
EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
- EXT4_FEATURE_INCOMPAT_ENCRYPT)
+ EXT4_FEATURE_INCOMPAT_ENCRYPT | \
+ EXT4_FEATURE_INCOMPAT_RICHACL)
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index a63c7b0..7457ea8 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1270,6 +1270,28 @@ static ext4_fsblk_t get_sb_block(void **data)
return sb_block;
}
+static int enable_acl(struct super_block *sb)
+{
+ sb->s_flags &= ~(MS_POSIXACL | MS_RICHACL);
+ if (test_opt(sb, ACL)) {
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb,
+ EXT4_FEATURE_INCOMPAT_RICHACL)) {
+#ifdef CONFIG_EXT4_FS_RICHACL
+ sb->s_flags |= MS_RICHACL;
+#else
+ return -EOPNOTSUPP;
+#endif
+ } else {
+#ifdef CONFIG_EXT4_FS_POSIX_ACL
+ sb->s_flags |= MS_POSIXACL;
+#else
+ return -EOPNOTSUPP;
+#endif
+ }
+ }
+ return 0;
+}
+
#define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
static char deprecated_msg[] = "Mount option \"%s\" will be removed by %s\n"
"Contact linux-ext4@vger.kernel.org if you think we should keep it.\n";
@@ -1416,9 +1438,9 @@ static const struct mount_opts {
MOPT_NO_EXT2 | MOPT_DATAJ},
{Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
{Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
- {Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET},
- {Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR},
+#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4_FS_RICHACL)
+ {Opt_acl, EXT4_MOUNT_ACL, MOPT_SET},
+ {Opt_noacl, EXT4_MOUNT_ACL, MOPT_CLEAR},
#else
{Opt_acl, 0, MOPT_NOSUPPORT},
{Opt_noacl, 0, MOPT_NOSUPPORT},
@@ -1466,6 +1488,13 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
#endif
switch (token) {
case Opt_noacl:
+#ifdef CONFIG_EXT4_FS_RICHACL
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RICHACL)) {
+ ext4_msg(sb, KERN_ERR, "Mount option \"%s\" incompatible "
+ "with richacl feature", opt);
+ return -1;
+ }
+#endif
case Opt_nouser_xattr:
ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
break;
@@ -3576,8 +3605,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
set_opt(sb, NO_UID32);
/* xattr user namespace & acls are now defaulted on */
set_opt(sb, XATTR_USER);
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
- set_opt(sb, POSIX_ACL);
+#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4_FS_RICHACL)
+ set_opt(sb, ACL);
#endif
/* don't forget to enable journal_csum when metadata_csum is enabled. */
if (ext4_has_metadata_csum(sb))
@@ -3660,8 +3689,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sb->s_iflags |= SB_I_CGROUPWB;
}
- sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
- (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
+ err = enable_acl(sb);
+ if (err)
+ goto failed_mount;
if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
(EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
@@ -4981,8 +5011,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
ext4_abort(sb, "Abort forced by user");
- sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
- (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
+ err = enable_acl(sb);
+ if (err)
+ goto restore_opts;
es = sbi->s_es;
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Dilger <adilger@dilger.ca> |
|---|---|
| Date | 2015-11-04 03:20 +0100 |
| Subject | Re: [PATCH v13 21/51] ext4: Add richacl feature flag |
| Message-ID | <qqVQ6-2Eh-13@gated-at.bofh.it> |
| In reply to | #1261654 |
[Multipart message — attachments visible in raw view] — view raw
> On Nov 3, 2015, at 8:16 AM, Andreas Gruenbacher <agruenba@redhat.com> wrote:
>
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
>
> This feature flag selects richacl instead of posix acl support on the
> file system. In addition, the "acl" mount option is needed for enabling
> either of the two kinds of acls.
This patch confuses me. I thought the whole point of INCOMPAT_RICHACL
was that the filesystem should never, ever be mounted without ACL support
because the ACLs will get confused without it. In that case, it doesn't
make sense to have a mount option that _has_ to be specified to mount the
filesystem, and returns an error when trying to disable it.
It makes more sense to just enable "acl" by default if INCOMPAT_RICHACL
is set in the superblock and not need the mount option at all.
Having a mount option made more sense when enabling this support was optional
for the filesystem, and it could be mounted without it enabled, but you
wanted INCOMPAT_RICHACL to prevent that so it needs to be fixed.
Cheers, Andreas
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
> ---
> fs/ext4/ext4.h | 6 ++++--
> fs/ext4/super.c | 49 ++++++++++++++++++++++++++++++++++++++++---------
> 2 files changed, 44 insertions(+), 11 deletions(-)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index fd1f28b..b97a3b1 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -991,7 +991,7 @@ struct ext4_inode_info {
> #define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
> #define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
> #define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
> -#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
> +#define EXT4_MOUNT_ACL 0x08000 /* Access Control Lists */
> #define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
> #define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
> #define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
> @@ -1582,6 +1582,7 @@ static inline int ext4_encrypted_inode(struct inode *inode)
> #define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
> #define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
> #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
> +#define EXT4_FEATURE_INCOMPAT_RICHACL 0x20000
>
> #define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
> #define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
> @@ -1607,7 +1608,8 @@ static inline int ext4_encrypted_inode(struct inode *inode)
> EXT4_FEATURE_INCOMPAT_FLEX_BG| \
> EXT4_FEATURE_INCOMPAT_MMP | \
> EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
> - EXT4_FEATURE_INCOMPAT_ENCRYPT)
> + EXT4_FEATURE_INCOMPAT_ENCRYPT | \
> + EXT4_FEATURE_INCOMPAT_RICHACL)
> #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
> EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
> EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index a63c7b0..7457ea8 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -1270,6 +1270,28 @@ static ext4_fsblk_t get_sb_block(void **data)
> return sb_block;
> }
>
> +static int enable_acl(struct super_block *sb)
> +{
> + sb->s_flags &= ~(MS_POSIXACL | MS_RICHACL);
> + if (test_opt(sb, ACL)) {
> + if (EXT4_HAS_INCOMPAT_FEATURE(sb,
> + EXT4_FEATURE_INCOMPAT_RICHACL)) {
> +#ifdef CONFIG_EXT4_FS_RICHACL
> + sb->s_flags |= MS_RICHACL;
> +#else
> + return -EOPNOTSUPP;
> +#endif
> + } else {
> +#ifdef CONFIG_EXT4_FS_POSIX_ACL
> + sb->s_flags |= MS_POSIXACL;
> +#else
> + return -EOPNOTSUPP;
> +#endif
> + }
> + }
> + return 0;
> +}
> +
> #define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3))
> static char deprecated_msg[] = "Mount option \"%s\" will be removed by %s\n"
> "Contact linux-ext4@vger.kernel.org if you think we should keep it.\n";
> @@ -1416,9 +1438,9 @@ static const struct mount_opts {
> MOPT_NO_EXT2 | MOPT_DATAJ},
> {Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
> {Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
> -#ifdef CONFIG_EXT4_FS_POSIX_ACL
> - {Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET},
> - {Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR},
> +#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4_FS_RICHACL)
> + {Opt_acl, EXT4_MOUNT_ACL, MOPT_SET},
> + {Opt_noacl, EXT4_MOUNT_ACL, MOPT_CLEAR},
> #else
> {Opt_acl, 0, MOPT_NOSUPPORT},
> {Opt_noacl, 0, MOPT_NOSUPPORT},
> @@ -1466,6 +1488,13 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
> #endif
> switch (token) {
> case Opt_noacl:
> +#ifdef CONFIG_EXT4_FS_RICHACL
> + if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RICHACL)) {
> + ext4_msg(sb, KERN_ERR, "Mount option \"%s\" incompatible "
> + "with richacl feature", opt);
> + return -1;
> + }
> +#endif
> case Opt_nouser_xattr:
> ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5");
> break;
> @@ -3576,8 +3605,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> set_opt(sb, NO_UID32);
> /* xattr user namespace & acls are now defaulted on */
> set_opt(sb, XATTR_USER);
> -#ifdef CONFIG_EXT4_FS_POSIX_ACL
> - set_opt(sb, POSIX_ACL);
> +#if defined(CONFIG_EXT4_FS_POSIX_ACL) || defined(CONFIG_EXT4_FS_RICHACL)
> + set_opt(sb, ACL);
> #endif
> /* don't forget to enable journal_csum when metadata_csum is enabled. */
> if (ext4_has_metadata_csum(sb))
> @@ -3660,8 +3689,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
> sb->s_iflags |= SB_I_CGROUPWB;
> }
>
> - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
> - (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
> + err = enable_acl(sb);
> + if (err)
> + goto failed_mount;
>
> if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
> (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
> @@ -4981,8 +5011,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
> if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
> ext4_abort(sb, "Abort forced by user");
>
> - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
> - (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
> + err = enable_acl(sb);
> + if (err)
> + goto restore_opts;
>
> es = sbi->s_es;
>
> --
> 2.5.0
>
Cheers, Andreas
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-04 03:30 +0100 |
| Subject | Re: [PATCH v13 21/51] ext4: Add richacl feature flag |
| Message-ID | <qqVZM-2HI-5@gated-at.bofh.it> |
| In reply to | #1262039 |
Andreas, On Wed, Nov 4, 2015 at 3:18 AM, Andreas Dilger <adilger@dilger.ca> wrote: > This patch confuses me. I thought the whole point of INCOMPAT_RICHACL > was that the filesystem should never, ever be mounted without ACL support > because the ACLs will get confused without it. In that case, it doesn't > make sense to have a mount option that _has_ to be specified to mount the > filesystem, and returns an error when trying to disable it. > > It makes more sense to just enable "acl" by default if INCOMPAT_RICHACL > is set in the superblock and not need the mount option at all. It's the commit message that's misleading here, I'll fix it. On richacl filesystems, the acl mount option is always on. It's only on POSIX ACL filesystems that the mount option can be used to turn POSIX ACLs off (which arguably wasn't such a good idea, but there we have it). Thanks, Andreas -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-04 03:50 +0100 |
| Subject | Re: [PATCH v13 21/51] ext4: Add richacl feature flag |
| Message-ID | <qqWj7-2Oh-7@gated-at.bofh.it> |
| In reply to | #1262042 |
On Wed, Nov 4, 2015 at 3:28 AM, Andreas Gruenbacher <agruenba@redhat.com> wrote:
> It's the commit message that's misleading here, I'll fix it.
Commit message changed to:
This feature flag selects richacl instead of POSIX ACL support on the
filesystem. When this feature is off, the "acl" and "noacl" mount options
control whether POSIX ACLs are enabled. When it is on, richacls are
automatically enabled and using the "noacl" mount option leads to an error.
Thanks,
Andreas
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 17:00 +0100 |
| Subject | [PATCH v13 14/51] richacl: Check if an acl is equivalent to a file mode |
| Message-ID | <qqMa7-4KZ-21@gated-at.bofh.it> |
| In reply to | #1261574 |
ACLs are considered equivalent to file modes if they only consist of
owner@, group@, and everyone@ entries, the owner@ permissions do not
depend on whether the owner is a member in the owning group, and no
inheritance flags are set. This test is used to avoid storing richacls
if the acl can be computed from the file permission bits.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: J. Bruce Fields <bfields@redhat.com>
---
fs/richacl_base.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/richacl.h | 1 +
2 files changed, 105 insertions(+)
diff --git a/fs/richacl_base.c b/fs/richacl_base.c
index 00e87be..56b5ad6 100644
--- a/fs/richacl_base.c
+++ b/fs/richacl_base.c
@@ -382,3 +382,107 @@ __richacl_chmod(struct richacl *acl, umode_t mode)
return clone;
}
EXPORT_SYMBOL_GPL(__richacl_chmod);
+
+/**
+ * richacl_equiv_mode - compute the mode equivalent of @acl
+ *
+ * An acl is considered equivalent to a file mode if it only consists of
+ * owner@, group@, and everyone@ entries and the owner@ permissions do not
+ * depend on whether the owner is a member in the owning group.
+ */
+int
+richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p)
+{
+ umode_t mode = *mode_p;
+
+ /*
+ * The RICHACE_DELETE_CHILD flag is meaningless for non-directories, so
+ * we ignore it.
+ */
+ unsigned int x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
+ struct {
+ unsigned int allowed;
+ unsigned int defined; /* allowed or denied */
+ } owner = {
+ .defined = RICHACE_POSIX_ALWAYS_ALLOWED |
+ RICHACE_POSIX_OWNER_ALLOWED | x,
+ }, group = {
+ .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x,
+ }, everyone = {
+ .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x,
+ };
+ const struct richace *ace;
+
+ if (acl->a_flags & ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED))
+ return -1;
+
+ richacl_for_each_entry(ace, acl) {
+ if (ace->e_flags & ~RICHACE_SPECIAL_WHO)
+ return -1;
+
+ if (richace_is_owner(ace) || richace_is_everyone(ace)) {
+ x = ace->e_mask & ~owner.defined;
+ if (richace_is_allow(ace)) {
+ unsigned int group_denied =
+ group.defined & ~group.allowed;
+
+ if (x & group_denied)
+ return -1;
+ owner.allowed |= x;
+ } else /* if (richace_is_deny(ace)) */ {
+ if (x & group.allowed)
+ return -1;
+ }
+ owner.defined |= x;
+
+ if (richace_is_everyone(ace)) {
+ x = ace->e_mask;
+ if (richace_is_allow(ace)) {
+ group.allowed |=
+ x & ~group.defined;
+ everyone.allowed |=
+ x & ~everyone.defined;
+ }
+ group.defined |= x;
+ everyone.defined |= x;
+ }
+ } else if (richace_is_group(ace)) {
+ x = ace->e_mask & ~group.defined;
+ if (richace_is_allow(ace))
+ group.allowed |= x;
+ group.defined |= x;
+ } else
+ return -1;
+ }
+
+ if (group.allowed & ~owner.defined)
+ return -1;
+
+ if (acl->a_flags & RICHACL_MASKED) {
+ if (acl->a_flags & RICHACL_WRITE_THROUGH) {
+ owner.allowed = acl->a_owner_mask;
+ everyone.allowed = acl->a_other_mask;
+ } else {
+ owner.allowed &= acl->a_owner_mask;
+ everyone.allowed &= acl->a_other_mask;
+ }
+ group.allowed &= acl->a_group_mask;
+ }
+
+ mode = (mode & ~S_IRWXUGO) |
+ (richacl_mask_to_mode(owner.allowed) << 6) |
+ (richacl_mask_to_mode(group.allowed) << 3) |
+ richacl_mask_to_mode(everyone.allowed);
+
+ /* Mask flags we can ignore */
+ x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD;
+
+ if (((richacl_mode_to_mask(mode >> 6) ^ owner.allowed) & ~x) ||
+ ((richacl_mode_to_mask(mode >> 3) ^ group.allowed) & ~x) ||
+ ((richacl_mode_to_mask(mode) ^ everyone.allowed) & ~x))
+ return -1;
+
+ *mode_p = mode;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(richacl_equiv_mode);
diff --git a/include/linux/richacl.h b/include/linux/richacl.h
index 3626314..ddd5aa6 100644
--- a/include/linux/richacl.h
+++ b/include/linux/richacl.h
@@ -185,6 +185,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 *);
extern struct richacl *__richacl_chmod(struct richacl *, umode_t);
+extern int richacl_equiv_mode(const struct richacl *, umode_t *);
/* richacl_inode.c */
extern int richacl_permission(struct inode *, const struct richacl *, int);
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-03 17:00 +0100 |
| Subject | [PATCH v13 20/51] ext4: Add richacl support |
| Message-ID | <qqMa7-4KZ-33@gated-at.bofh.it> |
| In reply to | #1261574 |
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Support the richacl permission model in ext4. The richacls are stored
in "system.richacl" xattrs. Richacls need to be enabled by tune2fs or
at file system create time.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
fs/ext4/Kconfig | 11 +++++
fs/ext4/Makefile | 1 +
fs/ext4/file.c | 3 ++
fs/ext4/ialloc.c | 11 ++++-
fs/ext4/inode.c | 12 ++++-
fs/ext4/namei.c | 5 ++
fs/ext4/richacl.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/ext4/richacl.h | 40 ++++++++++++++++
fs/ext4/xattr.c | 7 +++
9 files changed, 228 insertions(+), 3 deletions(-)
create mode 100644 fs/ext4/richacl.c
create mode 100644 fs/ext4/richacl.h
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index b46e9fc..65c5230 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -22,6 +22,17 @@ config EXT3_FS_POSIX_ACL
This config option is here only for backward compatibility. ext3
filesystem is now handled by the ext4 driver.
+config EXT4_FS_RICHACL
+ bool "Ext4 Rich Access Control Lists (EXPERIMENTAL)"
+ depends on EXT4_FS
+ select FS_RICHACL
+ help
+ Richacls are an implementation of NFSv4 ACLs, extended by file masks
+ to cleanly integrate into the POSIX file permission model. To learn
+ more about them, see http://www.bestbits.at/richacl/.
+
+ If you don't know what Richacls are, say N.
+
config EXT3_FS_SECURITY
bool "Ext3 Security Labels"
depends on EXT3_FS
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 75285ea..ea0d539 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -14,3 +14,4 @@ ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
ext4-$(CONFIG_EXT4_FS_ENCRYPTION) += crypto_policy.o crypto.o \
crypto_key.o crypto_fname.o
+ext4-$(CONFIG_EXT4_FS_RICHACL) += richacl.o
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 113837e..a03b4a5 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -30,6 +30,7 @@
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
+#include "richacl.h"
/*
* Called when an inode is released. Note that this is different
@@ -719,6 +720,8 @@ const struct inode_operations ext4_file_inode_operations = {
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
+ .get_richacl = ext4_get_richacl,
+ .set_richacl = ext4_set_richacl,
.fiemap = ext4_fiemap,
};
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 619bfc1..9657b3a 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -27,6 +27,7 @@
#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
+#include "richacl.h"
#include <trace/events/ext4.h>
@@ -697,6 +698,14 @@ out:
return ret;
}
+static inline int
+ext4_new_acl(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ if (IS_RICHACL(dir))
+ return ext4_init_richacl(handle, inode, dir);
+ return ext4_init_acl(handle, inode, dir);
+}
+
/*
* There are two policies for allocating an inode. If the new inode is
* a directory, then a forward search is made for a block group with both
@@ -1052,7 +1061,7 @@ got:
if (err)
goto fail_drop;
- err = ext4_init_acl(handle, inode, dir);
+ err = ext4_new_acl(handle, inode, dir);
if (err)
goto fail_free_drop;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 612fbcf..647f3c3 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -42,6 +42,7 @@
#include "xattr.h"
#include "acl.h"
#include "truncate.h"
+#include "richacl.h"
#include <trace/events/ext4.h>
@@ -4638,6 +4639,14 @@ static void ext4_wait_for_tail_page_commit(struct inode *inode)
}
}
+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);
+}
+
/*
* ext4_setattr()
*
@@ -4806,8 +4815,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_orphan_del(NULL, inode);
if (!rc && (ia_valid & ATTR_MODE))
- rc = posix_acl_chmod(inode, inode->i_mode);
-
+ rc = ext4_acl_chmod(inode, inode->i_mode);
err_out:
ext4_std_error(inode->i_sb, error);
if (!error)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 9f61e76..9b6e8b9 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -38,6 +38,7 @@
#include "xattr.h"
#include "acl.h"
+#include "richacl.h"
#include <trace/events/ext4.h>
/*
@@ -3854,6 +3855,8 @@ const struct inode_operations ext4_dir_inode_operations = {
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
+ .get_richacl = ext4_get_richacl,
+ .set_richacl = ext4_set_richacl,
.fiemap = ext4_fiemap,
};
@@ -3865,4 +3868,6 @@ const struct inode_operations ext4_special_inode_operations = {
.removexattr = generic_removexattr,
.get_acl = ext4_get_acl,
.set_acl = ext4_set_acl,
+ .get_richacl = ext4_get_richacl,
+ .set_richacl = ext4_set_richacl,
};
diff --git a/fs/ext4/richacl.c b/fs/ext4/richacl.c
new file mode 100644
index 0000000..906d048
--- /dev/null
+++ b/fs/ext4/richacl.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Author: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>,
+ * Andreas Gruenbacher <agruenba@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/richacl_xattr.h>
+
+#include "ext4.h"
+#include "ext4_jbd2.h"
+#include "xattr.h"
+#include "acl.h"
+#include "richacl.h"
+
+struct richacl *
+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);
+ } else if (retval != -ENODATA && retval != -ENOSYS)
+ acl = ERR_PTR(retval);
+ kfree(value);
+
+ if (!IS_ERR(acl))
+ set_cached_richacl(inode, acl);
+
+ return acl;
+}
+
+static int
+__ext4_remove_richacl(handle_t *handle, struct inode *inode)
+{
+ const int name_index = EXT4_XATTR_INDEX_RICHACL;
+ int retval;
+
+ retval = ext4_xattr_set_handle(handle, inode, name_index, "",
+ NULL, 0, 0);
+ if (!retval)
+ set_cached_richacl(inode, NULL);
+ return retval;
+}
+
+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);
+ }
+
+ mode &= ~S_IRWXUGO;
+ mode |= richacl_masks_to_mode(acl);
+
+ size = richacl_xattr_size(acl);
+ value = kmalloc(size, GFP_NOFS);
+ if (!value)
+ return -ENOMEM;
+ richacl_to_xattr(&init_user_ns, acl, value, size);
+ inode->i_mode = mode;
+ retval = ext4_xattr_set_handle(handle, inode, name_index, "",
+ value, size, 0);
+ kfree(value);
+ if (retval)
+ return retval;
+
+ set_cached_richacl(inode, acl);
+
+ return 0;
+}
+
+int
+ext4_set_richacl(struct inode *inode, struct richacl *acl)
+{
+ handle_t *handle;
+ int retval, retries = 0;
+
+retry:
+ handle = ext4_journal_start(inode, EXT4_HT_XATTR,
+ ext4_jbd2_credits_xattr(inode));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (acl)
+ retval = __ext4_set_richacl(handle, inode, acl);
+ else
+ retval = __ext4_remove_richacl(handle, inode);
+
+ ext4_journal_stop(handle);
+ if (retval == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+ return retval;
+}
+
+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 (acl) {
+ error = __ext4_set_richacl(handle, inode, acl);
+ richacl_put(acl);
+ }
+ return error;
+}
diff --git a/fs/ext4/richacl.h b/fs/ext4/richacl.h
new file mode 100644
index 0000000..6fe9a92
--- /dev/null
+++ b/fs/ext4/richacl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright IBM Corporation, 2010
+ * Copyright (C) 2015 Red Hat, Inc.
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#ifndef __FS_EXT4_RICHACL_H
+#define __FS_EXT4_RICHACL_H
+
+#include <linux/richacl.h>
+
+#ifdef CONFIG_EXT4_FS_RICHACL
+
+extern struct richacl *ext4_get_richacl(struct inode *);
+extern int ext4_set_richacl(struct inode *, struct richacl *);
+
+extern int ext4_init_richacl(handle_t *, struct inode *, struct inode *);
+
+#else /* CONFIG_EXT4_FS_RICHACL */
+
+#define ext4_get_richacl NULL
+#define ext4_set_richacl NULL
+
+static inline int
+ext4_init_richacl(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ return 0;
+}
+
+#endif /* CONFIG_EXT4_FS_RICHACL */
+#endif /* __FS_EXT4_RICHACL_H */
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 16e28c0..4d79adb 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -55,6 +55,7 @@
#include <linux/slab.h>
#include <linux/mbcache.h>
#include <linux/quotaops.h>
+#include <linux/richacl_xattr.h>
#include "ext4_jbd2.h"
#include "ext4.h"
#include "xattr.h"
@@ -99,6 +100,9 @@ static const struct xattr_handler *ext4_xattr_handler_map[] = {
#ifdef CONFIG_EXT4_FS_SECURITY
[EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler,
#endif
+#ifdef CONFIG_EXT4_FS_RICHACL
+ [EXT4_XATTR_INDEX_RICHACL] = &richacl_xattr_handler,
+#endif
};
const struct xattr_handler *ext4_xattr_handlers[] = {
@@ -111,6 +115,9 @@ const struct xattr_handler *ext4_xattr_handlers[] = {
#ifdef CONFIG_EXT4_FS_SECURITY
&ext4_xattr_security_handler,
#endif
+#ifdef CONFIG_EXT4_FS_RICHACL
+ &richacl_xattr_handler,
+#endif
NULL
};
--
2.5.0
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andreas Gruenbacher <agruenba@redhat.com> |
|---|---|
| Date | 2015-11-04 03:20 +0100 |
| Subject | Re: [PATCH v13 20/51] ext4: Add richacl support |
| Message-ID | <qqVQ6-2Eh-7@gated-at.bofh.it> |
| In reply to | #1261659 |
On Wed, Nov 4, 2015 at 3:13 AM, Andreas Dilger <adilger@dilger.ca> wrote: > Patch looks reasonable. One minor cleanup below that could be fixed when > the patch series is refreshed, and you can add: > > Reviewed-by: Andreas Dilger <adilger@dilger.ca> Okay, thank you. Andreas -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
Page 3 of 4 — ← Prev page 1 2 [3] 4 Next page →
Back to top | Article view | linux.kernel
csiph-web