Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/fs/9p/acl.c
15109 views
1
/*
2
* Copyright IBM Corporation, 2010
3
* Author Aneesh Kumar K.V <[email protected]>
4
*
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms of version 2.1 of the GNU Lesser General Public License
7
* as published by the Free Software Foundation.
8
*
9
* This program is distributed in the hope that it would be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
*
13
*/
14
15
#include <linux/module.h>
16
#include <linux/fs.h>
17
#include <net/9p/9p.h>
18
#include <net/9p/client.h>
19
#include <linux/slab.h>
20
#include <linux/sched.h>
21
#include <linux/posix_acl_xattr.h>
22
#include "xattr.h"
23
#include "acl.h"
24
#include "v9fs.h"
25
#include "v9fs_vfs.h"
26
27
static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
28
{
29
ssize_t size;
30
void *value = NULL;
31
struct posix_acl *acl = NULL;
32
33
size = v9fs_fid_xattr_get(fid, name, NULL, 0);
34
if (size > 0) {
35
value = kzalloc(size, GFP_NOFS);
36
if (!value)
37
return ERR_PTR(-ENOMEM);
38
size = v9fs_fid_xattr_get(fid, name, value, size);
39
if (size > 0) {
40
acl = posix_acl_from_xattr(value, size);
41
if (IS_ERR(acl))
42
goto err_out;
43
}
44
} else if (size == -ENODATA || size == 0 ||
45
size == -ENOSYS || size == -EOPNOTSUPP) {
46
acl = NULL;
47
} else
48
acl = ERR_PTR(-EIO);
49
50
err_out:
51
kfree(value);
52
return acl;
53
}
54
55
int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
56
{
57
int retval = 0;
58
struct posix_acl *pacl, *dacl;
59
struct v9fs_session_info *v9ses;
60
61
v9ses = v9fs_inode2v9ses(inode);
62
if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) ||
63
((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) {
64
set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
65
set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
66
return 0;
67
}
68
/* get the default/access acl values and cache them */
69
dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
70
pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
71
72
if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
73
set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
74
set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
75
} else
76
retval = -EIO;
77
78
if (!IS_ERR(dacl))
79
posix_acl_release(dacl);
80
81
if (!IS_ERR(pacl))
82
posix_acl_release(pacl);
83
84
return retval;
85
}
86
87
static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
88
{
89
struct posix_acl *acl;
90
/*
91
* 9p Always cache the acl value when
92
* instantiating the inode (v9fs_inode_from_fid)
93
*/
94
acl = get_cached_acl(inode, type);
95
BUG_ON(acl == ACL_NOT_CACHED);
96
return acl;
97
}
98
99
int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags)
100
{
101
struct posix_acl *acl;
102
struct v9fs_session_info *v9ses;
103
104
if (flags & IPERM_FLAG_RCU)
105
return -ECHILD;
106
107
v9ses = v9fs_inode2v9ses(inode);
108
if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) ||
109
((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) {
110
/*
111
* On access = client and acl = on mode get the acl
112
* values from the server
113
*/
114
return 0;
115
}
116
acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
117
118
if (IS_ERR(acl))
119
return PTR_ERR(acl);
120
if (acl) {
121
int error = posix_acl_permission(inode, acl, mask);
122
posix_acl_release(acl);
123
return error;
124
}
125
return -EAGAIN;
126
}
127
128
static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
129
{
130
int retval;
131
char *name;
132
size_t size;
133
void *buffer;
134
struct inode *inode = dentry->d_inode;
135
136
set_cached_acl(inode, type, acl);
137
138
if (!acl)
139
return 0;
140
141
/* Set a setxattr request to server */
142
size = posix_acl_xattr_size(acl->a_count);
143
buffer = kmalloc(size, GFP_KERNEL);
144
if (!buffer)
145
return -ENOMEM;
146
retval = posix_acl_to_xattr(acl, buffer, size);
147
if (retval < 0)
148
goto err_free_out;
149
switch (type) {
150
case ACL_TYPE_ACCESS:
151
name = POSIX_ACL_XATTR_ACCESS;
152
break;
153
case ACL_TYPE_DEFAULT:
154
name = POSIX_ACL_XATTR_DEFAULT;
155
break;
156
default:
157
BUG();
158
}
159
retval = v9fs_xattr_set(dentry, name, buffer, size, 0);
160
err_free_out:
161
kfree(buffer);
162
return retval;
163
}
164
165
int v9fs_acl_chmod(struct dentry *dentry)
166
{
167
int retval = 0;
168
struct posix_acl *acl, *clone;
169
struct inode *inode = dentry->d_inode;
170
171
if (S_ISLNK(inode->i_mode))
172
return -EOPNOTSUPP;
173
acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
174
if (acl) {
175
clone = posix_acl_clone(acl, GFP_KERNEL);
176
posix_acl_release(acl);
177
if (!clone)
178
return -ENOMEM;
179
retval = posix_acl_chmod_masq(clone, inode->i_mode);
180
if (!retval)
181
retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone);
182
posix_acl_release(clone);
183
}
184
return retval;
185
}
186
187
int v9fs_set_create_acl(struct dentry *dentry,
188
struct posix_acl *dpacl, struct posix_acl *pacl)
189
{
190
v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl);
191
v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl);
192
posix_acl_release(dpacl);
193
posix_acl_release(pacl);
194
return 0;
195
}
196
197
int v9fs_acl_mode(struct inode *dir, mode_t *modep,
198
struct posix_acl **dpacl, struct posix_acl **pacl)
199
{
200
int retval = 0;
201
mode_t mode = *modep;
202
struct posix_acl *acl = NULL;
203
204
if (!S_ISLNK(mode)) {
205
acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
206
if (IS_ERR(acl))
207
return PTR_ERR(acl);
208
if (!acl)
209
mode &= ~current_umask();
210
}
211
if (acl) {
212
struct posix_acl *clone;
213
214
if (S_ISDIR(mode))
215
*dpacl = acl;
216
clone = posix_acl_clone(acl, GFP_NOFS);
217
retval = -ENOMEM;
218
if (!clone)
219
goto cleanup;
220
221
retval = posix_acl_create_masq(clone, &mode);
222
if (retval < 0) {
223
posix_acl_release(clone);
224
goto cleanup;
225
}
226
if (retval > 0)
227
*pacl = clone;
228
}
229
*modep = mode;
230
return 0;
231
cleanup:
232
posix_acl_release(acl);
233
return retval;
234
235
}
236
237
static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
238
void *buffer, size_t size, int type)
239
{
240
char *full_name;
241
242
switch (type) {
243
case ACL_TYPE_ACCESS:
244
full_name = POSIX_ACL_XATTR_ACCESS;
245
break;
246
case ACL_TYPE_DEFAULT:
247
full_name = POSIX_ACL_XATTR_DEFAULT;
248
break;
249
default:
250
BUG();
251
}
252
return v9fs_xattr_get(dentry, full_name, buffer, size);
253
}
254
255
static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
256
void *buffer, size_t size, int type)
257
{
258
struct v9fs_session_info *v9ses;
259
struct posix_acl *acl;
260
int error;
261
262
if (strcmp(name, "") != 0)
263
return -EINVAL;
264
265
v9ses = v9fs_dentry2v9ses(dentry);
266
/*
267
* We allow set/get/list of acl when access=client is not specified
268
*/
269
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
270
return v9fs_remote_get_acl(dentry, name, buffer, size, type);
271
272
acl = v9fs_get_cached_acl(dentry->d_inode, type);
273
if (IS_ERR(acl))
274
return PTR_ERR(acl);
275
if (acl == NULL)
276
return -ENODATA;
277
error = posix_acl_to_xattr(acl, buffer, size);
278
posix_acl_release(acl);
279
280
return error;
281
}
282
283
static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
284
const void *value, size_t size,
285
int flags, int type)
286
{
287
char *full_name;
288
289
switch (type) {
290
case ACL_TYPE_ACCESS:
291
full_name = POSIX_ACL_XATTR_ACCESS;
292
break;
293
case ACL_TYPE_DEFAULT:
294
full_name = POSIX_ACL_XATTR_DEFAULT;
295
break;
296
default:
297
BUG();
298
}
299
return v9fs_xattr_set(dentry, full_name, value, size, flags);
300
}
301
302
303
static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
304
const void *value, size_t size,
305
int flags, int type)
306
{
307
int retval;
308
struct posix_acl *acl;
309
struct v9fs_session_info *v9ses;
310
struct inode *inode = dentry->d_inode;
311
312
if (strcmp(name, "") != 0)
313
return -EINVAL;
314
315
v9ses = v9fs_dentry2v9ses(dentry);
316
/*
317
* set the attribute on the remote. Without even looking at the
318
* xattr value. We leave it to the server to validate
319
*/
320
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
321
return v9fs_remote_set_acl(dentry, name,
322
value, size, flags, type);
323
324
if (S_ISLNK(inode->i_mode))
325
return -EOPNOTSUPP;
326
if (!inode_owner_or_capable(inode))
327
return -EPERM;
328
if (value) {
329
/* update the cached acl value */
330
acl = posix_acl_from_xattr(value, size);
331
if (IS_ERR(acl))
332
return PTR_ERR(acl);
333
else if (acl) {
334
retval = posix_acl_valid(acl);
335
if (retval)
336
goto err_out;
337
}
338
} else
339
acl = NULL;
340
341
switch (type) {
342
case ACL_TYPE_ACCESS:
343
name = POSIX_ACL_XATTR_ACCESS;
344
if (acl) {
345
mode_t mode = inode->i_mode;
346
retval = posix_acl_equiv_mode(acl, &mode);
347
if (retval < 0)
348
goto err_out;
349
else {
350
struct iattr iattr;
351
if (retval == 0) {
352
/*
353
* ACL can be represented
354
* by the mode bits. So don't
355
* update ACL.
356
*/
357
acl = NULL;
358
value = NULL;
359
size = 0;
360
}
361
/* Updte the mode bits */
362
iattr.ia_mode = ((mode & S_IALLUGO) |
363
(inode->i_mode & ~S_IALLUGO));
364
iattr.ia_valid = ATTR_MODE;
365
/* FIXME should we update ctime ?
366
* What is the following setxattr update the
367
* mode ?
368
*/
369
v9fs_vfs_setattr_dotl(dentry, &iattr);
370
}
371
}
372
break;
373
case ACL_TYPE_DEFAULT:
374
name = POSIX_ACL_XATTR_DEFAULT;
375
if (!S_ISDIR(inode->i_mode)) {
376
retval = acl ? -EINVAL : 0;
377
goto err_out;
378
}
379
break;
380
default:
381
BUG();
382
}
383
retval = v9fs_xattr_set(dentry, name, value, size, flags);
384
if (!retval)
385
set_cached_acl(inode, type, acl);
386
err_out:
387
posix_acl_release(acl);
388
return retval;
389
}
390
391
const struct xattr_handler v9fs_xattr_acl_access_handler = {
392
.prefix = POSIX_ACL_XATTR_ACCESS,
393
.flags = ACL_TYPE_ACCESS,
394
.get = v9fs_xattr_get_acl,
395
.set = v9fs_xattr_set_acl,
396
};
397
398
const struct xattr_handler v9fs_xattr_acl_default_handler = {
399
.prefix = POSIX_ACL_XATTR_DEFAULT,
400
.flags = ACL_TYPE_DEFAULT,
401
.get = v9fs_xattr_get_acl,
402
.set = v9fs_xattr_set_acl,
403
};
404
405