xref: /openbmc/linux/fs/ext4/acl.c (revision b6bec26c)
1  /*
2   * linux/fs/ext4/acl.c
3   *
4   * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
5   */
6  
7  #include <linux/init.h>
8  #include <linux/sched.h>
9  #include <linux/slab.h>
10  #include <linux/capability.h>
11  #include <linux/fs.h>
12  #include "ext4_jbd2.h"
13  #include "ext4.h"
14  #include "xattr.h"
15  #include "acl.h"
16  
17  /*
18   * Convert from filesystem to in-memory representation.
19   */
20  static struct posix_acl *
21  ext4_acl_from_disk(const void *value, size_t size)
22  {
23  	const char *end = (char *)value + size;
24  	int n, count;
25  	struct posix_acl *acl;
26  
27  	if (!value)
28  		return NULL;
29  	if (size < sizeof(ext4_acl_header))
30  		 return ERR_PTR(-EINVAL);
31  	if (((ext4_acl_header *)value)->a_version !=
32  	    cpu_to_le32(EXT4_ACL_VERSION))
33  		return ERR_PTR(-EINVAL);
34  	value = (char *)value + sizeof(ext4_acl_header);
35  	count = ext4_acl_count(size);
36  	if (count < 0)
37  		return ERR_PTR(-EINVAL);
38  	if (count == 0)
39  		return NULL;
40  	acl = posix_acl_alloc(count, GFP_NOFS);
41  	if (!acl)
42  		return ERR_PTR(-ENOMEM);
43  	for (n = 0; n < count; n++) {
44  		ext4_acl_entry *entry =
45  			(ext4_acl_entry *)value;
46  		if ((char *)value + sizeof(ext4_acl_entry_short) > end)
47  			goto fail;
48  		acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
49  		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
50  
51  		switch (acl->a_entries[n].e_tag) {
52  		case ACL_USER_OBJ:
53  		case ACL_GROUP_OBJ:
54  		case ACL_MASK:
55  		case ACL_OTHER:
56  			value = (char *)value +
57  				sizeof(ext4_acl_entry_short);
58  			break;
59  
60  		case ACL_USER:
61  			value = (char *)value + sizeof(ext4_acl_entry);
62  			if ((char *)value > end)
63  				goto fail;
64  			acl->a_entries[n].e_uid =
65  				make_kuid(&init_user_ns,
66  					  le32_to_cpu(entry->e_id));
67  			break;
68  		case ACL_GROUP:
69  			value = (char *)value + sizeof(ext4_acl_entry);
70  			if ((char *)value > end)
71  				goto fail;
72  			acl->a_entries[n].e_gid =
73  				make_kgid(&init_user_ns,
74  					  le32_to_cpu(entry->e_id));
75  			break;
76  
77  		default:
78  			goto fail;
79  		}
80  	}
81  	if (value != end)
82  		goto fail;
83  	return acl;
84  
85  fail:
86  	posix_acl_release(acl);
87  	return ERR_PTR(-EINVAL);
88  }
89  
90  /*
91   * Convert from in-memory to filesystem representation.
92   */
93  static void *
94  ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
95  {
96  	ext4_acl_header *ext_acl;
97  	char *e;
98  	size_t n;
99  
100  	*size = ext4_acl_size(acl->a_count);
101  	ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
102  			sizeof(ext4_acl_entry), GFP_NOFS);
103  	if (!ext_acl)
104  		return ERR_PTR(-ENOMEM);
105  	ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION);
106  	e = (char *)ext_acl + sizeof(ext4_acl_header);
107  	for (n = 0; n < acl->a_count; n++) {
108  		const struct posix_acl_entry *acl_e = &acl->a_entries[n];
109  		ext4_acl_entry *entry = (ext4_acl_entry *)e;
110  		entry->e_tag  = cpu_to_le16(acl_e->e_tag);
111  		entry->e_perm = cpu_to_le16(acl_e->e_perm);
112  		switch (acl_e->e_tag) {
113  		case ACL_USER:
114  			entry->e_id = cpu_to_le32(
115  				from_kuid(&init_user_ns, acl_e->e_uid));
116  			e += sizeof(ext4_acl_entry);
117  			break;
118  		case ACL_GROUP:
119  			entry->e_id = cpu_to_le32(
120  				from_kgid(&init_user_ns, acl_e->e_gid));
121  			e += sizeof(ext4_acl_entry);
122  			break;
123  
124  		case ACL_USER_OBJ:
125  		case ACL_GROUP_OBJ:
126  		case ACL_MASK:
127  		case ACL_OTHER:
128  			e += sizeof(ext4_acl_entry_short);
129  			break;
130  
131  		default:
132  			goto fail;
133  		}
134  	}
135  	return (char *)ext_acl;
136  
137  fail:
138  	kfree(ext_acl);
139  	return ERR_PTR(-EINVAL);
140  }
141  
142  /*
143   * Inode operation get_posix_acl().
144   *
145   * inode->i_mutex: don't care
146   */
147  struct posix_acl *
148  ext4_get_acl(struct inode *inode, int type)
149  {
150  	int name_index;
151  	char *value = NULL;
152  	struct posix_acl *acl;
153  	int retval;
154  
155  	if (!test_opt(inode->i_sb, POSIX_ACL))
156  		return NULL;
157  
158  	acl = get_cached_acl(inode, type);
159  	if (acl != ACL_NOT_CACHED)
160  		return acl;
161  
162  	switch (type) {
163  	case ACL_TYPE_ACCESS:
164  		name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
165  		break;
166  	case ACL_TYPE_DEFAULT:
167  		name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
168  		break;
169  	default:
170  		BUG();
171  	}
172  	retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
173  	if (retval > 0) {
174  		value = kmalloc(retval, GFP_NOFS);
175  		if (!value)
176  			return ERR_PTR(-ENOMEM);
177  		retval = ext4_xattr_get(inode, name_index, "", value, retval);
178  	}
179  	if (retval > 0)
180  		acl = ext4_acl_from_disk(value, retval);
181  	else if (retval == -ENODATA || retval == -ENOSYS)
182  		acl = NULL;
183  	else
184  		acl = ERR_PTR(retval);
185  	kfree(value);
186  
187  	if (!IS_ERR(acl))
188  		set_cached_acl(inode, type, acl);
189  
190  	return acl;
191  }
192  
193  /*
194   * Set the access or default ACL of an inode.
195   *
196   * inode->i_mutex: down unless called from ext4_new_inode
197   */
198  static int
199  ext4_set_acl(handle_t *handle, struct inode *inode, int type,
200  	     struct posix_acl *acl)
201  {
202  	int name_index;
203  	void *value = NULL;
204  	size_t size = 0;
205  	int error;
206  
207  	if (S_ISLNK(inode->i_mode))
208  		return -EOPNOTSUPP;
209  
210  	switch (type) {
211  	case ACL_TYPE_ACCESS:
212  		name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
213  		if (acl) {
214  			error = posix_acl_equiv_mode(acl, &inode->i_mode);
215  			if (error < 0)
216  				return error;
217  			else {
218  				inode->i_ctime = ext4_current_time(inode);
219  				ext4_mark_inode_dirty(handle, inode);
220  				if (error == 0)
221  					acl = NULL;
222  			}
223  		}
224  		break;
225  
226  	case ACL_TYPE_DEFAULT:
227  		name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
228  		if (!S_ISDIR(inode->i_mode))
229  			return acl ? -EACCES : 0;
230  		break;
231  
232  	default:
233  		return -EINVAL;
234  	}
235  	if (acl) {
236  		value = ext4_acl_to_disk(acl, &size);
237  		if (IS_ERR(value))
238  			return (int)PTR_ERR(value);
239  	}
240  
241  	error = ext4_xattr_set_handle(handle, inode, name_index, "",
242  				      value, size, 0);
243  
244  	kfree(value);
245  	if (!error)
246  		set_cached_acl(inode, type, acl);
247  
248  	return error;
249  }
250  
251  /*
252   * Initialize the ACLs of a new inode. Called from ext4_new_inode.
253   *
254   * dir->i_mutex: down
255   * inode->i_mutex: up (access to inode is still exclusive)
256   */
257  int
258  ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
259  {
260  	struct posix_acl *acl = NULL;
261  	int error = 0;
262  
263  	if (!S_ISLNK(inode->i_mode)) {
264  		if (test_opt(dir->i_sb, POSIX_ACL)) {
265  			acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT);
266  			if (IS_ERR(acl))
267  				return PTR_ERR(acl);
268  		}
269  		if (!acl)
270  			inode->i_mode &= ~current_umask();
271  	}
272  	if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
273  		if (S_ISDIR(inode->i_mode)) {
274  			error = ext4_set_acl(handle, inode,
275  					     ACL_TYPE_DEFAULT, acl);
276  			if (error)
277  				goto cleanup;
278  		}
279  		error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
280  		if (error < 0)
281  			return error;
282  
283  		if (error > 0) {
284  			/* This is an extended ACL */
285  			error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
286  		}
287  	}
288  cleanup:
289  	posix_acl_release(acl);
290  	return error;
291  }
292  
293  /*
294   * Does chmod for an inode that may have an Access Control List. The
295   * inode->i_mode field must be updated to the desired value by the caller
296   * before calling this function.
297   * Returns 0 on success, or a negative error number.
298   *
299   * We change the ACL rather than storing some ACL entries in the file
300   * mode permission bits (which would be more efficient), because that
301   * would break once additional permissions (like  ACL_APPEND, ACL_DELETE
302   * for directories) are added. There are no more bits available in the
303   * file mode.
304   *
305   * inode->i_mutex: down
306   */
307  int
308  ext4_acl_chmod(struct inode *inode)
309  {
310  	struct posix_acl *acl;
311  	handle_t *handle;
312  	int retries = 0;
313  	int error;
314  
315  
316  	if (S_ISLNK(inode->i_mode))
317  		return -EOPNOTSUPP;
318  	if (!test_opt(inode->i_sb, POSIX_ACL))
319  		return 0;
320  	acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
321  	if (IS_ERR(acl) || !acl)
322  		return PTR_ERR(acl);
323  	error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
324  	if (error)
325  		return error;
326  retry:
327  	handle = ext4_journal_start(inode,
328  			EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
329  	if (IS_ERR(handle)) {
330  		error = PTR_ERR(handle);
331  		ext4_std_error(inode->i_sb, error);
332  		goto out;
333  	}
334  	error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
335  	ext4_journal_stop(handle);
336  	if (error == -ENOSPC &&
337  	    ext4_should_retry_alloc(inode->i_sb, &retries))
338  		goto retry;
339  out:
340  	posix_acl_release(acl);
341  	return error;
342  }
343  
344  /*
345   * Extended attribute handlers
346   */
347  static size_t
348  ext4_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
349  			   const char *name, size_t name_len, int type)
350  {
351  	const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
352  
353  	if (!test_opt(dentry->d_sb, POSIX_ACL))
354  		return 0;
355  	if (list && size <= list_len)
356  		memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
357  	return size;
358  }
359  
360  static size_t
361  ext4_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
362  			    const char *name, size_t name_len, int type)
363  {
364  	const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
365  
366  	if (!test_opt(dentry->d_sb, POSIX_ACL))
367  		return 0;
368  	if (list && size <= list_len)
369  		memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
370  	return size;
371  }
372  
373  static int
374  ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
375  		   size_t size, int type)
376  {
377  	struct posix_acl *acl;
378  	int error;
379  
380  	if (strcmp(name, "") != 0)
381  		return -EINVAL;
382  	if (!test_opt(dentry->d_sb, POSIX_ACL))
383  		return -EOPNOTSUPP;
384  
385  	acl = ext4_get_acl(dentry->d_inode, type);
386  	if (IS_ERR(acl))
387  		return PTR_ERR(acl);
388  	if (acl == NULL)
389  		return -ENODATA;
390  	error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
391  	posix_acl_release(acl);
392  
393  	return error;
394  }
395  
396  static int
397  ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
398  		   size_t size, int flags, int type)
399  {
400  	struct inode *inode = dentry->d_inode;
401  	handle_t *handle;
402  	struct posix_acl *acl;
403  	int error, retries = 0;
404  
405  	if (strcmp(name, "") != 0)
406  		return -EINVAL;
407  	if (!test_opt(inode->i_sb, POSIX_ACL))
408  		return -EOPNOTSUPP;
409  	if (!inode_owner_or_capable(inode))
410  		return -EPERM;
411  
412  	if (value) {
413  		acl = posix_acl_from_xattr(&init_user_ns, value, size);
414  		if (IS_ERR(acl))
415  			return PTR_ERR(acl);
416  		else if (acl) {
417  			error = posix_acl_valid(acl);
418  			if (error)
419  				goto release_and_out;
420  		}
421  	} else
422  		acl = NULL;
423  
424  retry:
425  	handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
426  	if (IS_ERR(handle)) {
427  		error = PTR_ERR(handle);
428  		goto release_and_out;
429  	}
430  	error = ext4_set_acl(handle, inode, type, acl);
431  	ext4_journal_stop(handle);
432  	if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
433  		goto retry;
434  
435  release_and_out:
436  	posix_acl_release(acl);
437  	return error;
438  }
439  
440  const struct xattr_handler ext4_xattr_acl_access_handler = {
441  	.prefix	= POSIX_ACL_XATTR_ACCESS,
442  	.flags	= ACL_TYPE_ACCESS,
443  	.list	= ext4_xattr_list_acl_access,
444  	.get	= ext4_xattr_get_acl,
445  	.set	= ext4_xattr_set_acl,
446  };
447  
448  const struct xattr_handler ext4_xattr_acl_default_handler = {
449  	.prefix	= POSIX_ACL_XATTR_DEFAULT,
450  	.flags	= ACL_TYPE_DEFAULT,
451  	.list	= ext4_xattr_list_acl_default,
452  	.get	= ext4_xattr_get_acl,
453  	.set	= ext4_xattr_set_acl,
454  };
455