1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/fs.h> |
3 | #include <linux/gfp.h> |
4 | #include <linux/nfs.h> |
5 | #include <linux/nfs3.h> |
6 | #include <linux/nfs_fs.h> |
7 | #include <linux/posix_acl_xattr.h> |
8 | #include <linux/nfsacl.h> |
9 | |
10 | #include "internal.h" |
11 | #include "nfs3_fs.h" |
12 | |
13 | #define NFSDBG_FACILITY NFSDBG_PROC |
14 | |
15 | /* |
16 | * nfs3_prepare_get_acl, nfs3_complete_get_acl, nfs3_abort_get_acl: Helpers for |
17 | * caching get_acl results in a race-free way. See fs/posix_acl.c:get_acl() |
18 | * for explanations. |
19 | */ |
20 | static void nfs3_prepare_get_acl(struct posix_acl **p) |
21 | { |
22 | struct posix_acl *sentinel = uncached_acl_sentinel(current); |
23 | |
24 | /* If the ACL isn't being read yet, set our sentinel. */ |
25 | cmpxchg(p, ACL_NOT_CACHED, sentinel); |
26 | } |
27 | |
28 | static void nfs3_complete_get_acl(struct posix_acl **p, struct posix_acl *acl) |
29 | { |
30 | struct posix_acl *sentinel = uncached_acl_sentinel(current); |
31 | |
32 | /* Only cache the ACL if our sentinel is still in place. */ |
33 | posix_acl_dup(acl); |
34 | if (cmpxchg(p, sentinel, acl) != sentinel) |
35 | posix_acl_release(acl); |
36 | } |
37 | |
38 | static void nfs3_abort_get_acl(struct posix_acl **p) |
39 | { |
40 | struct posix_acl *sentinel = uncached_acl_sentinel(current); |
41 | |
42 | /* Remove our sentinel upon failure. */ |
43 | cmpxchg(p, sentinel, ACL_NOT_CACHED); |
44 | } |
45 | |
46 | struct posix_acl *nfs3_get_acl(struct inode *inode, int type, bool rcu) |
47 | { |
48 | struct nfs_server *server = NFS_SERVER(inode); |
49 | struct page *pages[NFSACL_MAXPAGES] = { }; |
50 | struct nfs3_getaclargs args = { |
51 | .fh = NFS_FH(inode), |
52 | /* The xdr layer may allocate pages here. */ |
53 | .pages = pages, |
54 | }; |
55 | struct nfs3_getaclres res = { |
56 | NULL, |
57 | }; |
58 | struct rpc_message msg = { |
59 | .rpc_argp = &args, |
60 | .rpc_resp = &res, |
61 | }; |
62 | int status, count; |
63 | |
64 | if (rcu) |
65 | return ERR_PTR(error: -ECHILD); |
66 | |
67 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) |
68 | return ERR_PTR(error: -EOPNOTSUPP); |
69 | |
70 | status = nfs_revalidate_inode(inode, NFS_INO_INVALID_CHANGE); |
71 | if (status < 0) |
72 | return ERR_PTR(error: status); |
73 | |
74 | /* |
75 | * Only get the access acl when explicitly requested: We don't |
76 | * need it for access decisions, and only some applications use |
77 | * it. Applications which request the access acl first are not |
78 | * penalized from this optimization. |
79 | */ |
80 | if (type == ACL_TYPE_ACCESS) |
81 | args.mask |= NFS_ACLCNT|NFS_ACL; |
82 | if (S_ISDIR(inode->i_mode)) |
83 | args.mask |= NFS_DFACLCNT|NFS_DFACL; |
84 | if (args.mask == 0) |
85 | return NULL; |
86 | |
87 | dprintk("NFS call getacl\n" ); |
88 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_GETACL]; |
89 | res.fattr = nfs_alloc_fattr(); |
90 | if (res.fattr == NULL) |
91 | return ERR_PTR(error: -ENOMEM); |
92 | |
93 | if (args.mask & NFS_ACL) |
94 | nfs3_prepare_get_acl(p: &inode->i_acl); |
95 | if (args.mask & NFS_DFACL) |
96 | nfs3_prepare_get_acl(p: &inode->i_default_acl); |
97 | |
98 | status = rpc_call_sync(clnt: server->client_acl, msg: &msg, flags: 0); |
99 | dprintk("NFS reply getacl: %d\n" , status); |
100 | |
101 | /* pages may have been allocated at the xdr layer. */ |
102 | for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++) |
103 | __free_page(args.pages[count]); |
104 | |
105 | switch (status) { |
106 | case 0: |
107 | status = nfs_refresh_inode(inode, res.fattr); |
108 | break; |
109 | case -EPFNOSUPPORT: |
110 | case -EPROTONOSUPPORT: |
111 | dprintk("NFS_V3_ACL extension not supported; disabling\n" ); |
112 | server->caps &= ~NFS_CAP_ACLS; |
113 | fallthrough; |
114 | case -ENOTSUPP: |
115 | status = -EOPNOTSUPP; |
116 | goto getout; |
117 | default: |
118 | goto getout; |
119 | } |
120 | if ((args.mask & res.mask) != args.mask) { |
121 | status = -EIO; |
122 | goto getout; |
123 | } |
124 | |
125 | if (res.acl_access != NULL) { |
126 | if ((posix_acl_equiv_mode(res.acl_access, NULL) == 0) || |
127 | res.acl_access->a_count == 0) { |
128 | posix_acl_release(acl: res.acl_access); |
129 | res.acl_access = NULL; |
130 | } |
131 | } |
132 | |
133 | if (res.mask & NFS_ACL) |
134 | nfs3_complete_get_acl(p: &inode->i_acl, acl: res.acl_access); |
135 | else |
136 | forget_cached_acl(inode, ACL_TYPE_ACCESS); |
137 | |
138 | if (res.mask & NFS_DFACL) |
139 | nfs3_complete_get_acl(p: &inode->i_default_acl, acl: res.acl_default); |
140 | else |
141 | forget_cached_acl(inode, ACL_TYPE_DEFAULT); |
142 | |
143 | nfs_free_fattr(fattr: res.fattr); |
144 | if (type == ACL_TYPE_ACCESS) { |
145 | posix_acl_release(acl: res.acl_default); |
146 | return res.acl_access; |
147 | } else { |
148 | posix_acl_release(acl: res.acl_access); |
149 | return res.acl_default; |
150 | } |
151 | |
152 | getout: |
153 | nfs3_abort_get_acl(p: &inode->i_acl); |
154 | nfs3_abort_get_acl(p: &inode->i_default_acl); |
155 | posix_acl_release(acl: res.acl_access); |
156 | posix_acl_release(acl: res.acl_default); |
157 | nfs_free_fattr(fattr: res.fattr); |
158 | return ERR_PTR(error: status); |
159 | } |
160 | |
161 | static int __nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, |
162 | struct posix_acl *dfacl) |
163 | { |
164 | struct nfs_server *server = NFS_SERVER(inode); |
165 | struct nfs_fattr *fattr; |
166 | struct page *pages[NFSACL_MAXPAGES]; |
167 | struct nfs3_setaclargs args = { |
168 | .inode = inode, |
169 | .mask = NFS_ACL, |
170 | .acl_access = acl, |
171 | .pages = pages, |
172 | }; |
173 | struct rpc_message msg = { |
174 | .rpc_argp = &args, |
175 | .rpc_resp = &fattr, |
176 | }; |
177 | int status = 0; |
178 | |
179 | if (acl == NULL && (!S_ISDIR(inode->i_mode) || dfacl == NULL)) |
180 | goto out; |
181 | |
182 | status = -EOPNOTSUPP; |
183 | if (!nfs_server_capable(inode, NFS_CAP_ACLS)) |
184 | goto out; |
185 | |
186 | /* We are doing this here because XDR marshalling does not |
187 | * return any results, it BUGs. */ |
188 | status = -ENOSPC; |
189 | if (acl != NULL && acl->a_count > NFS_ACL_MAX_ENTRIES) |
190 | goto out; |
191 | if (dfacl != NULL && dfacl->a_count > NFS_ACL_MAX_ENTRIES) |
192 | goto out; |
193 | if (S_ISDIR(inode->i_mode)) { |
194 | args.mask |= NFS_DFACL; |
195 | args.acl_default = dfacl; |
196 | args.len = nfsacl_size(acl_access: acl, acl_default: dfacl); |
197 | } else |
198 | args.len = nfsacl_size(acl_access: acl, NULL); |
199 | |
200 | if (args.len > NFS_ACL_INLINE_BUFSIZE) { |
201 | unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT); |
202 | |
203 | status = -ENOMEM; |
204 | do { |
205 | args.pages[args.npages] = alloc_page(GFP_KERNEL); |
206 | if (args.pages[args.npages] == NULL) |
207 | goto out_freepages; |
208 | args.npages++; |
209 | } while (args.npages < npages); |
210 | } |
211 | |
212 | dprintk("NFS call setacl\n" ); |
213 | status = -ENOMEM; |
214 | fattr = nfs_alloc_fattr(); |
215 | if (fattr == NULL) |
216 | goto out_freepages; |
217 | |
218 | msg.rpc_proc = &server->client_acl->cl_procinfo[ACLPROC3_SETACL]; |
219 | msg.rpc_resp = fattr; |
220 | status = rpc_call_sync(clnt: server->client_acl, msg: &msg, flags: 0); |
221 | nfs_access_zap_cache(inode); |
222 | nfs_zap_acl_cache(inode); |
223 | dprintk("NFS reply setacl: %d\n" , status); |
224 | |
225 | switch (status) { |
226 | case 0: |
227 | status = nfs_refresh_inode(inode, fattr); |
228 | break; |
229 | case -EPFNOSUPPORT: |
230 | case -EPROTONOSUPPORT: |
231 | dprintk("NFS_V3_ACL SETACL RPC not supported" |
232 | "(will not retry)\n" ); |
233 | server->caps &= ~NFS_CAP_ACLS; |
234 | fallthrough; |
235 | case -ENOTSUPP: |
236 | status = -EOPNOTSUPP; |
237 | } |
238 | nfs_free_fattr(fattr); |
239 | out_freepages: |
240 | while (args.npages != 0) { |
241 | args.npages--; |
242 | __free_page(args.pages[args.npages]); |
243 | } |
244 | out: |
245 | return status; |
246 | } |
247 | |
248 | int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl, |
249 | struct posix_acl *dfacl) |
250 | { |
251 | int ret; |
252 | ret = __nfs3_proc_setacls(inode, acl, dfacl); |
253 | return (ret == -EOPNOTSUPP) ? 0 : ret; |
254 | |
255 | } |
256 | |
257 | int nfs3_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, |
258 | struct posix_acl *acl, int type) |
259 | { |
260 | struct posix_acl *orig = acl, *dfacl = NULL, *alloc; |
261 | struct inode *inode = d_inode(dentry); |
262 | int status; |
263 | |
264 | if (S_ISDIR(inode->i_mode)) { |
265 | switch(type) { |
266 | case ACL_TYPE_ACCESS: |
267 | alloc = get_inode_acl(inode, ACL_TYPE_DEFAULT); |
268 | if (IS_ERR(ptr: alloc)) |
269 | goto fail; |
270 | dfacl = alloc; |
271 | break; |
272 | |
273 | case ACL_TYPE_DEFAULT: |
274 | alloc = get_inode_acl(inode, ACL_TYPE_ACCESS); |
275 | if (IS_ERR(ptr: alloc)) |
276 | goto fail; |
277 | dfacl = acl; |
278 | acl = alloc; |
279 | break; |
280 | } |
281 | } |
282 | |
283 | if (acl == NULL) { |
284 | alloc = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); |
285 | if (IS_ERR(ptr: alloc)) |
286 | goto fail; |
287 | acl = alloc; |
288 | } |
289 | status = __nfs3_proc_setacls(inode, acl, dfacl); |
290 | out: |
291 | if (acl != orig) |
292 | posix_acl_release(acl); |
293 | if (dfacl != orig) |
294 | posix_acl_release(acl: dfacl); |
295 | return status; |
296 | |
297 | fail: |
298 | status = PTR_ERR(ptr: alloc); |
299 | goto out; |
300 | } |
301 | |
302 | static int |
303 | nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data, |
304 | size_t size, ssize_t *result) |
305 | { |
306 | struct posix_acl *acl; |
307 | char *p = data + *result; |
308 | |
309 | acl = get_inode_acl(inode, type); |
310 | if (IS_ERR_OR_NULL(ptr: acl)) |
311 | return 0; |
312 | |
313 | posix_acl_release(acl); |
314 | |
315 | *result += strlen(name); |
316 | *result += 1; |
317 | if (!size) |
318 | return 0; |
319 | if (*result > size) |
320 | return -ERANGE; |
321 | |
322 | strcpy(p, q: name); |
323 | return 0; |
324 | } |
325 | |
326 | ssize_t |
327 | nfs3_listxattr(struct dentry *dentry, char *data, size_t size) |
328 | { |
329 | struct inode *inode = d_inode(dentry); |
330 | ssize_t result = 0; |
331 | int error; |
332 | |
333 | error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS, |
334 | XATTR_NAME_POSIX_ACL_ACCESS, data, size, result: &result); |
335 | if (error) |
336 | return error; |
337 | |
338 | error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT, |
339 | XATTR_NAME_POSIX_ACL_DEFAULT, data, size, result: &result); |
340 | if (error) |
341 | return error; |
342 | return result; |
343 | } |
344 | |