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