• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * FUSE: Filesystem in Userspace
3  * Copyright (C) 2001-2016  Miklos Szeredi <miklos@szeredi.hu>
4  *
5  * This program can be distributed under the terms of the GNU GPL.
6  * See the file COPYING.
7  */
8 
9 #include "fuse_i.h"
10 
11 #include <linux/xattr.h>
12 #include <linux/posix_acl_xattr.h>
13 
fuse_setxattr(struct inode * inode,const char * name,const void * value,size_t size,int flags,unsigned int extra_flags)14 int fuse_setxattr(struct inode *inode, const char *name, const void *value,
15 		  size_t size, int flags, unsigned int extra_flags)
16 {
17 	struct fuse_mount *fm = get_fuse_mount(inode);
18 	FUSE_ARGS(args);
19 	struct fuse_setxattr_in inarg;
20 	int err;
21 
22 	if (fm->fc->no_setxattr)
23 		return -EOPNOTSUPP;
24 
25 	memset(&inarg, 0, sizeof(inarg));
26 	inarg.size = size;
27 	inarg.flags = flags;
28 	inarg.setxattr_flags = extra_flags;
29 
30 	args.opcode = FUSE_SETXATTR;
31 	args.nodeid = get_node_id(inode);
32 	args.in_numargs = 3;
33 	args.in_args[0].size = fm->fc->setxattr_ext ?
34 		sizeof(inarg) : FUSE_COMPAT_SETXATTR_IN_SIZE;
35 	args.in_args[0].value = &inarg;
36 	args.in_args[1].size = strlen(name) + 1;
37 	args.in_args[1].value = name;
38 	args.in_args[2].size = size;
39 	args.in_args[2].value = value;
40 	err = fuse_simple_request(fm, &args);
41 	if (err == -ENOSYS) {
42 		fm->fc->no_setxattr = 1;
43 		err = -EOPNOTSUPP;
44 	}
45 	if (!err) {
46 		fuse_invalidate_attr(inode);
47 		fuse_update_ctime(inode);
48 	}
49 	return err;
50 }
51 
fuse_getxattr(struct inode * inode,const char * name,void * value,size_t size)52 ssize_t fuse_getxattr(struct inode *inode, const char *name, void *value,
53 		      size_t size)
54 {
55 	struct fuse_mount *fm = get_fuse_mount(inode);
56 	FUSE_ARGS(args);
57 	struct fuse_getxattr_in inarg;
58 	struct fuse_getxattr_out outarg;
59 	ssize_t ret;
60 
61 	if (fm->fc->no_getxattr)
62 		return -EOPNOTSUPP;
63 
64 	memset(&inarg, 0, sizeof(inarg));
65 	inarg.size = size;
66 	args.opcode = FUSE_GETXATTR;
67 	args.nodeid = get_node_id(inode);
68 	args.in_numargs = 2;
69 	args.in_args[0].size = sizeof(inarg);
70 	args.in_args[0].value = &inarg;
71 	args.in_args[1].size = strlen(name) + 1;
72 	args.in_args[1].value = name;
73 	/* This is really two different operations rolled into one */
74 	args.out_numargs = 1;
75 	if (size) {
76 		args.out_argvar = true;
77 		args.out_args[0].size = size;
78 		args.out_args[0].value = value;
79 	} else {
80 		args.out_args[0].size = sizeof(outarg);
81 		args.out_args[0].value = &outarg;
82 	}
83 	ret = fuse_simple_request(fm, &args);
84 	if (!ret && !size)
85 		ret = min_t(ssize_t, outarg.size, XATTR_SIZE_MAX);
86 	if (ret == -ENOSYS) {
87 		fm->fc->no_getxattr = 1;
88 		ret = -EOPNOTSUPP;
89 	}
90 	return ret;
91 }
92 
fuse_verify_xattr_list(char * list,size_t size)93 static int fuse_verify_xattr_list(char *list, size_t size)
94 {
95 	size_t origsize = size;
96 
97 	while (size) {
98 		size_t thislen = strnlen(list, size);
99 
100 		if (!thislen || thislen == size)
101 			return -EIO;
102 
103 		size -= thislen + 1;
104 		list += thislen + 1;
105 	}
106 
107 	return origsize;
108 }
109 
fuse_listxattr(struct dentry * entry,char * list,size_t size)110 ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
111 {
112 	struct inode *inode = d_inode(entry);
113 	struct fuse_mount *fm = get_fuse_mount(inode);
114 	FUSE_ARGS(args);
115 	struct fuse_getxattr_in inarg;
116 	struct fuse_getxattr_out outarg;
117 	ssize_t ret;
118 
119 #ifdef CONFIG_FUSE_BPF
120 	struct fuse_err_ret fer;
121 
122 	fer = fuse_bpf_backing(inode, struct fuse_getxattr_io,
123 			       fuse_listxattr_initialize,
124 			       fuse_listxattr_backing, fuse_listxattr_finalize,
125 			       entry, list, size);
126 	if (fer.ret)
127 		return PTR_ERR(fer.result);
128 #endif
129 
130 	if (fuse_is_bad(inode))
131 		return -EIO;
132 
133 	if (!fuse_allow_current_process(fm->fc))
134 		return -EACCES;
135 
136 	if (fm->fc->no_listxattr)
137 		return -EOPNOTSUPP;
138 
139 	memset(&inarg, 0, sizeof(inarg));
140 	inarg.size = size;
141 	args.opcode = FUSE_LISTXATTR;
142 	args.nodeid = get_node_id(inode);
143 	args.in_numargs = 1;
144 	args.in_args[0].size = sizeof(inarg);
145 	args.in_args[0].value = &inarg;
146 	/* This is really two different operations rolled into one */
147 	args.out_numargs = 1;
148 	if (size) {
149 		args.out_argvar = true;
150 		args.out_args[0].size = size;
151 		args.out_args[0].value = list;
152 	} else {
153 		args.out_args[0].size = sizeof(outarg);
154 		args.out_args[0].value = &outarg;
155 	}
156 	ret = fuse_simple_request(fm, &args);
157 	if (!ret && !size)
158 		ret = min_t(ssize_t, outarg.size, XATTR_LIST_MAX);
159 	if (ret > 0 && size)
160 		ret = fuse_verify_xattr_list(list, ret);
161 	if (ret == -ENOSYS) {
162 		fm->fc->no_listxattr = 1;
163 		ret = -EOPNOTSUPP;
164 	}
165 	return ret;
166 }
167 
fuse_removexattr(struct inode * inode,const char * name)168 int fuse_removexattr(struct inode *inode, const char *name)
169 {
170 	struct fuse_mount *fm = get_fuse_mount(inode);
171 	FUSE_ARGS(args);
172 	int err;
173 
174 	if (fm->fc->no_removexattr)
175 		return -EOPNOTSUPP;
176 
177 	args.opcode = FUSE_REMOVEXATTR;
178 	args.nodeid = get_node_id(inode);
179 	args.in_numargs = 1;
180 	args.in_args[0].size = strlen(name) + 1;
181 	args.in_args[0].value = name;
182 	err = fuse_simple_request(fm, &args);
183 	if (err == -ENOSYS) {
184 		fm->fc->no_removexattr = 1;
185 		err = -EOPNOTSUPP;
186 	}
187 	if (!err) {
188 		fuse_invalidate_attr(inode);
189 		fuse_update_ctime(inode);
190 	}
191 	return err;
192 }
193 
fuse_xattr_get(const struct xattr_handler * handler,struct dentry * dentry,struct inode * inode,const char * name,void * value,size_t size)194 static int fuse_xattr_get(const struct xattr_handler *handler,
195 			 struct dentry *dentry, struct inode *inode,
196 			 const char *name, void *value, size_t size)
197 {
198 #ifdef CONFIG_FUSE_BPF
199 	struct fuse_err_ret fer;
200 
201 	fer = fuse_bpf_backing(inode, struct fuse_getxattr_io,
202 			       fuse_getxattr_initialize, fuse_getxattr_backing,
203 			       fuse_getxattr_finalize,
204 			       dentry, name, value, size);
205 	if (fer.ret)
206 		return PTR_ERR(fer.result);
207 #endif
208 
209 	if (fuse_is_bad(inode))
210 		return -EIO;
211 
212 	return fuse_getxattr(inode, name, value, size);
213 }
214 
fuse_xattr_set(const struct xattr_handler * handler,struct user_namespace * mnt_userns,struct dentry * dentry,struct inode * inode,const char * name,const void * value,size_t size,int flags)215 static int fuse_xattr_set(const struct xattr_handler *handler,
216 			  struct user_namespace *mnt_userns,
217 			  struct dentry *dentry, struct inode *inode,
218 			  const char *name, const void *value, size_t size,
219 			  int flags)
220 {
221 #ifdef CONFIG_FUSE_BPF
222 	struct fuse_err_ret fer;
223 
224 	if (value)
225 		fer = fuse_bpf_backing(inode, struct fuse_setxattr_in,
226 			       fuse_setxattr_initialize, fuse_setxattr_backing,
227 			       fuse_setxattr_finalize, dentry, name, value,
228 			       size, flags);
229 	else
230 		fer = fuse_bpf_backing(inode, struct fuse_dummy_io,
231 				       fuse_removexattr_initialize,
232 				       fuse_removexattr_backing,
233 				       fuse_removexattr_finalize,
234 				       dentry, name);
235 	if (fer.ret)
236 		return PTR_ERR(fer.result);
237 #endif
238 
239 	if (fuse_is_bad(inode))
240 		return -EIO;
241 
242 	if (!value)
243 		return fuse_removexattr(inode, name);
244 
245 	return fuse_setxattr(inode, name, value, size, flags, 0);
246 }
247 
no_xattr_list(struct dentry * dentry)248 static bool no_xattr_list(struct dentry *dentry)
249 {
250 	return false;
251 }
252 
no_xattr_get(const struct xattr_handler * handler,struct dentry * dentry,struct inode * inode,const char * name,void * value,size_t size)253 static int no_xattr_get(const struct xattr_handler *handler,
254 			struct dentry *dentry, struct inode *inode,
255 			const char *name, void *value, size_t size)
256 {
257 	return -EOPNOTSUPP;
258 }
259 
no_xattr_set(const struct xattr_handler * handler,struct user_namespace * mnt_userns,struct dentry * dentry,struct inode * nodee,const char * name,const void * value,size_t size,int flags)260 static int no_xattr_set(const struct xattr_handler *handler,
261 			struct user_namespace *mnt_userns,
262 			struct dentry *dentry, struct inode *nodee,
263 			const char *name, const void *value,
264 			size_t size, int flags)
265 {
266 	return -EOPNOTSUPP;
267 }
268 
269 static const struct xattr_handler fuse_xattr_handler = {
270 	.prefix = "",
271 	.get    = fuse_xattr_get,
272 	.set    = fuse_xattr_set,
273 };
274 
275 const struct xattr_handler *fuse_xattr_handlers[] = {
276 	&fuse_xattr_handler,
277 	NULL
278 };
279 
280 const struct xattr_handler *fuse_acl_xattr_handlers[] = {
281 	&posix_acl_access_xattr_handler,
282 	&posix_acl_default_xattr_handler,
283 	&fuse_xattr_handler,
284 	NULL
285 };
286 
287 static const struct xattr_handler fuse_no_acl_access_xattr_handler = {
288 	.name  = XATTR_NAME_POSIX_ACL_ACCESS,
289 	.flags = ACL_TYPE_ACCESS,
290 	.list  = no_xattr_list,
291 	.get   = no_xattr_get,
292 	.set   = no_xattr_set,
293 };
294 
295 static const struct xattr_handler fuse_no_acl_default_xattr_handler = {
296 	.name  = XATTR_NAME_POSIX_ACL_DEFAULT,
297 	.flags = ACL_TYPE_ACCESS,
298 	.list  = no_xattr_list,
299 	.get   = no_xattr_get,
300 	.set   = no_xattr_set,
301 };
302 
303 const struct xattr_handler *fuse_no_acl_xattr_handlers[] = {
304 	&fuse_no_acl_access_xattr_handler,
305 	&fuse_no_acl_default_xattr_handler,
306 	&fuse_xattr_handler,
307 	NULL
308 };
309