Branch data Line data Source code
1 : : /*
2 : : * JFFS2 -- Journalling Flash File System, Version 2.
3 : : *
4 : : * Copyright © 2006 NEC Corporation
5 : : *
6 : : * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
7 : : *
8 : : * For licensing information, see the file 'LICENCE' in this directory.
9 : : *
10 : : */
11 : :
12 : : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 : :
14 : : #include <linux/kernel.h>
15 : : #include <linux/slab.h>
16 : : #include <linux/fs.h>
17 : : #include <linux/sched.h>
18 : : #include <linux/time.h>
19 : : #include <linux/crc32.h>
20 : : #include <linux/jffs2.h>
21 : : #include <linux/xattr.h>
22 : : #include <linux/posix_acl_xattr.h>
23 : : #include <linux/mtd/mtd.h>
24 : : #include "nodelist.h"
25 : :
26 : : static size_t jffs2_acl_size(int count)
27 : : {
28 [ # # ]: 0 : if (count <= 4) {
29 : 0 : return sizeof(struct jffs2_acl_header)
30 : 0 : + count * sizeof(struct jffs2_acl_entry_short);
31 : : } else {
32 : 0 : return sizeof(struct jffs2_acl_header)
33 : : + 4 * sizeof(struct jffs2_acl_entry_short)
34 : 0 : + (count - 4) * sizeof(struct jffs2_acl_entry);
35 : : }
36 : : }
37 : :
38 : : static int jffs2_acl_count(size_t size)
39 : : {
40 : : size_t s;
41 : :
42 : 0 : size -= sizeof(struct jffs2_acl_header);
43 [ # # ]: 0 : if (size < 4 * sizeof(struct jffs2_acl_entry_short)) {
44 [ # # ]: 0 : if (size % sizeof(struct jffs2_acl_entry_short))
45 : : return -1;
46 : 0 : return size / sizeof(struct jffs2_acl_entry_short);
47 : : } else {
48 : 0 : s = size - 4 * sizeof(struct jffs2_acl_entry_short);
49 [ # # ]: 0 : if (s % sizeof(struct jffs2_acl_entry))
50 : : return -1;
51 : 0 : return s / sizeof(struct jffs2_acl_entry) + 4;
52 : : }
53 : : }
54 : :
55 : 0 : static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size)
56 : : {
57 : 0 : void *end = value + size;
58 : : struct jffs2_acl_header *header = value;
59 : : struct jffs2_acl_entry *entry;
60 : : struct posix_acl *acl;
61 : : uint32_t ver;
62 : : int i, count;
63 : :
64 [ # # ]: 0 : if (!value)
65 : : return NULL;
66 [ # # ]: 0 : if (size < sizeof(struct jffs2_acl_header))
67 : : return ERR_PTR(-EINVAL);
68 : 0 : ver = je32_to_cpu(header->a_version);
69 [ # # ]: 0 : if (ver != JFFS2_ACL_VERSION) {
70 : 0 : JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);
71 : 0 : return ERR_PTR(-EINVAL);
72 : : }
73 : :
74 : 0 : value += sizeof(struct jffs2_acl_header);
75 : : count = jffs2_acl_count(size);
76 [ # # ]: 0 : if (count < 0)
77 : : return ERR_PTR(-EINVAL);
78 [ # # ]: 0 : if (count == 0)
79 : : return NULL;
80 : :
81 : 0 : acl = posix_acl_alloc(count, GFP_KERNEL);
82 [ # # ]: 0 : if (!acl)
83 : : return ERR_PTR(-ENOMEM);
84 : :
85 [ # # ]: 0 : for (i=0; i < count; i++) {
86 : : entry = value;
87 [ # # ]: 0 : if (value + sizeof(struct jffs2_acl_entry_short) > end)
88 : : goto fail;
89 : 0 : acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);
90 : 0 : acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);
91 [ # # ][ # # ]: 0 : switch (acl->a_entries[i].e_tag) {
[ # # ][ # # ]
92 : : case ACL_USER_OBJ:
93 : : case ACL_GROUP_OBJ:
94 : : case ACL_MASK:
95 : : case ACL_OTHER:
96 : : value += sizeof(struct jffs2_acl_entry_short);
97 : : break;
98 : :
99 : : case ACL_USER:
100 : 0 : value += sizeof(struct jffs2_acl_entry);
101 [ # # ]: 0 : if (value > end)
102 : : goto fail;
103 : 0 : acl->a_entries[i].e_uid =
104 : 0 : make_kuid(&init_user_ns,
105 : : je32_to_cpu(entry->e_id));
106 : 0 : break;
107 : : case ACL_GROUP:
108 : 0 : value += sizeof(struct jffs2_acl_entry);
109 [ # # ]: 0 : if (value > end)
110 : : goto fail;
111 : 0 : acl->a_entries[i].e_gid =
112 : 0 : make_kgid(&init_user_ns,
113 : : je32_to_cpu(entry->e_id));
114 : 0 : break;
115 : :
116 : : default:
117 : : goto fail;
118 : : }
119 : : }
120 [ # # ]: 0 : if (value != end)
121 : : goto fail;
122 : : return acl;
123 : : fail:
124 : : posix_acl_release(acl);
125 : : return ERR_PTR(-EINVAL);
126 : : }
127 : :
128 : 0 : static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
129 : : {
130 : : struct jffs2_acl_header *header;
131 : : struct jffs2_acl_entry *entry;
132 : : void *e;
133 : : size_t i;
134 : :
135 : 0 : *size = jffs2_acl_size(acl->a_count);
136 : 0 : header = kmalloc(sizeof(*header) + acl->a_count * sizeof(*entry), GFP_KERNEL);
137 [ # # ]: 0 : if (!header)
138 : : return ERR_PTR(-ENOMEM);
139 : 0 : header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
140 : 0 : e = header + 1;
141 [ # # ]: 0 : for (i=0; i < acl->a_count; i++) {
142 : 0 : const struct posix_acl_entry *acl_e = &acl->a_entries[i];
143 : : entry = e;
144 : 0 : entry->e_tag = cpu_to_je16(acl_e->e_tag);
145 : 0 : entry->e_perm = cpu_to_je16(acl_e->e_perm);
146 [ # # ][ # # ]: 0 : switch(acl_e->e_tag) {
[ # # ][ # # ]
147 : : case ACL_USER:
148 : 0 : entry->e_id = cpu_to_je32(
149 : : from_kuid(&init_user_ns, acl_e->e_uid));
150 : 0 : e += sizeof(struct jffs2_acl_entry);
151 : 0 : break;
152 : : case ACL_GROUP:
153 : 0 : entry->e_id = cpu_to_je32(
154 : : from_kgid(&init_user_ns, acl_e->e_gid));
155 : 0 : e += sizeof(struct jffs2_acl_entry);
156 : 0 : break;
157 : :
158 : : case ACL_USER_OBJ:
159 : : case ACL_GROUP_OBJ:
160 : : case ACL_MASK:
161 : : case ACL_OTHER:
162 : 0 : e += sizeof(struct jffs2_acl_entry_short);
163 : 0 : break;
164 : :
165 : : default:
166 : : goto fail;
167 : : }
168 : : }
169 : : return header;
170 : : fail:
171 : 0 : kfree(header);
172 : 0 : return ERR_PTR(-EINVAL);
173 : : }
174 : :
175 : 0 : struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
176 : : {
177 : : struct posix_acl *acl;
178 : : char *value = NULL;
179 : : int rc, xprefix;
180 : :
181 [ # # # ]: 0 : switch (type) {
182 : : case ACL_TYPE_ACCESS:
183 : : xprefix = JFFS2_XPREFIX_ACL_ACCESS;
184 : : break;
185 : : case ACL_TYPE_DEFAULT:
186 : : xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
187 : 0 : break;
188 : : default:
189 : 0 : BUG();
190 : : }
191 : 0 : rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
192 [ # # ]: 0 : if (rc > 0) {
193 : 0 : value = kmalloc(rc, GFP_KERNEL);
194 [ # # ]: 0 : if (!value)
195 : : return ERR_PTR(-ENOMEM);
196 : 0 : rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);
197 : : }
198 [ # # ]: 0 : if (rc > 0) {
199 : 0 : acl = jffs2_acl_from_medium(value, rc);
200 [ # # ]: 0 : } else if (rc == -ENODATA || rc == -ENOSYS) {
201 : : acl = NULL;
202 : : } else {
203 : : acl = ERR_PTR(rc);
204 : : }
205 [ # # ]: 0 : if (value)
206 : 0 : kfree(value);
207 [ # # ]: 0 : if (!IS_ERR(acl))
208 : 0 : set_cached_acl(inode, type, acl);
209 : 0 : return acl;
210 : : }
211 : :
212 : 0 : static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl)
213 : : {
214 : : char *value = NULL;
215 : 0 : size_t size = 0;
216 : : int rc;
217 : :
218 [ # # ]: 0 : if (acl) {
219 : 0 : value = jffs2_acl_to_medium(acl, &size);
220 [ # # ]: 0 : if (IS_ERR(value))
221 : 0 : return PTR_ERR(value);
222 : : }
223 : 0 : rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
224 [ # # ]: 0 : if (!value && rc == -ENODATA)
225 : : rc = 0;
226 : 0 : kfree(value);
227 : :
228 : 0 : return rc;
229 : : }
230 : :
231 : 0 : int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
232 : : {
233 : : int rc, xprefix;
234 : :
235 [ # # # ]: 0 : switch (type) {
236 : : case ACL_TYPE_ACCESS:
237 : : xprefix = JFFS2_XPREFIX_ACL_ACCESS;
238 [ # # ]: 0 : if (acl) {
239 : 0 : umode_t mode = inode->i_mode;
240 : 0 : rc = posix_acl_equiv_mode(acl, &mode);
241 [ # # ]: 0 : if (rc < 0)
242 : 0 : return rc;
243 [ # # ]: 0 : if (inode->i_mode != mode) {
244 : : struct iattr attr;
245 : :
246 : 0 : attr.ia_valid = ATTR_MODE | ATTR_CTIME;
247 : 0 : attr.ia_mode = mode;
248 : 0 : attr.ia_ctime = CURRENT_TIME_SEC;
249 : 0 : rc = jffs2_do_setattr(inode, &attr);
250 [ # # ]: 0 : if (rc < 0)
251 : 0 : return rc;
252 : : }
253 [ # # ]: 0 : if (rc == 0)
254 : : acl = NULL;
255 : : }
256 : : break;
257 : : case ACL_TYPE_DEFAULT:
258 : : xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
259 [ # # ]: 0 : if (!S_ISDIR(inode->i_mode))
260 [ # # ]: 0 : return acl ? -EACCES : 0;
261 : : break;
262 : : default:
263 : : return -EINVAL;
264 : : }
265 : 0 : rc = __jffs2_set_acl(inode, xprefix, acl);
266 [ # # ]: 0 : if (!rc)
267 : 0 : set_cached_acl(inode, type, acl);
268 : 0 : return rc;
269 : : }
270 : :
271 : 0 : int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
272 : : {
273 : : struct posix_acl *default_acl, *acl;
274 : : int rc;
275 : :
276 : : cache_no_acl(inode);
277 : :
278 : 0 : rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl);
279 [ # # ]: 0 : if (rc)
280 : : return rc;
281 : :
282 [ # # ]: 0 : if (default_acl) {
283 : 0 : set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
284 : 0 : posix_acl_release(default_acl);
285 : : }
286 [ # # ]: 0 : if (acl) {
287 : 0 : set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
288 : 0 : posix_acl_release(acl);
289 : : }
290 : : return 0;
291 : : }
292 : :
293 : 0 : int jffs2_init_acl_post(struct inode *inode)
294 : : {
295 : : int rc;
296 : :
297 [ # # ]: 0 : if (inode->i_default_acl) {
298 : 0 : rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl);
299 [ # # ]: 0 : if (rc)
300 : : return rc;
301 : : }
302 : :
303 [ # # ]: 0 : if (inode->i_acl) {
304 : 0 : rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl);
305 [ # # ]: 0 : if (rc)
306 : 0 : return rc;
307 : : }
308 : :
309 : : return 0;
310 : : }
|