Blame view

fs/jffs2/acl.c 6.67 KB
652ecc20d   KaiGai Kohei   [JFFS2][XATTR] Un...
1
2
  /*
   * JFFS2 -- Journalling Flash File System, Version 2.
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
3
   *
c00c310ea   David Woodhouse   [JFFS2] Tidy up l...
4
   * Copyright © 2006  NEC Corporation
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
5
   *
652ecc20d   KaiGai Kohei   [JFFS2][XATTR] Un...
6
7
8
9
10
   * Created by KaiGai Kohei <kaigai@ak.jp.nec.com>
   *
   * For licensing information, see the file 'LICENCE' in this directory.
   *
   */
c00c310ea   David Woodhouse   [JFFS2] Tidy up l...
11

5a528957e   Joe Perches   jffs2: Use pr_fmt...
12
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
13
14
15
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/fs.h>
914e26379   Al Viro   [PATCH] severing ...
16
  #include <linux/sched.h>
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
17
18
19
20
21
22
23
24
25
26
27
  #include <linux/time.h>
  #include <linux/crc32.h>
  #include <linux/jffs2.h>
  #include <linux/xattr.h>
  #include <linux/posix_acl_xattr.h>
  #include <linux/mtd/mtd.h>
  #include "nodelist.h"
  
  static size_t jffs2_acl_size(int count)
  {
  	if (count <= 4) {
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
28
29
  		return sizeof(struct jffs2_acl_header)
  		       + count * sizeof(struct jffs2_acl_entry_short);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
30
  	} else {
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
31
32
33
  		return sizeof(struct jffs2_acl_header)
  		       + 4 * sizeof(struct jffs2_acl_entry_short)
  		       + (count - 4) * sizeof(struct jffs2_acl_entry);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
34
35
36
37
38
39
  	}
  }
  
  static int jffs2_acl_count(size_t size)
  {
  	size_t s;
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
40
  	size -= sizeof(struct jffs2_acl_header);
fc371a25e   Roel Kluin   [JFFS2] jffs2_acl...
41
  	if (size < 4 * sizeof(struct jffs2_acl_entry_short)) {
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
42
  		if (size % sizeof(struct jffs2_acl_entry_short))
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
43
  			return -1;
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
44
  		return size / sizeof(struct jffs2_acl_entry_short);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
45
  	} else {
fc371a25e   Roel Kluin   [JFFS2] jffs2_acl...
46
  		s = size - 4 * sizeof(struct jffs2_acl_entry_short);
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
47
  		if (s % sizeof(struct jffs2_acl_entry))
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
48
  			return -1;
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
49
  		return s / sizeof(struct jffs2_acl_entry) + 4;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
50
51
  	}
  }
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
52
  static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
53
  {
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
54
55
56
  	void *end = value + size;
  	struct jffs2_acl_header *header = value;
  	struct jffs2_acl_entry *entry;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
57
58
59
60
61
62
  	struct posix_acl *acl;
  	uint32_t ver;
  	int i, count;
  
  	if (!value)
  		return NULL;
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
63
  	if (size < sizeof(struct jffs2_acl_header))
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
64
  		return ERR_PTR(-EINVAL);
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
65
  	ver = je32_to_cpu(header->a_version);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
66
67
68
69
70
  	if (ver != JFFS2_ACL_VERSION) {
  		JFFS2_WARNING("Invalid ACL version. (=%u)
  ", ver);
  		return ERR_PTR(-EINVAL);
  	}
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
71
  	value += sizeof(struct jffs2_acl_header);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
72
73
74
75
76
77
78
79
80
81
82
  	count = jffs2_acl_count(size);
  	if (count < 0)
  		return ERR_PTR(-EINVAL);
  	if (count == 0)
  		return NULL;
  
  	acl = posix_acl_alloc(count, GFP_KERNEL);
  	if (!acl)
  		return ERR_PTR(-ENOMEM);
  
  	for (i=0; i < count; i++) {
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
83
84
  		entry = value;
  		if (value + sizeof(struct jffs2_acl_entry_short) > end)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
85
86
87
88
89
90
91
92
  			goto fail;
  		acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);
  		acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);
  		switch (acl->a_entries[i].e_tag) {
  			case ACL_USER_OBJ:
  			case ACL_GROUP_OBJ:
  			case ACL_MASK:
  			case ACL_OTHER:
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
93
  				value += sizeof(struct jffs2_acl_entry_short);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
94
95
96
  				break;
  
  			case ACL_USER:
0cfe53d3c   Eric W. Biederman   userns: Convert j...
97
98
99
100
101
102
103
  				value += sizeof(struct jffs2_acl_entry);
  				if (value > end)
  					goto fail;
  				acl->a_entries[i].e_uid =
  					make_kuid(&init_user_ns,
  						  je32_to_cpu(entry->e_id));
  				break;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
104
  			case ACL_GROUP:
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
105
106
  				value += sizeof(struct jffs2_acl_entry);
  				if (value > end)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
107
  					goto fail;
0cfe53d3c   Eric W. Biederman   userns: Convert j...
108
109
110
  				acl->a_entries[i].e_gid =
  					make_kgid(&init_user_ns,
  						  je32_to_cpu(entry->e_id));
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  				break;
  
  			default:
  				goto fail;
  		}
  	}
  	if (value != end)
  		goto fail;
  	return acl;
   fail:
  	posix_acl_release(acl);
  	return ERR_PTR(-EINVAL);
  }
  
  static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size)
  {
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
127
128
129
  	struct jffs2_acl_header *header;
  	struct jffs2_acl_entry *entry;
  	void *e;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
130
131
132
  	size_t i;
  
  	*size = jffs2_acl_size(acl->a_count);
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
133
134
  	header = kmalloc(sizeof(*header) + acl->a_count * sizeof(*entry), GFP_KERNEL);
  	if (!header)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
135
  		return ERR_PTR(-ENOMEM);
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
136
137
  	header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);
  	e = header + 1;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
138
  	for (i=0; i < acl->a_count; i++) {
0cfe53d3c   Eric W. Biederman   userns: Convert j...
139
  		const struct posix_acl_entry *acl_e = &acl->a_entries[i];
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
140
  		entry = e;
0cfe53d3c   Eric W. Biederman   userns: Convert j...
141
142
143
  		entry->e_tag = cpu_to_je16(acl_e->e_tag);
  		entry->e_perm = cpu_to_je16(acl_e->e_perm);
  		switch(acl_e->e_tag) {
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
144
  			case ACL_USER:
0cfe53d3c   Eric W. Biederman   userns: Convert j...
145
146
147
148
  				entry->e_id = cpu_to_je32(
  					from_kuid(&init_user_ns, acl_e->e_uid));
  				e += sizeof(struct jffs2_acl_entry);
  				break;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
149
  			case ACL_GROUP:
0cfe53d3c   Eric W. Biederman   userns: Convert j...
150
151
  				entry->e_id = cpu_to_je32(
  					from_kgid(&init_user_ns, acl_e->e_gid));
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
152
  				e += sizeof(struct jffs2_acl_entry);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
153
154
155
156
157
158
  				break;
  
  			case ACL_USER_OBJ:
  			case ACL_GROUP_OBJ:
  			case ACL_MASK:
  			case ACL_OTHER:
de1f72fab   KaiGai Kohei   [JFFS2][XATTR] re...
159
  				e += sizeof(struct jffs2_acl_entry_short);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
160
161
162
163
164
165
  				break;
  
  			default:
  				goto fail;
  		}
  	}
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
166
  	return header;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
167
   fail:
dea80134d   KaiGai Kohei   [JFFS2][XATTR] re...
168
  	kfree(header);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
169
170
  	return ERR_PTR(-EINVAL);
  }
4e34e719e   Christoph Hellwig   fs: take the ACL ...
171
  struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
172
  {
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
173
174
175
176
177
178
  	struct posix_acl *acl;
  	char *value = NULL;
  	int rc, xprefix;
  
  	switch (type) {
  	case ACL_TYPE_ACCESS:
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
179
180
181
  		xprefix = JFFS2_XPREFIX_ACL_ACCESS;
  		break;
  	case ACL_TYPE_DEFAULT:
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
182
183
184
  		xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
  		break;
  	default:
073aaa1b1   Al Viro   helpers for acl c...
185
  		BUG();
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  	}
  	rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);
  	if (rc > 0) {
  		value = kmalloc(rc, GFP_KERNEL);
  		if (!value)
  			return ERR_PTR(-ENOMEM);
  		rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);
  	}
  	if (rc > 0) {
  		acl = jffs2_acl_from_medium(value, rc);
  	} else if (rc == -ENODATA || rc == -ENOSYS) {
  		acl = NULL;
  	} else {
  		acl = ERR_PTR(rc);
  	}
b6861d0a1   Fabian Frederick   fs/jffs2/acl.c: r...
201
  	kfree(value);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
202
203
  	return acl;
  }
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl)
  {
  	char *value = NULL;
  	size_t size = 0;
  	int rc;
  
  	if (acl) {
  		value = jffs2_acl_to_medium(acl, &size);
  		if (IS_ERR(value))
  			return PTR_ERR(value);
  	}
  	rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);
  	if (!value && rc == -ENODATA)
  		rc = 0;
  	kfree(value);
  
  	return rc;
  }
f2963d455   Christoph Hellwig   jffs2: use generi...
222
  int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
223
  {
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
224
  	int rc, xprefix;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
225
226
227
228
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		xprefix = JFFS2_XPREFIX_ACL_ACCESS;
  		if (acl) {
073931017   Jan Kara   posix_acl: Clear ...
229
230
231
232
  			umode_t mode;
  
  			rc = posix_acl_update_mode(inode, &mode, &acl);
  			if (rc)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
233
234
  				return rc;
  			if (inode->i_mode != mode) {
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
235
  				struct iattr attr;
1c24d06f8   Jan Kara   jffs2: update cti...
236
  				attr.ia_valid = ATTR_MODE | ATTR_CTIME;
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
237
  				attr.ia_mode = mode;
02027d42c   Deepa Dinamani   fs: Replace CURRE...
238
  				attr.ia_ctime = current_time(inode);
9ed437c50   David Woodhouse   [JFFS2] Fix ACL v...
239
240
241
  				rc = jffs2_do_setattr(inode, &attr);
  				if (rc < 0)
  					return rc;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
242
  			}
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
243
244
245
246
247
248
249
250
251
252
  		}
  		break;
  	case ACL_TYPE_DEFAULT:
  		xprefix = JFFS2_XPREFIX_ACL_DEFAULT;
  		if (!S_ISDIR(inode->i_mode))
  			return acl ? -EACCES : 0;
  		break;
  	default:
  		return -EINVAL;
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
253
  	rc = __jffs2_set_acl(inode, xprefix, acl);
073aaa1b1   Al Viro   helpers for acl c...
254
255
  	if (!rc)
  		set_cached_acl(inode, type, acl);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
256
257
  	return rc;
  }
d3fb61207   Al Viro   switch posix_acl_...
258
  int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
259
  {
f2963d455   Christoph Hellwig   jffs2: use generi...
260
  	struct posix_acl *default_acl, *acl;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
261
  	int rc;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
262

72c04902d   Al Viro   Get "no acls for ...
263
  	cache_no_acl(inode);
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
264

f2963d455   Christoph Hellwig   jffs2: use generi...
265
266
267
  	rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl);
  	if (rc)
  		return rc;
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
268

f2963d455   Christoph Hellwig   jffs2: use generi...
269
270
271
272
273
274
  	if (default_acl) {
  		set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
  		posix_acl_release(default_acl);
  	}
  	if (acl) {
  		set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
826cae2f2   Al Viro   kill boilerplates...
275
  		posix_acl_release(acl);
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
276
  	}
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
277
278
279
280
281
  	return 0;
  }
  
  int jffs2_init_acl_post(struct inode *inode)
  {
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
282
  	int rc;
290c263bf   Al Viro   switch jffs2 to i...
283
284
  	if (inode->i_default_acl) {
  		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, inode->i_default_acl);
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
285
286
287
  		if (rc)
  			return rc;
  	}
290c263bf   Al Viro   switch jffs2 to i...
288
289
  	if (inode->i_acl) {
  		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, inode->i_acl);
cfc8dc6f6   KaiGai Kohei   [JFFS2] Tidy up f...
290
291
292
  		if (rc)
  			return rc;
  	}
8d6ea587d   David Woodhouse   [JFFS2] Prevent r...
293
  	return 0;
aa98d7cf5   KaiGai Kohei   [JFFS2][XATTR] XA...
294
  }