Branch data Line data Source code
1 : : /*
2 : : * linux/fs/xattr_acl.c
3 : : *
4 : : * Almost all from linux/fs/ext2/acl.c:
5 : : * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
6 : : */
7 : :
8 : : #include <linux/export.h>
9 : : #include <linux/fs.h>
10 : : #include <linux/posix_acl_xattr.h>
11 : : #include <linux/gfp.h>
12 : : #include <linux/user_namespace.h>
13 : :
14 : : /*
15 : : * Fix up the uids and gids in posix acl extended attributes in place.
16 : : */
17 : : static void posix_acl_fix_xattr_userns(
18 : : struct user_namespace *to, struct user_namespace *from,
19 : : void *value, size_t size)
20 : : {
21 : : posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
22 : : posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
23 : : int count;
24 : : kuid_t uid;
25 : : kgid_t gid;
26 : :
27 : : if (!value)
28 : : return;
29 : : if (size < sizeof(posix_acl_xattr_header))
30 : : return;
31 : : if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
32 : : return;
33 : :
34 : : count = posix_acl_xattr_count(size);
35 : : if (count < 0)
36 : : return;
37 : : if (count == 0)
38 : : return;
39 : :
40 : : for (end = entry + count; entry != end; entry++) {
41 : : switch(le16_to_cpu(entry->e_tag)) {
42 : : case ACL_USER:
43 : : uid = make_kuid(from, le32_to_cpu(entry->e_id));
44 : : entry->e_id = cpu_to_le32(from_kuid(to, uid));
45 : : break;
46 : : case ACL_GROUP:
47 : : gid = make_kgid(from, le32_to_cpu(entry->e_id));
48 : : entry->e_id = cpu_to_le32(from_kgid(to, gid));
49 : : break;
50 : : default:
51 : : break;
52 : : }
53 : : }
54 : : }
55 : :
56 : 0 : void posix_acl_fix_xattr_from_user(void *value, size_t size)
57 : : {
58 : : struct user_namespace *user_ns = current_user_ns();
59 : : if (user_ns == &init_user_ns)
60 : 2636 : return;
61 : : posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
62 : : }
63 : :
64 : 0 : void posix_acl_fix_xattr_to_user(void *value, size_t size)
65 : : {
66 : : struct user_namespace *user_ns = current_user_ns();
67 : : if (user_ns == &init_user_ns)
68 : 0 : return;
69 : : posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
70 : : }
71 : :
72 : : /*
73 : : * Convert from extended attribute to in-memory representation.
74 : : */
75 : : struct posix_acl *
76 : 0 : posix_acl_from_xattr(struct user_namespace *user_ns,
77 : : const void *value, size_t size)
78 : : {
79 : : posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
80 : 0 : posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
81 : : int count;
82 : : struct posix_acl *acl;
83 : : struct posix_acl_entry *acl_e;
84 : :
85 [ # # ]: 0 : if (!value)
86 : : return NULL;
87 [ # # ]: 0 : if (size < sizeof(posix_acl_xattr_header))
88 : : return ERR_PTR(-EINVAL);
89 [ # # ]: 0 : if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
90 : : return ERR_PTR(-EOPNOTSUPP);
91 : :
92 : : count = posix_acl_xattr_count(size);
93 [ # # ]: 0 : if (count < 0)
94 : : return ERR_PTR(-EINVAL);
95 [ # # ]: 0 : if (count == 0)
96 : : return NULL;
97 : :
98 : 0 : acl = posix_acl_alloc(count, GFP_NOFS);
99 [ # # ]: 0 : if (!acl)
100 : : return ERR_PTR(-ENOMEM);
101 : 0 : acl_e = acl->a_entries;
102 : :
103 [ # # ]: 0 : for (end = entry + count; entry != end; acl_e++, entry++) {
104 : 0 : acl_e->e_tag = le16_to_cpu(entry->e_tag);
105 [ # # ][ # # ]: 0 : acl_e->e_perm = le16_to_cpu(entry->e_perm);
[ # # ][ # # ]
106 : :
107 : : switch(acl_e->e_tag) {
108 : : case ACL_USER_OBJ:
109 : : case ACL_GROUP_OBJ:
110 : : case ACL_MASK:
111 : : case ACL_OTHER:
112 : : break;
113 : :
114 : : case ACL_USER:
115 : 0 : acl_e->e_uid =
116 : 0 : make_kuid(user_ns,
117 : : le32_to_cpu(entry->e_id));
118 [ # # ]: 0 : if (!uid_valid(acl_e->e_uid))
119 : : goto fail;
120 : : break;
121 : : case ACL_GROUP:
122 : 0 : acl_e->e_gid =
123 : 0 : make_kgid(user_ns,
124 : : le32_to_cpu(entry->e_id));
125 [ # # ]: 0 : if (!gid_valid(acl_e->e_gid))
126 : : goto fail;
127 : : break;
128 : :
129 : : default:
130 : : goto fail;
131 : : }
132 : : }
133 : : return acl;
134 : :
135 : : fail:
136 : : posix_acl_release(acl);
137 : : return ERR_PTR(-EINVAL);
138 : : }
139 : : EXPORT_SYMBOL (posix_acl_from_xattr);
140 : :
141 : : /*
142 : : * Convert from in-memory to extended attribute representation.
143 : : */
144 : : int
145 : 0 : posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
146 : : void *buffer, size_t size)
147 : : {
148 : : posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
149 : 0 : posix_acl_xattr_entry *ext_entry = ext_acl->a_entries;
150 : : int real_size, n;
151 : :
152 : 0 : real_size = posix_acl_xattr_size(acl->a_count);
153 [ # # ]: 0 : if (!buffer)
154 : : return real_size;
155 [ # # ]: 0 : if (real_size > size)
156 : : return -ERANGE;
157 : :
158 : 0 : ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
159 : :
160 [ # # ]: 0 : for (n=0; n < acl->a_count; n++, ext_entry++) {
161 : 0 : const struct posix_acl_entry *acl_e = &acl->a_entries[n];
162 : 0 : ext_entry->e_tag = cpu_to_le16(acl_e->e_tag);
163 : 0 : ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
164 [ # # # ]: 0 : switch(acl_e->e_tag) {
165 : : case ACL_USER:
166 : 0 : ext_entry->e_id =
167 : 0 : cpu_to_le32(from_kuid(user_ns, acl_e->e_uid));
168 : 0 : break;
169 : : case ACL_GROUP:
170 : 0 : ext_entry->e_id =
171 : 0 : cpu_to_le32(from_kgid(user_ns, acl_e->e_gid));
172 : 0 : break;
173 : : default:
174 : 0 : ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
175 : 0 : break;
176 : : }
177 : : }
178 : : return real_size;
179 : : }
180 : : EXPORT_SYMBOL (posix_acl_to_xattr);
|