1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
6 * http://www.samsung.com/
8 * Portions of this code from linux/fs/ext2/acl.c
10 * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
12 #include <linux/f2fs_fs.h>
17 static inline size_t f2fs_acl_size(int count
)
20 return sizeof(struct f2fs_acl_header
) +
21 count
* sizeof(struct f2fs_acl_entry_short
);
23 return sizeof(struct f2fs_acl_header
) +
24 4 * sizeof(struct f2fs_acl_entry_short
) +
25 (count
- 4) * sizeof(struct f2fs_acl_entry
);
29 static inline int f2fs_acl_count(size_t size
)
33 size
-= sizeof(struct f2fs_acl_header
);
34 s
= size
- 4 * sizeof(struct f2fs_acl_entry_short
);
36 if (size
% sizeof(struct f2fs_acl_entry_short
))
38 return size
/ sizeof(struct f2fs_acl_entry_short
);
40 if (s
% sizeof(struct f2fs_acl_entry
))
42 return s
/ sizeof(struct f2fs_acl_entry
) + 4;
46 static struct posix_acl
*f2fs_acl_from_disk(const char *value
, size_t size
)
49 struct posix_acl
*acl
;
50 struct f2fs_acl_header
*hdr
= (struct f2fs_acl_header
*)value
;
51 struct f2fs_acl_entry
*entry
= (struct f2fs_acl_entry
*)(hdr
+ 1);
52 const char *end
= value
+ size
;
54 if (size
< sizeof(struct f2fs_acl_header
))
55 return ERR_PTR(-EINVAL
);
57 if (hdr
->a_version
!= cpu_to_le32(F2FS_ACL_VERSION
))
58 return ERR_PTR(-EINVAL
);
60 count
= f2fs_acl_count(size
);
62 return ERR_PTR(-EINVAL
);
66 acl
= posix_acl_alloc(count
, GFP_NOFS
);
68 return ERR_PTR(-ENOMEM
);
70 for (i
= 0; i
< count
; i
++) {
72 if ((char *)entry
> end
)
75 acl
->a_entries
[i
].e_tag
= le16_to_cpu(entry
->e_tag
);
76 acl
->a_entries
[i
].e_perm
= le16_to_cpu(entry
->e_perm
);
78 switch (acl
->a_entries
[i
].e_tag
) {
83 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
84 sizeof(struct f2fs_acl_entry_short
));
88 acl
->a_entries
[i
].e_uid
=
89 make_kuid(&init_user_ns
,
90 le32_to_cpu(entry
->e_id
));
91 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
92 sizeof(struct f2fs_acl_entry
));
95 acl
->a_entries
[i
].e_gid
=
96 make_kgid(&init_user_ns
,
97 le32_to_cpu(entry
->e_id
));
98 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
99 sizeof(struct f2fs_acl_entry
));
105 if ((char *)entry
!= end
)
109 posix_acl_release(acl
);
110 return ERR_PTR(-EINVAL
);
113 static void *f2fs_acl_to_disk(struct f2fs_sb_info
*sbi
,
114 const struct posix_acl
*acl
, size_t *size
)
116 struct f2fs_acl_header
*f2fs_acl
;
117 struct f2fs_acl_entry
*entry
;
120 f2fs_acl
= f2fs_kmalloc(sbi
, sizeof(struct f2fs_acl_header
) +
121 acl
->a_count
* sizeof(struct f2fs_acl_entry
),
124 return ERR_PTR(-ENOMEM
);
126 f2fs_acl
->a_version
= cpu_to_le32(F2FS_ACL_VERSION
);
127 entry
= (struct f2fs_acl_entry
*)(f2fs_acl
+ 1);
129 for (i
= 0; i
< acl
->a_count
; i
++) {
131 entry
->e_tag
= cpu_to_le16(acl
->a_entries
[i
].e_tag
);
132 entry
->e_perm
= cpu_to_le16(acl
->a_entries
[i
].e_perm
);
134 switch (acl
->a_entries
[i
].e_tag
) {
136 entry
->e_id
= cpu_to_le32(
137 from_kuid(&init_user_ns
,
138 acl
->a_entries
[i
].e_uid
));
139 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
140 sizeof(struct f2fs_acl_entry
));
143 entry
->e_id
= cpu_to_le32(
144 from_kgid(&init_user_ns
,
145 acl
->a_entries
[i
].e_gid
));
146 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
147 sizeof(struct f2fs_acl_entry
));
153 entry
= (struct f2fs_acl_entry
*)((char *)entry
+
154 sizeof(struct f2fs_acl_entry_short
));
160 *size
= f2fs_acl_size(acl
->a_count
);
161 return (void *)f2fs_acl
;
165 return ERR_PTR(-EINVAL
);
168 static struct posix_acl
*__f2fs_get_acl(struct inode
*inode
, int type
,
171 int name_index
= F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT
;
173 struct posix_acl
*acl
;
176 if (type
== ACL_TYPE_ACCESS
)
177 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_ACCESS
;
179 retval
= f2fs_getxattr(inode
, name_index
, "", NULL
, 0, dpage
);
181 value
= f2fs_kmalloc(F2FS_I_SB(inode
), retval
, GFP_F2FS_ZERO
);
183 return ERR_PTR(-ENOMEM
);
184 retval
= f2fs_getxattr(inode
, name_index
, "", value
,
189 acl
= f2fs_acl_from_disk(value
, retval
);
190 else if (retval
== -ENODATA
)
193 acl
= ERR_PTR(retval
);
199 struct posix_acl
*f2fs_get_acl(struct inode
*inode
, int type
, bool rcu
)
202 return ERR_PTR(-ECHILD
);
204 return __f2fs_get_acl(inode
, type
, NULL
);
207 static int f2fs_acl_update_mode(struct user_namespace
*mnt_userns
,
208 struct inode
*inode
, umode_t
*mode_p
,
209 struct posix_acl
**acl
)
211 umode_t mode
= inode
->i_mode
;
214 if (is_inode_flag_set(inode
, FI_ACL_MODE
))
215 mode
= F2FS_I(inode
)->i_acl_mode
;
217 error
= posix_acl_equiv_mode(*acl
, &mode
);
222 if (!vfsgid_in_group_p(i_gid_into_vfsgid(mnt_userns
, inode
)) &&
223 !capable_wrt_inode_uidgid(mnt_userns
, inode
, CAP_FSETID
))
229 static int __f2fs_set_acl(struct user_namespace
*mnt_userns
,
230 struct inode
*inode
, int type
,
231 struct posix_acl
*acl
, struct page
*ipage
)
237 umode_t mode
= inode
->i_mode
;
240 case ACL_TYPE_ACCESS
:
241 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_ACCESS
;
243 error
= f2fs_acl_update_mode(mnt_userns
, inode
,
247 set_acl_inode(inode
, mode
);
251 case ACL_TYPE_DEFAULT
:
252 name_index
= F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT
;
253 if (!S_ISDIR(inode
->i_mode
))
254 return acl
? -EACCES
: 0;
262 value
= f2fs_acl_to_disk(F2FS_I_SB(inode
), acl
, &size
);
264 clear_inode_flag(inode
, FI_ACL_MODE
);
265 return PTR_ERR(value
);
269 error
= f2fs_setxattr(inode
, name_index
, "", value
, size
, ipage
, 0);
273 set_cached_acl(inode
, type
, acl
);
275 clear_inode_flag(inode
, FI_ACL_MODE
);
279 int f2fs_set_acl(struct mnt_idmap
*idmap
, struct dentry
*dentry
,
280 struct posix_acl
*acl
, int type
)
282 struct user_namespace
*mnt_userns
= mnt_idmap_owner(idmap
);
283 struct inode
*inode
= d_inode(dentry
);
285 if (unlikely(f2fs_cp_error(F2FS_I_SB(inode
))))
288 return __f2fs_set_acl(mnt_userns
, inode
, type
, acl
, NULL
);
292 * Most part of f2fs_acl_clone, f2fs_acl_create_masq, f2fs_acl_create
293 * are copied from posix_acl.c
295 static struct posix_acl
*f2fs_acl_clone(const struct posix_acl
*acl
,
298 struct posix_acl
*clone
= NULL
;
301 int size
= sizeof(struct posix_acl
) + acl
->a_count
*
302 sizeof(struct posix_acl_entry
);
303 clone
= kmemdup(acl
, size
, flags
);
305 refcount_set(&clone
->a_refcount
, 1);
310 static int f2fs_acl_create_masq(struct posix_acl
*acl
, umode_t
*mode_p
)
312 struct posix_acl_entry
*pa
, *pe
;
313 struct posix_acl_entry
*group_obj
= NULL
, *mask_obj
= NULL
;
314 umode_t mode
= *mode_p
;
317 /* assert(atomic_read(acl->a_refcount) == 1); */
319 FOREACH_ACL_ENTRY(pa
, acl
, pe
) {
322 pa
->e_perm
&= (mode
>> 6) | ~S_IRWXO
;
323 mode
&= (pa
->e_perm
<< 6) | ~S_IRWXU
;
336 pa
->e_perm
&= mode
| ~S_IRWXO
;
337 mode
&= pa
->e_perm
| ~S_IRWXO
;
351 mask_obj
->e_perm
&= (mode
>> 3) | ~S_IRWXO
;
352 mode
&= (mask_obj
->e_perm
<< 3) | ~S_IRWXG
;
356 group_obj
->e_perm
&= (mode
>> 3) | ~S_IRWXO
;
357 mode
&= (group_obj
->e_perm
<< 3) | ~S_IRWXG
;
360 *mode_p
= (*mode_p
& ~S_IRWXUGO
) | mode
;
364 static int f2fs_acl_create(struct inode
*dir
, umode_t
*mode
,
365 struct posix_acl
**default_acl
, struct posix_acl
**acl
,
369 struct posix_acl
*clone
;
375 if (S_ISLNK(*mode
) || !IS_POSIXACL(dir
))
378 p
= __f2fs_get_acl(dir
, ACL_TYPE_DEFAULT
, dpage
);
379 if (!p
|| p
== ERR_PTR(-EOPNOTSUPP
)) {
380 *mode
&= ~current_umask();
386 clone
= f2fs_acl_clone(p
, GFP_NOFS
);
392 ret
= f2fs_acl_create_masq(clone
, mode
);
397 posix_acl_release(clone
);
402 posix_acl_release(p
);
409 posix_acl_release(clone
);
411 posix_acl_release(p
);
415 int f2fs_init_acl(struct inode
*inode
, struct inode
*dir
, struct page
*ipage
,
418 struct posix_acl
*default_acl
= NULL
, *acl
= NULL
;
421 error
= f2fs_acl_create(dir
, &inode
->i_mode
, &default_acl
, &acl
, dpage
);
425 f2fs_mark_inode_dirty_sync(inode
, true);
428 error
= __f2fs_set_acl(NULL
, inode
, ACL_TYPE_DEFAULT
, default_acl
,
430 posix_acl_release(default_acl
);
432 inode
->i_default_acl
= NULL
;
436 error
= __f2fs_set_acl(NULL
, inode
, ACL_TYPE_ACCESS
, acl
,
438 posix_acl_release(acl
);