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