xref: /openbmc/linux/fs/ocfs2/acl.c (revision 57904291176fa16a981cefca5cbe1a0b50196792)
1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   * acl.c
4   *
5   * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
6   *
7   * CREDITS:
8   * Lots of code in this file is copy from linux/fs/ext3/acl.c.
9   * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
10   */
11  
12  #include <linux/init.h>
13  #include <linux/module.h>
14  #include <linux/slab.h>
15  #include <linux/string.h>
16  
17  #include <cluster/masklog.h>
18  
19  #include "ocfs2.h"
20  #include "alloc.h"
21  #include "dlmglue.h"
22  #include "file.h"
23  #include "inode.h"
24  #include "journal.h"
25  #include "ocfs2_fs.h"
26  
27  #include "xattr.h"
28  #include "acl.h"
29  
30  /*
31   * Convert from xattr value to acl struct.
32   */
ocfs2_acl_from_xattr(const void * value,size_t size)33  static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
34  {
35  	int n, count;
36  	struct posix_acl *acl;
37  
38  	if (!value)
39  		return NULL;
40  	if (size < sizeof(struct posix_acl_entry))
41  		return ERR_PTR(-EINVAL);
42  
43  	count = size / sizeof(struct posix_acl_entry);
44  
45  	acl = posix_acl_alloc(count, GFP_NOFS);
46  	if (!acl)
47  		return ERR_PTR(-ENOMEM);
48  	for (n = 0; n < count; n++) {
49  		struct ocfs2_acl_entry *entry =
50  			(struct ocfs2_acl_entry *)value;
51  
52  		acl->a_entries[n].e_tag  = le16_to_cpu(entry->e_tag);
53  		acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
54  		switch(acl->a_entries[n].e_tag) {
55  		case ACL_USER:
56  			acl->a_entries[n].e_uid =
57  				make_kuid(&init_user_ns,
58  					  le32_to_cpu(entry->e_id));
59  			break;
60  		case ACL_GROUP:
61  			acl->a_entries[n].e_gid =
62  				make_kgid(&init_user_ns,
63  					  le32_to_cpu(entry->e_id));
64  			break;
65  		default:
66  			break;
67  		}
68  		value += sizeof(struct posix_acl_entry);
69  
70  	}
71  	return acl;
72  }
73  
74  /*
75   * Convert acl struct to xattr value.
76   */
ocfs2_acl_to_xattr(const struct posix_acl * acl,size_t * size)77  static void *ocfs2_acl_to_xattr(const struct posix_acl *acl, size_t *size)
78  {
79  	struct ocfs2_acl_entry *entry = NULL;
80  	char *ocfs2_acl;
81  	size_t n;
82  
83  	*size = acl->a_count * sizeof(struct posix_acl_entry);
84  
85  	ocfs2_acl = kmalloc(*size, GFP_NOFS);
86  	if (!ocfs2_acl)
87  		return ERR_PTR(-ENOMEM);
88  
89  	entry = (struct ocfs2_acl_entry *)ocfs2_acl;
90  	for (n = 0; n < acl->a_count; n++, entry++) {
91  		entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
92  		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
93  		switch(acl->a_entries[n].e_tag) {
94  		case ACL_USER:
95  			entry->e_id = cpu_to_le32(
96  				from_kuid(&init_user_ns,
97  					  acl->a_entries[n].e_uid));
98  			break;
99  		case ACL_GROUP:
100  			entry->e_id = cpu_to_le32(
101  				from_kgid(&init_user_ns,
102  					  acl->a_entries[n].e_gid));
103  			break;
104  		default:
105  			entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
106  			break;
107  		}
108  	}
109  	return ocfs2_acl;
110  }
111  
ocfs2_get_acl_nolock(struct inode * inode,int type,struct buffer_head * di_bh)112  static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
113  					      int type,
114  					      struct buffer_head *di_bh)
115  {
116  	int name_index;
117  	char *value = NULL;
118  	struct posix_acl *acl;
119  	int retval;
120  
121  	switch (type) {
122  	case ACL_TYPE_ACCESS:
123  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
124  		break;
125  	case ACL_TYPE_DEFAULT:
126  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
127  		break;
128  	default:
129  		return ERR_PTR(-EINVAL);
130  	}
131  
132  	retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index, "", NULL, 0);
133  	if (retval > 0) {
134  		value = kmalloc(retval, GFP_NOFS);
135  		if (!value)
136  			return ERR_PTR(-ENOMEM);
137  		retval = ocfs2_xattr_get_nolock(inode, di_bh, name_index,
138  						"", value, retval);
139  	}
140  
141  	if (retval > 0)
142  		acl = ocfs2_acl_from_xattr(value, retval);
143  	else if (retval == -ENODATA || retval == 0)
144  		acl = NULL;
145  	else
146  		acl = ERR_PTR(retval);
147  
148  	kfree(value);
149  
150  	return acl;
151  }
152  
153  /*
154   * Helper function to set i_mode in memory and disk. Some call paths
155   * will not have di_bh or a journal handle to pass, in which case it
156   * will create it's own.
157   */
ocfs2_acl_set_mode(struct inode * inode,struct buffer_head * di_bh,handle_t * handle,umode_t new_mode)158  static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head *di_bh,
159  			      handle_t *handle, umode_t new_mode)
160  {
161  	int ret, commit_handle = 0;
162  	struct ocfs2_dinode *di;
163  
164  	if (di_bh == NULL) {
165  		ret = ocfs2_read_inode_block(inode, &di_bh);
166  		if (ret) {
167  			mlog_errno(ret);
168  			goto out;
169  		}
170  	} else
171  		get_bh(di_bh);
172  
173  	if (handle == NULL) {
174  		handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb),
175  					   OCFS2_INODE_UPDATE_CREDITS);
176  		if (IS_ERR(handle)) {
177  			ret = PTR_ERR(handle);
178  			mlog_errno(ret);
179  			goto out_brelse;
180  		}
181  
182  		commit_handle = 1;
183  	}
184  
185  	di = (struct ocfs2_dinode *)di_bh->b_data;
186  	ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), di_bh,
187  				      OCFS2_JOURNAL_ACCESS_WRITE);
188  	if (ret) {
189  		mlog_errno(ret);
190  		goto out_commit;
191  	}
192  
193  	inode->i_mode = new_mode;
194  	inode_set_ctime_current(inode);
195  	di->i_mode = cpu_to_le16(inode->i_mode);
196  	di->i_ctime = cpu_to_le64(inode_get_ctime_sec(inode));
197  	di->i_ctime_nsec = cpu_to_le32(inode_get_ctime_nsec(inode));
198  	ocfs2_update_inode_fsync_trans(handle, inode, 0);
199  
200  	ocfs2_journal_dirty(handle, di_bh);
201  
202  out_commit:
203  	if (commit_handle)
204  		ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
205  out_brelse:
206  	brelse(di_bh);
207  out:
208  	return ret;
209  }
210  
211  /*
212   * Set the access or default ACL of an inode.
213   */
ocfs2_set_acl(handle_t * handle,struct inode * inode,struct buffer_head * di_bh,int type,struct posix_acl * acl,struct ocfs2_alloc_context * meta_ac,struct ocfs2_alloc_context * data_ac)214  static int ocfs2_set_acl(handle_t *handle,
215  			 struct inode *inode,
216  			 struct buffer_head *di_bh,
217  			 int type,
218  			 struct posix_acl *acl,
219  			 struct ocfs2_alloc_context *meta_ac,
220  			 struct ocfs2_alloc_context *data_ac)
221  {
222  	int name_index;
223  	void *value = NULL;
224  	size_t size = 0;
225  	int ret;
226  
227  	if (S_ISLNK(inode->i_mode))
228  		return -EOPNOTSUPP;
229  
230  	switch (type) {
231  	case ACL_TYPE_ACCESS:
232  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS;
233  		break;
234  	case ACL_TYPE_DEFAULT:
235  		name_index = OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT;
236  		if (!S_ISDIR(inode->i_mode))
237  			return acl ? -EACCES : 0;
238  		break;
239  	default:
240  		return -EINVAL;
241  	}
242  
243  	if (acl) {
244  		value = ocfs2_acl_to_xattr(acl, &size);
245  		if (IS_ERR(value))
246  			return (int)PTR_ERR(value);
247  	}
248  
249  	if (handle)
250  		ret = ocfs2_xattr_set_handle(handle, inode, di_bh, name_index,
251  					     "", value, size, 0,
252  					     meta_ac, data_ac);
253  	else
254  		ret = ocfs2_xattr_set(inode, name_index, "", value, size, 0);
255  
256  	kfree(value);
257  	if (!ret)
258  		set_cached_acl(inode, type, acl);
259  
260  	return ret;
261  }
262  
ocfs2_iop_set_acl(struct mnt_idmap * idmap,struct dentry * dentry,struct posix_acl * acl,int type)263  int ocfs2_iop_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
264  		      struct posix_acl *acl, int type)
265  {
266  	struct buffer_head *bh = NULL;
267  	int status, had_lock;
268  	struct ocfs2_lock_holder oh;
269  	struct inode *inode = d_inode(dentry);
270  
271  	had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
272  	if (had_lock < 0)
273  		return had_lock;
274  	if (type == ACL_TYPE_ACCESS && acl) {
275  		umode_t mode;
276  
277  		status = posix_acl_update_mode(&nop_mnt_idmap, inode, &mode,
278  					       &acl);
279  		if (status)
280  			goto unlock;
281  
282  		status = ocfs2_acl_set_mode(inode, bh, NULL, mode);
283  		if (status)
284  			goto unlock;
285  	}
286  	status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL);
287  unlock:
288  	ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
289  	brelse(bh);
290  	return status;
291  }
292  
ocfs2_iop_get_acl(struct inode * inode,int type,bool rcu)293  struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type, bool rcu)
294  {
295  	struct ocfs2_super *osb;
296  	struct buffer_head *di_bh = NULL;
297  	struct posix_acl *acl;
298  	int had_lock;
299  	struct ocfs2_lock_holder oh;
300  
301  	if (rcu)
302  		return ERR_PTR(-ECHILD);
303  
304  	osb = OCFS2_SB(inode->i_sb);
305  	if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
306  		return NULL;
307  
308  	had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
309  	if (had_lock < 0)
310  		return ERR_PTR(had_lock);
311  
312  	down_read(&OCFS2_I(inode)->ip_xattr_sem);
313  	acl = ocfs2_get_acl_nolock(inode, type, di_bh);
314  	up_read(&OCFS2_I(inode)->ip_xattr_sem);
315  
316  	ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);
317  	brelse(di_bh);
318  	return acl;
319  }
320  
ocfs2_acl_chmod(struct inode * inode,struct buffer_head * bh)321  int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
322  {
323  	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
324  	struct posix_acl *acl;
325  	int ret;
326  
327  	if (S_ISLNK(inode->i_mode))
328  		return -EOPNOTSUPP;
329  
330  	if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
331  		return 0;
332  
333  	down_read(&OCFS2_I(inode)->ip_xattr_sem);
334  	acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
335  	up_read(&OCFS2_I(inode)->ip_xattr_sem);
336  	if (IS_ERR_OR_NULL(acl))
337  		return PTR_ERR_OR_ZERO(acl);
338  	ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
339  	if (ret)
340  		return ret;
341  	ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
342  			    acl, NULL, NULL);
343  	posix_acl_release(acl);
344  	return ret;
345  }
346  
347  /*
348   * Initialize the ACLs of a new inode. If parent directory has default ACL,
349   * then clone to new inode. Called from ocfs2_mknod.
350   */
ocfs2_init_acl(handle_t * handle,struct inode * inode,struct inode * dir,struct buffer_head * di_bh,struct buffer_head * dir_bh,struct ocfs2_alloc_context * meta_ac,struct ocfs2_alloc_context * data_ac)351  int ocfs2_init_acl(handle_t *handle,
352  		   struct inode *inode,
353  		   struct inode *dir,
354  		   struct buffer_head *di_bh,
355  		   struct buffer_head *dir_bh,
356  		   struct ocfs2_alloc_context *meta_ac,
357  		   struct ocfs2_alloc_context *data_ac)
358  {
359  	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
360  	struct posix_acl *acl = NULL;
361  	int ret = 0, ret2;
362  	umode_t mode;
363  
364  	if (!S_ISLNK(inode->i_mode)) {
365  		if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
366  			down_read(&OCFS2_I(dir)->ip_xattr_sem);
367  			acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
368  						   dir_bh);
369  			up_read(&OCFS2_I(dir)->ip_xattr_sem);
370  			if (IS_ERR(acl))
371  				return PTR_ERR(acl);
372  		}
373  		if (!acl) {
374  			mode = inode->i_mode & ~current_umask();
375  			ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
376  			if (ret) {
377  				mlog_errno(ret);
378  				goto cleanup;
379  			}
380  		}
381  	}
382  	if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
383  		if (S_ISDIR(inode->i_mode)) {
384  			ret = ocfs2_set_acl(handle, inode, di_bh,
385  					    ACL_TYPE_DEFAULT, acl,
386  					    meta_ac, data_ac);
387  			if (ret)
388  				goto cleanup;
389  		}
390  		mode = inode->i_mode;
391  		ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
392  		if (ret < 0)
393  			return ret;
394  
395  		ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
396  		if (ret2) {
397  			mlog_errno(ret2);
398  			ret = ret2;
399  			goto cleanup;
400  		}
401  		if (ret > 0) {
402  			ret = ocfs2_set_acl(handle, inode,
403  					    di_bh, ACL_TYPE_ACCESS,
404  					    acl, meta_ac, data_ac);
405  		}
406  	}
407  cleanup:
408  	posix_acl_release(acl);
409  	return ret;
410  }
411