xref: /openbmc/linux/fs/afs/xattr.c (revision ec8f24b7faaf3d4799a7c3f4c1b87f6b02778ad1)
1 /* Extended attribute handling for AFS.  We use xattrs to get and set metadata
2  * instead of providing pioctl().
3  *
4  * Copyright (C) 2017 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public Licence
9  * as published by the Free Software Foundation; either version
10  * 2 of the Licence, or (at your option) any later version.
11  */
12 
13 #include <linux/slab.h>
14 #include <linux/fs.h>
15 #include <linux/xattr.h>
16 #include "internal.h"
17 
18 static const char afs_xattr_list[] =
19 	"afs.acl\0"
20 	"afs.cell\0"
21 	"afs.fid\0"
22 	"afs.volume\0"
23 	"afs.yfs.acl\0"
24 	"afs.yfs.acl_inherited\0"
25 	"afs.yfs.acl_num_cleaned\0"
26 	"afs.yfs.vol_acl";
27 
28 /*
29  * Retrieve a list of the supported xattrs.
30  */
31 ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
32 {
33 	if (size == 0)
34 		return sizeof(afs_xattr_list);
35 	if (size < sizeof(afs_xattr_list))
36 		return -ERANGE;
37 	memcpy(buffer, afs_xattr_list, sizeof(afs_xattr_list));
38 	return sizeof(afs_xattr_list);
39 }
40 
41 /*
42  * Get a file's ACL.
43  */
44 static int afs_xattr_get_acl(const struct xattr_handler *handler,
45 			     struct dentry *dentry,
46 			     struct inode *inode, const char *name,
47 			     void *buffer, size_t size)
48 {
49 	struct afs_fs_cursor fc;
50 	struct afs_status_cb *scb;
51 	struct afs_vnode *vnode = AFS_FS_I(inode);
52 	struct afs_acl *acl = NULL;
53 	struct key *key;
54 	int ret = -ENOMEM;
55 
56 	scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
57 	if (!scb)
58 		goto error;
59 
60 	key = afs_request_key(vnode->volume->cell);
61 	if (IS_ERR(key)) {
62 		ret = PTR_ERR(key);
63 		goto error_scb;
64 	}
65 
66 	ret = -ERESTARTSYS;
67 	if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
68 		afs_dataversion_t data_version = vnode->status.data_version;
69 
70 		while (afs_select_fileserver(&fc)) {
71 			fc.cb_break = afs_calc_vnode_cb_break(vnode);
72 			acl = afs_fs_fetch_acl(&fc, scb);
73 		}
74 
75 		afs_check_for_remote_deletion(&fc, fc.vnode);
76 		afs_vnode_commit_status(&fc, vnode, fc.cb_break,
77 					&data_version, scb);
78 		ret = afs_end_vnode_operation(&fc);
79 	}
80 
81 	if (ret == 0) {
82 		ret = acl->size;
83 		if (size > 0) {
84 			if (acl->size <= size)
85 				memcpy(buffer, acl->data, acl->size);
86 			else
87 				ret = -ERANGE;
88 		}
89 		kfree(acl);
90 	}
91 
92 	key_put(key);
93 error_scb:
94 	kfree(scb);
95 error:
96 	return ret;
97 }
98 
99 /*
100  * Set a file's AFS3 ACL.
101  */
102 static int afs_xattr_set_acl(const struct xattr_handler *handler,
103                              struct dentry *dentry,
104                              struct inode *inode, const char *name,
105                              const void *buffer, size_t size, int flags)
106 {
107 	struct afs_fs_cursor fc;
108 	struct afs_status_cb *scb;
109 	struct afs_vnode *vnode = AFS_FS_I(inode);
110 	struct afs_acl *acl = NULL;
111 	struct key *key;
112 	int ret = -ENOMEM;
113 
114 	if (flags == XATTR_CREATE)
115 		return -EINVAL;
116 
117 	scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
118 	if (!scb)
119 		goto error;
120 
121 	acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
122 	if (!acl)
123 		goto error_scb;
124 
125 	key = afs_request_key(vnode->volume->cell);
126 	if (IS_ERR(key)) {
127 		ret = PTR_ERR(key);
128 		goto error_acl;
129 	}
130 
131 	acl->size = size;
132 	memcpy(acl->data, buffer, size);
133 
134 	ret = -ERESTARTSYS;
135 	if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
136 		afs_dataversion_t data_version = vnode->status.data_version;
137 
138 		while (afs_select_fileserver(&fc)) {
139 			fc.cb_break = afs_calc_vnode_cb_break(vnode);
140 			afs_fs_store_acl(&fc, acl, scb);
141 		}
142 
143 		afs_check_for_remote_deletion(&fc, fc.vnode);
144 		afs_vnode_commit_status(&fc, vnode, fc.cb_break,
145 					&data_version, scb);
146 		ret = afs_end_vnode_operation(&fc);
147 	}
148 
149 	key_put(key);
150 error_acl:
151 	kfree(acl);
152 error_scb:
153 	kfree(scb);
154 error:
155 	return ret;
156 }
157 
158 static const struct xattr_handler afs_xattr_afs_acl_handler = {
159 	.name   = "afs.acl",
160 	.get    = afs_xattr_get_acl,
161 	.set    = afs_xattr_set_acl,
162 };
163 
164 /*
165  * Get a file's YFS ACL.
166  */
167 static int afs_xattr_get_yfs(const struct xattr_handler *handler,
168 			     struct dentry *dentry,
169 			     struct inode *inode, const char *name,
170 			     void *buffer, size_t size)
171 {
172 	struct afs_fs_cursor fc;
173 	struct afs_status_cb *scb;
174 	struct afs_vnode *vnode = AFS_FS_I(inode);
175 	struct yfs_acl *yacl = NULL;
176 	struct key *key;
177 	char buf[16], *data;
178 	int which = 0, dsize, ret = -ENOMEM;
179 
180 	if (strcmp(name, "acl") == 0)
181 		which = 0;
182 	else if (strcmp(name, "acl_inherited") == 0)
183 		which = 1;
184 	else if (strcmp(name, "acl_num_cleaned") == 0)
185 		which = 2;
186 	else if (strcmp(name, "vol_acl") == 0)
187 		which = 3;
188 	else
189 		return -EOPNOTSUPP;
190 
191 	yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL);
192 	if (!yacl)
193 		goto error;
194 
195 	if (which == 0)
196 		yacl->flags |= YFS_ACL_WANT_ACL;
197 	else if (which == 3)
198 		yacl->flags |= YFS_ACL_WANT_VOL_ACL;
199 
200 	scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
201 	if (!scb)
202 		goto error_yacl;
203 
204 	key = afs_request_key(vnode->volume->cell);
205 	if (IS_ERR(key)) {
206 		ret = PTR_ERR(key);
207 		goto error_scb;
208 	}
209 
210 	ret = -ERESTARTSYS;
211 	if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
212 		afs_dataversion_t data_version = vnode->status.data_version;
213 
214 		while (afs_select_fileserver(&fc)) {
215 			fc.cb_break = afs_calc_vnode_cb_break(vnode);
216 			yfs_fs_fetch_opaque_acl(&fc, yacl, scb);
217 		}
218 
219 		afs_check_for_remote_deletion(&fc, fc.vnode);
220 		afs_vnode_commit_status(&fc, vnode, fc.cb_break,
221 					&data_version, scb);
222 		ret = afs_end_vnode_operation(&fc);
223 	}
224 
225 	if (ret < 0)
226 		goto error_key;
227 
228 	switch (which) {
229 	case 0:
230 		data = yacl->acl->data;
231 		dsize = yacl->acl->size;
232 		break;
233 	case 1:
234 		data = buf;
235 		dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag);
236 		break;
237 	case 2:
238 		data = buf;
239 		dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned);
240 		break;
241 	case 3:
242 		data = yacl->vol_acl->data;
243 		dsize = yacl->vol_acl->size;
244 		break;
245 	default:
246 		ret = -EOPNOTSUPP;
247 		goto error_key;
248 	}
249 
250 	ret = dsize;
251 	if (size > 0) {
252 		if (dsize > size) {
253 			ret = -ERANGE;
254 			goto error_key;
255 		}
256 		memcpy(buffer, data, dsize);
257 	}
258 
259 error_key:
260 	key_put(key);
261 error_scb:
262 	kfree(scb);
263 error_yacl:
264 	yfs_free_opaque_acl(yacl);
265 error:
266 	return ret;
267 }
268 
269 /*
270  * Set a file's YFS ACL.
271  */
272 static int afs_xattr_set_yfs(const struct xattr_handler *handler,
273                              struct dentry *dentry,
274                              struct inode *inode, const char *name,
275                              const void *buffer, size_t size, int flags)
276 {
277 	struct afs_fs_cursor fc;
278 	struct afs_status_cb *scb;
279 	struct afs_vnode *vnode = AFS_FS_I(inode);
280 	struct afs_acl *acl = NULL;
281 	struct key *key;
282 	int ret = -ENOMEM;
283 
284 	if (flags == XATTR_CREATE ||
285 	    strcmp(name, "acl") != 0)
286 		return -EINVAL;
287 
288 	scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS);
289 	if (!scb)
290 		goto error;
291 
292 	acl = kmalloc(sizeof(*acl) + size, GFP_KERNEL);
293 	if (!acl)
294 		goto error_scb;
295 
296 	acl->size = size;
297 	memcpy(acl->data, buffer, size);
298 
299 	key = afs_request_key(vnode->volume->cell);
300 	if (IS_ERR(key)) {
301 		ret = PTR_ERR(key);
302 		goto error_acl;
303 	}
304 
305 	ret = -ERESTARTSYS;
306 	if (afs_begin_vnode_operation(&fc, vnode, key, true)) {
307 		afs_dataversion_t data_version = vnode->status.data_version;
308 
309 		while (afs_select_fileserver(&fc)) {
310 			fc.cb_break = afs_calc_vnode_cb_break(vnode);
311 			yfs_fs_store_opaque_acl2(&fc, acl, scb);
312 		}
313 
314 		afs_check_for_remote_deletion(&fc, fc.vnode);
315 		afs_vnode_commit_status(&fc, vnode, fc.cb_break,
316 					&data_version, scb);
317 		ret = afs_end_vnode_operation(&fc);
318 	}
319 
320 error_acl:
321 	kfree(acl);
322 	key_put(key);
323 error_scb:
324 	kfree(scb);
325 error:
326 	return ret;
327 }
328 
329 static const struct xattr_handler afs_xattr_yfs_handler = {
330 	.prefix	= "afs.yfs.",
331 	.get	= afs_xattr_get_yfs,
332 	.set	= afs_xattr_set_yfs,
333 };
334 
335 /*
336  * Get the name of the cell on which a file resides.
337  */
338 static int afs_xattr_get_cell(const struct xattr_handler *handler,
339 			      struct dentry *dentry,
340 			      struct inode *inode, const char *name,
341 			      void *buffer, size_t size)
342 {
343 	struct afs_vnode *vnode = AFS_FS_I(inode);
344 	struct afs_cell *cell = vnode->volume->cell;
345 	size_t namelen;
346 
347 	namelen = cell->name_len;
348 	if (size == 0)
349 		return namelen;
350 	if (namelen > size)
351 		return -ERANGE;
352 	memcpy(buffer, cell->name, namelen);
353 	return namelen;
354 }
355 
356 static const struct xattr_handler afs_xattr_afs_cell_handler = {
357 	.name	= "afs.cell",
358 	.get	= afs_xattr_get_cell,
359 };
360 
361 /*
362  * Get the volume ID, vnode ID and vnode uniquifier of a file as a sequence of
363  * hex numbers separated by colons.
364  */
365 static int afs_xattr_get_fid(const struct xattr_handler *handler,
366 			     struct dentry *dentry,
367 			     struct inode *inode, const char *name,
368 			     void *buffer, size_t size)
369 {
370 	struct afs_vnode *vnode = AFS_FS_I(inode);
371 	char text[16 + 1 + 24 + 1 + 8 + 1];
372 	size_t len;
373 
374 	/* The volume ID is 64-bit, the vnode ID is 96-bit and the
375 	 * uniquifier is 32-bit.
376 	 */
377 	len = sprintf(text, "%llx:", vnode->fid.vid);
378 	if (vnode->fid.vnode_hi)
379 		len += sprintf(text + len, "%x%016llx",
380 			       vnode->fid.vnode_hi, vnode->fid.vnode);
381 	else
382 		len += sprintf(text + len, "%llx", vnode->fid.vnode);
383 	len += sprintf(text + len, ":%x", vnode->fid.unique);
384 
385 	if (size == 0)
386 		return len;
387 	if (len > size)
388 		return -ERANGE;
389 	memcpy(buffer, text, len);
390 	return len;
391 }
392 
393 static const struct xattr_handler afs_xattr_afs_fid_handler = {
394 	.name	= "afs.fid",
395 	.get	= afs_xattr_get_fid,
396 };
397 
398 /*
399  * Get the name of the volume on which a file resides.
400  */
401 static int afs_xattr_get_volume(const struct xattr_handler *handler,
402 			      struct dentry *dentry,
403 			      struct inode *inode, const char *name,
404 			      void *buffer, size_t size)
405 {
406 	struct afs_vnode *vnode = AFS_FS_I(inode);
407 	const char *volname = vnode->volume->name;
408 	size_t namelen;
409 
410 	namelen = strlen(volname);
411 	if (size == 0)
412 		return namelen;
413 	if (namelen > size)
414 		return -ERANGE;
415 	memcpy(buffer, volname, namelen);
416 	return namelen;
417 }
418 
419 static const struct xattr_handler afs_xattr_afs_volume_handler = {
420 	.name	= "afs.volume",
421 	.get	= afs_xattr_get_volume,
422 };
423 
424 const struct xattr_handler *afs_xattr_handlers[] = {
425 	&afs_xattr_afs_acl_handler,
426 	&afs_xattr_afs_cell_handler,
427 	&afs_xattr_afs_fid_handler,
428 	&afs_xattr_afs_volume_handler,
429 	&afs_xattr_yfs_handler,		/* afs.yfs. prefix */
430 	NULL
431 };
432