Blame view

fs/xfs/xfs_acl.c 8.71 KB
ef14f0c15   Christoph Hellwig   xfs: use generic ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  /*
   * Copyright (c) 2008, Christoph Hellwig
   * All Rights Reserved.
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation.
   *
   * 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.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write the Free Software Foundation,
   * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
  #include "xfs.h"
  #include "xfs_acl.h"
  #include "xfs_attr.h"
  #include "xfs_bmap_btree.h"
  #include "xfs_inode.h"
  #include "xfs_vnodeops.h"
0b1b213fc   Christoph Hellwig   xfs: event tracin...
24
  #include "xfs_trace.h"
5a0e3ad6a   Tejun Heo   include cleanup: ...
25
  #include <linux/slab.h>
ef14f0c15   Christoph Hellwig   xfs: use generic ...
26
27
  #include <linux/xattr.h>
  #include <linux/posix_acl_xattr.h>
ef14f0c15   Christoph Hellwig   xfs: use generic ...
28
29
30
31
  /*
   * Locking scheme:
   *  - all ACL updates are protected by inode->i_mutex, which is taken before
   *    calling into this file.
ef14f0c15   Christoph Hellwig   xfs: use generic ...
32
33
34
35
36
37
38
39
   */
  
  STATIC struct posix_acl *
  xfs_acl_from_disk(struct xfs_acl *aclp)
  {
  	struct posix_acl_entry *acl_e;
  	struct posix_acl *acl;
  	struct xfs_acl_entry *ace;
093019cf1   Xi Wang   xfs: fix acl coun...
40
  	unsigned int count, i;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
41
42
  
  	count = be32_to_cpu(aclp->acl_cnt);
fa8b18edd   Christoph Hellwig   xfs: validate acl...
43
44
  	if (count > XFS_ACL_MAX_ENTRIES)
  		return ERR_PTR(-EFSCORRUPTED);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  
  	acl = posix_acl_alloc(count, GFP_KERNEL);
  	if (!acl)
  		return ERR_PTR(-ENOMEM);
  
  	for (i = 0; i < count; i++) {
  		acl_e = &acl->a_entries[i];
  		ace = &aclp->acl_entry[i];
  
  		/*
  		 * The tag is 32 bits on disk and 16 bits in core.
  		 *
  		 * Because every access to it goes through the core
  		 * format first this is not a problem.
  		 */
  		acl_e->e_tag = be32_to_cpu(ace->ae_tag);
  		acl_e->e_perm = be16_to_cpu(ace->ae_perm);
  
  		switch (acl_e->e_tag) {
  		case ACL_USER:
  		case ACL_GROUP:
  			acl_e->e_id = be32_to_cpu(ace->ae_id);
  			break;
  		case ACL_USER_OBJ:
  		case ACL_GROUP_OBJ:
  		case ACL_MASK:
  		case ACL_OTHER:
  			acl_e->e_id = ACL_UNDEFINED_ID;
  			break;
  		default:
  			goto fail;
  		}
  	}
  	return acl;
  
  fail:
  	posix_acl_release(acl);
  	return ERR_PTR(-EINVAL);
  }
  
  STATIC void
  xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
  {
  	const struct posix_acl_entry *acl_e;
  	struct xfs_acl_entry *ace;
  	int i;
  
  	aclp->acl_cnt = cpu_to_be32(acl->a_count);
  	for (i = 0; i < acl->a_count; i++) {
  		ace = &aclp->acl_entry[i];
  		acl_e = &acl->a_entries[i];
  
  		ace->ae_tag = cpu_to_be32(acl_e->e_tag);
  		ace->ae_id = cpu_to_be32(acl_e->e_id);
  		ace->ae_perm = cpu_to_be16(acl_e->e_perm);
  	}
  }
ef14f0c15   Christoph Hellwig   xfs: use generic ...
102
103
104
105
  struct posix_acl *
  xfs_get_acl(struct inode *inode, int type)
  {
  	struct xfs_inode *ip = XFS_I(inode);
1cbd20d82   Al Viro   switch xfs to gen...
106
  	struct posix_acl *acl;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
107
108
  	struct xfs_acl *xfs_acl;
  	int len = sizeof(struct xfs_acl);
a9273ca5c   Dave Chinner   xfs: convert attr...
109
  	unsigned char *ea_name;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
110
  	int error;
1cbd20d82   Al Viro   switch xfs to gen...
111
112
113
  	acl = get_cached_acl(inode, type);
  	if (acl != ACL_NOT_CACHED)
  		return acl;
4e34e719e   Christoph Hellwig   fs: take the ACL ...
114
  	trace_xfs_get_acl(ip);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
115
116
117
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		ea_name = SGI_ACL_FILE;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
118
119
120
  		break;
  	case ACL_TYPE_DEFAULT:
  		ea_name = SGI_ACL_DEFAULT;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
121
122
  		break;
  	default:
1cbd20d82   Al Viro   switch xfs to gen...
123
  		BUG();
ef14f0c15   Christoph Hellwig   xfs: use generic ...
124
  	}
ef14f0c15   Christoph Hellwig   xfs: use generic ...
125
126
127
128
  	/*
  	 * If we have a cached ACLs value just return it, not need to
  	 * go out to the disk.
  	 */
ef14f0c15   Christoph Hellwig   xfs: use generic ...
129
130
131
132
  
  	xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
  	if (!xfs_acl)
  		return ERR_PTR(-ENOMEM);
a9273ca5c   Dave Chinner   xfs: convert attr...
133
134
  	error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl,
  							&len, ATTR_ROOT);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
135
136
137
138
  	if (error) {
  		/*
  		 * If the attribute doesn't exist make sure we have a negative
  		 * cache entry, for any other error assume it is transient and
1cbd20d82   Al Viro   switch xfs to gen...
139
  		 * leave the cache entry as ACL_NOT_CACHED.
ef14f0c15   Christoph Hellwig   xfs: use generic ...
140
141
142
143
144
145
146
147
148
149
150
151
152
  		 */
  		if (error == -ENOATTR) {
  			acl = NULL;
  			goto out_update_cache;
  		}
  		goto out;
  	}
  
  	acl = xfs_acl_from_disk(xfs_acl);
  	if (IS_ERR(acl))
  		goto out;
  
   out_update_cache:
1cbd20d82   Al Viro   switch xfs to gen...
153
  	set_cached_acl(inode, type, acl);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
154
155
156
157
158
159
160
161
162
   out:
  	kfree(xfs_acl);
  	return acl;
  }
  
  STATIC int
  xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
  {
  	struct xfs_inode *ip = XFS_I(inode);
a9273ca5c   Dave Chinner   xfs: convert attr...
163
  	unsigned char *ea_name;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
164
165
166
167
168
169
170
171
  	int error;
  
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
  
  	switch (type) {
  	case ACL_TYPE_ACCESS:
  		ea_name = SGI_ACL_FILE;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
172
173
174
175
176
  		break;
  	case ACL_TYPE_DEFAULT:
  		if (!S_ISDIR(inode->i_mode))
  			return acl ? -EACCES : 0;
  		ea_name = SGI_ACL_DEFAULT;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	if (acl) {
  		struct xfs_acl *xfs_acl;
  		int len;
  
  		xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL);
  		if (!xfs_acl)
  			return -ENOMEM;
  
  		xfs_acl_to_disk(xfs_acl, acl);
  		len = sizeof(struct xfs_acl) -
  			(sizeof(struct xfs_acl_entry) *
  			 (XFS_ACL_MAX_ENTRIES - acl->a_count));
a9273ca5c   Dave Chinner   xfs: convert attr...
194
  		error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
ef14f0c15   Christoph Hellwig   xfs: use generic ...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
  				len, ATTR_ROOT);
  
  		kfree(xfs_acl);
  	} else {
  		/*
  		 * A NULL ACL argument means we want to remove the ACL.
  		 */
  		error = -xfs_attr_remove(ip, ea_name, ATTR_ROOT);
  
  		/*
  		 * If the attribute didn't exist to start with that's fine.
  		 */
  		if (error == -ENOATTR)
  			error = 0;
  	}
  
  	if (!error)
1cbd20d82   Al Viro   switch xfs to gen...
212
  		set_cached_acl(inode, type, acl);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
213
214
  	return error;
  }
ef14f0c15   Christoph Hellwig   xfs: use generic ...
215
  static int
d3fb61207   Al Viro   switch posix_acl_...
216
  xfs_set_mode(struct inode *inode, umode_t mode)
ef14f0c15   Christoph Hellwig   xfs: use generic ...
217
218
219
220
221
  {
  	int error = 0;
  
  	if (mode != inode->i_mode) {
  		struct iattr iattr;
d6d59bada   Christoph Hellwig   xfs: fix timestam...
222
  		iattr.ia_valid = ATTR_MODE | ATTR_CTIME;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
223
  		iattr.ia_mode = mode;
d6d59bada   Christoph Hellwig   xfs: fix timestam...
224
  		iattr.ia_ctime = current_fs_time(inode->i_sb);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
225

c4ed4243c   Christoph Hellwig   xfs: split xfs_se...
226
  		error = -xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
227
228
229
230
231
232
  	}
  
  	return error;
  }
  
  static int
a9273ca5c   Dave Chinner   xfs: convert attr...
233
  xfs_acl_exists(struct inode *inode, unsigned char *name)
ef14f0c15   Christoph Hellwig   xfs: use generic ...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  {
  	int len = sizeof(struct xfs_acl);
  
  	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);
  }
  
  /*
   * No need for i_mutex because the inode is not yet exposed to the VFS.
   */
  int
826cae2f2   Al Viro   kill boilerplates...
259
  xfs_inherit_acl(struct inode *inode, struct posix_acl *acl)
ef14f0c15   Christoph Hellwig   xfs: use generic ...
260
  {
d3fb61207   Al Viro   switch posix_acl_...
261
  	umode_t mode = inode->i_mode;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
262
263
264
  	int error = 0, inherit = 0;
  
  	if (S_ISDIR(inode->i_mode)) {
826cae2f2   Al Viro   kill boilerplates...
265
  		error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
266
  		if (error)
826cae2f2   Al Viro   kill boilerplates...
267
  			goto out;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
268
  	}
826cae2f2   Al Viro   kill boilerplates...
269
  	error = posix_acl_create(&acl, GFP_KERNEL, &mode);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
270
  	if (error < 0)
826cae2f2   Al Viro   kill boilerplates...
271
  		return error;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
272
273
  
  	/*
826cae2f2   Al Viro   kill boilerplates...
274
  	 * If posix_acl_create returns a positive value we need to
ef14f0c15   Christoph Hellwig   xfs: use generic ...
275
276
277
278
279
280
281
282
  	 * inherit a permission that can't be represented using the Unix
  	 * mode bits and we actually need to set an ACL.
  	 */
  	if (error > 0)
  		inherit = 1;
  
  	error = xfs_set_mode(inode, mode);
  	if (error)
826cae2f2   Al Viro   kill boilerplates...
283
  		goto out;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
284
285
  
  	if (inherit)
826cae2f2   Al Viro   kill boilerplates...
286
  		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
287

826cae2f2   Al Viro   kill boilerplates...
288
289
  out:
  	posix_acl_release(acl);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
290
291
292
293
294
295
  	return error;
  }
  
  int
  xfs_acl_chmod(struct inode *inode)
  {
bc26ab5f6   Al Viro   kill boilerplate ...
296
  	struct posix_acl *acl;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
297
298
299
300
301
302
303
304
  	int error;
  
  	if (S_ISLNK(inode->i_mode))
  		return -EOPNOTSUPP;
  
  	acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
  	if (IS_ERR(acl) || !acl)
  		return PTR_ERR(acl);
bc26ab5f6   Al Viro   kill boilerplate ...
305
306
307
  	error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
  	if (error)
  		return error;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
308

bc26ab5f6   Al Viro   kill boilerplate ...
309
310
  	error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
  	posix_acl_release(acl);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
311
312
  	return error;
  }
ef14f0c15   Christoph Hellwig   xfs: use generic ...
313
  static int
431547b3c   Christoph Hellwig   sanitize xattr ha...
314
315
  xfs_xattr_acl_get(struct dentry *dentry, const char *name,
  		void *value, size_t size, int type)
ef14f0c15   Christoph Hellwig   xfs: use generic ...
316
317
  {
  	struct posix_acl *acl;
431547b3c   Christoph Hellwig   sanitize xattr ha...
318
  	int error;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
319

431547b3c   Christoph Hellwig   sanitize xattr ha...
320
  	acl = xfs_get_acl(dentry->d_inode, type);
ef14f0c15   Christoph Hellwig   xfs: use generic ...
321
322
323
324
325
326
327
328
329
330
331
332
  	if (IS_ERR(acl))
  		return PTR_ERR(acl);
  	if (acl == NULL)
  		return -ENODATA;
  
  	error = posix_acl_to_xattr(acl, value, size);
  	posix_acl_release(acl);
  
  	return error;
  }
  
  static int
431547b3c   Christoph Hellwig   sanitize xattr ha...
333
334
  xfs_xattr_acl_set(struct dentry *dentry, const char *name,
  		const void *value, size_t size, int flags, int type)
ef14f0c15   Christoph Hellwig   xfs: use generic ...
335
  {
431547b3c   Christoph Hellwig   sanitize xattr ha...
336
  	struct inode *inode = dentry->d_inode;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
337
  	struct posix_acl *acl = NULL;
431547b3c   Christoph Hellwig   sanitize xattr ha...
338
  	int error = 0;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
339

ef14f0c15   Christoph Hellwig   xfs: use generic ...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  	if (flags & XATTR_CREATE)
  		return -EINVAL;
  	if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
  		return value ? -EACCES : 0;
  	if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
  		return -EPERM;
  
  	if (!value)
  		goto set_acl;
  
  	acl = posix_acl_from_xattr(value, size);
  	if (!acl) {
  		/*
  		 * acl_set_file(3) may request that we set default ACLs with
  		 * zero length -- defend (gracefully) against that here.
  		 */
  		goto out;
  	}
  	if (IS_ERR(acl)) {
  		error = PTR_ERR(acl);
  		goto out;
  	}
  
  	error = posix_acl_valid(acl);
  	if (error)
  		goto out_release;
  
  	error = -EINVAL;
  	if (acl->a_count > XFS_ACL_MAX_ENTRIES)
  		goto out_release;
  
  	if (type == ACL_TYPE_ACCESS) {
d6952123b   Al Viro   switch posix_acl_...
372
  		umode_t mode = inode->i_mode;
ef14f0c15   Christoph Hellwig   xfs: use generic ...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  		error = posix_acl_equiv_mode(acl, &mode);
  
  		if (error <= 0) {
  			posix_acl_release(acl);
  			acl = NULL;
  
  			if (error < 0)
  				return error;
  		}
  
  		error = xfs_set_mode(inode, mode);
  		if (error)
  			goto out_release;
  	}
  
   set_acl:
  	error = xfs_set_acl(inode, type, acl);
   out_release:
  	posix_acl_release(acl);
   out:
  	return error;
  }
46e58764f   Stephen Hemminger   xfs: constify xat...
395
  const struct xattr_handler xfs_xattr_acl_access_handler = {
431547b3c   Christoph Hellwig   sanitize xattr ha...
396
397
398
399
400
  	.prefix	= POSIX_ACL_XATTR_ACCESS,
  	.flags	= ACL_TYPE_ACCESS,
  	.get	= xfs_xattr_acl_get,
  	.set	= xfs_xattr_acl_set,
  };
46e58764f   Stephen Hemminger   xfs: constify xat...
401
  const struct xattr_handler xfs_xattr_acl_default_handler = {
431547b3c   Christoph Hellwig   sanitize xattr ha...
402
403
404
405
  	.prefix	= POSIX_ACL_XATTR_DEFAULT,
  	.flags	= ACL_TYPE_DEFAULT,
  	.get	= xfs_xattr_acl_get,
  	.set	= xfs_xattr_acl_set,
ef14f0c15   Christoph Hellwig   xfs: use generic ...
406
  };