Merge tag 'dt-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / fs / ocfs2 / acl.c
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  */
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  */
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
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  */
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->i_ctime = current_time(inode);
195         di->i_mode = cpu_to_le16(inode->i_mode);
196         di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
197         di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
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  */
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
263 int ocfs2_iop_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
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
270         had_lock = ocfs2_inode_lock_tracker(inode, &bh, 1, &oh);
271         if (had_lock < 0)
272                 return had_lock;
273         if (type == ACL_TYPE_ACCESS && acl) {
274                 umode_t mode;
275
276                 status = posix_acl_update_mode(&init_user_ns, inode, &mode,
277                                                &acl);
278                 if (status)
279                         goto unlock;
280
281                 status = ocfs2_acl_set_mode(inode, bh, NULL, mode);
282                 if (status)
283                         goto unlock;
284         }
285         status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL);
286 unlock:
287         ocfs2_inode_unlock_tracker(inode, 1, &oh, had_lock);
288         brelse(bh);
289         return status;
290 }
291
292 struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
293 {
294         struct ocfs2_super *osb;
295         struct buffer_head *di_bh = NULL;
296         struct posix_acl *acl;
297         int had_lock;
298         struct ocfs2_lock_holder oh;
299
300         osb = OCFS2_SB(inode->i_sb);
301         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
302                 return NULL;
303
304         had_lock = ocfs2_inode_lock_tracker(inode, &di_bh, 0, &oh);
305         if (had_lock < 0)
306                 return ERR_PTR(had_lock);
307
308         down_read(&OCFS2_I(inode)->ip_xattr_sem);
309         acl = ocfs2_get_acl_nolock(inode, type, di_bh);
310         up_read(&OCFS2_I(inode)->ip_xattr_sem);
311
312         ocfs2_inode_unlock_tracker(inode, 0, &oh, had_lock);
313         brelse(di_bh);
314         return acl;
315 }
316
317 int ocfs2_acl_chmod(struct inode *inode, struct buffer_head *bh)
318 {
319         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
320         struct posix_acl *acl;
321         int ret;
322
323         if (S_ISLNK(inode->i_mode))
324                 return -EOPNOTSUPP;
325
326         if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
327                 return 0;
328
329         down_read(&OCFS2_I(inode)->ip_xattr_sem);
330         acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, bh);
331         up_read(&OCFS2_I(inode)->ip_xattr_sem);
332         if (IS_ERR_OR_NULL(acl))
333                 return PTR_ERR_OR_ZERO(acl);
334         ret = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
335         if (ret)
336                 return ret;
337         ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
338                             acl, NULL, NULL);
339         posix_acl_release(acl);
340         return ret;
341 }
342
343 /*
344  * Initialize the ACLs of a new inode. If parent directory has default ACL,
345  * then clone to new inode. Called from ocfs2_mknod.
346  */
347 int ocfs2_init_acl(handle_t *handle,
348                    struct inode *inode,
349                    struct inode *dir,
350                    struct buffer_head *di_bh,
351                    struct buffer_head *dir_bh,
352                    struct ocfs2_alloc_context *meta_ac,
353                    struct ocfs2_alloc_context *data_ac)
354 {
355         struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
356         struct posix_acl *acl = NULL;
357         int ret = 0, ret2;
358         umode_t mode;
359
360         if (!S_ISLNK(inode->i_mode)) {
361                 if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
362                         down_read(&OCFS2_I(dir)->ip_xattr_sem);
363                         acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
364                                                    dir_bh);
365                         up_read(&OCFS2_I(dir)->ip_xattr_sem);
366                         if (IS_ERR(acl))
367                                 return PTR_ERR(acl);
368                 }
369                 if (!acl) {
370                         mode = inode->i_mode & ~current_umask();
371                         ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
372                         if (ret) {
373                                 mlog_errno(ret);
374                                 goto cleanup;
375                         }
376                 }
377         }
378         if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
379                 if (S_ISDIR(inode->i_mode)) {
380                         ret = ocfs2_set_acl(handle, inode, di_bh,
381                                             ACL_TYPE_DEFAULT, acl,
382                                             meta_ac, data_ac);
383                         if (ret)
384                                 goto cleanup;
385                 }
386                 mode = inode->i_mode;
387                 ret = __posix_acl_create(&acl, GFP_NOFS, &mode);
388                 if (ret < 0)
389                         return ret;
390
391                 ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
392                 if (ret2) {
393                         mlog_errno(ret2);
394                         ret = ret2;
395                         goto cleanup;
396                 }
397                 if (ret > 0) {
398                         ret = ocfs2_set_acl(handle, inode,
399                                             di_bh, ACL_TYPE_ACCESS,
400                                             acl, meta_ac, data_ac);
401                 }
402         }
403 cleanup:
404         posix_acl_release(acl);
405         return ret;
406 }