xref: /linux/fs/file_attr.c (revision 69050f8d6d075dc01af7a5f2f550a8067510366f)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/fs.h>
3 #include <linux/security.h>
4 #include <linux/fscrypt.h>
5 #include <linux/fsnotify.h>
6 #include <linux/fileattr.h>
7 #include <linux/export.h>
8 #include <linux/syscalls.h>
9 #include <linux/namei.h>
10 
11 #include "internal.h"
12 
13 /**
14  * fileattr_fill_xflags - initialize fileattr with xflags
15  * @fa:		fileattr pointer
16  * @xflags:	FS_XFLAG_* flags
17  *
18  * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags).  All
19  * other fields are zeroed.
20  */
21 void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags)
22 {
23 	memset(fa, 0, sizeof(*fa));
24 	fa->fsx_valid = true;
25 	fa->fsx_xflags = xflags;
26 	if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)
27 		fa->flags |= FS_IMMUTABLE_FL;
28 	if (fa->fsx_xflags & FS_XFLAG_APPEND)
29 		fa->flags |= FS_APPEND_FL;
30 	if (fa->fsx_xflags & FS_XFLAG_SYNC)
31 		fa->flags |= FS_SYNC_FL;
32 	if (fa->fsx_xflags & FS_XFLAG_NOATIME)
33 		fa->flags |= FS_NOATIME_FL;
34 	if (fa->fsx_xflags & FS_XFLAG_NODUMP)
35 		fa->flags |= FS_NODUMP_FL;
36 	if (fa->fsx_xflags & FS_XFLAG_DAX)
37 		fa->flags |= FS_DAX_FL;
38 	if (fa->fsx_xflags & FS_XFLAG_PROJINHERIT)
39 		fa->flags |= FS_PROJINHERIT_FL;
40 	if (fa->fsx_xflags & FS_XFLAG_VERITY)
41 		fa->flags |= FS_VERITY_FL;
42 }
43 EXPORT_SYMBOL(fileattr_fill_xflags);
44 
45 /**
46  * fileattr_fill_flags - initialize fileattr with flags
47  * @fa:		fileattr pointer
48  * @flags:	FS_*_FL flags
49  *
50  * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags).
51  * All other fields are zeroed.
52  */
53 void fileattr_fill_flags(struct file_kattr *fa, u32 flags)
54 {
55 	memset(fa, 0, sizeof(*fa));
56 	fa->flags_valid = true;
57 	fa->flags = flags;
58 	if (fa->flags & FS_SYNC_FL)
59 		fa->fsx_xflags |= FS_XFLAG_SYNC;
60 	if (fa->flags & FS_IMMUTABLE_FL)
61 		fa->fsx_xflags |= FS_XFLAG_IMMUTABLE;
62 	if (fa->flags & FS_APPEND_FL)
63 		fa->fsx_xflags |= FS_XFLAG_APPEND;
64 	if (fa->flags & FS_NODUMP_FL)
65 		fa->fsx_xflags |= FS_XFLAG_NODUMP;
66 	if (fa->flags & FS_NOATIME_FL)
67 		fa->fsx_xflags |= FS_XFLAG_NOATIME;
68 	if (fa->flags & FS_DAX_FL)
69 		fa->fsx_xflags |= FS_XFLAG_DAX;
70 	if (fa->flags & FS_PROJINHERIT_FL)
71 		fa->fsx_xflags |= FS_XFLAG_PROJINHERIT;
72 	if (fa->flags & FS_VERITY_FL)
73 		fa->fsx_xflags |= FS_XFLAG_VERITY;
74 }
75 EXPORT_SYMBOL(fileattr_fill_flags);
76 
77 /**
78  * vfs_fileattr_get - retrieve miscellaneous file attributes
79  * @dentry:	the object to retrieve from
80  * @fa:		fileattr pointer
81  *
82  * Call i_op->fileattr_get() callback, if exists.
83  *
84  * Return: 0 on success, or a negative error on failure.
85  */
86 int vfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
87 {
88 	struct inode *inode = d_inode(dentry);
89 	int error;
90 
91 	if (!inode->i_op->fileattr_get)
92 		return -ENOIOCTLCMD;
93 
94 	error = security_inode_file_getattr(dentry, fa);
95 	if (error)
96 		return error;
97 
98 	return inode->i_op->fileattr_get(dentry, fa);
99 }
100 EXPORT_SYMBOL(vfs_fileattr_get);
101 
102 static void fileattr_to_file_attr(const struct file_kattr *fa,
103 				  struct file_attr *fattr)
104 {
105 	__u32 mask = FS_XFLAGS_MASK;
106 
107 	memset(fattr, 0, sizeof(struct file_attr));
108 	fattr->fa_xflags = fa->fsx_xflags & mask;
109 	fattr->fa_extsize = fa->fsx_extsize;
110 	fattr->fa_nextents = fa->fsx_nextents;
111 	fattr->fa_projid = fa->fsx_projid;
112 	fattr->fa_cowextsize = fa->fsx_cowextsize;
113 }
114 
115 /**
116  * copy_fsxattr_to_user - copy fsxattr to userspace.
117  * @fa:		fileattr pointer
118  * @ufa:	fsxattr user pointer
119  *
120  * Return: 0 on success, or -EFAULT on failure.
121  */
122 int copy_fsxattr_to_user(const struct file_kattr *fa, struct fsxattr __user *ufa)
123 {
124 	struct fsxattr xfa;
125 	__u32 mask = FS_XFLAGS_MASK;
126 
127 	memset(&xfa, 0, sizeof(xfa));
128 	xfa.fsx_xflags = fa->fsx_xflags & mask;
129 	xfa.fsx_extsize = fa->fsx_extsize;
130 	xfa.fsx_nextents = fa->fsx_nextents;
131 	xfa.fsx_projid = fa->fsx_projid;
132 	xfa.fsx_cowextsize = fa->fsx_cowextsize;
133 
134 	if (copy_to_user(ufa, &xfa, sizeof(xfa)))
135 		return -EFAULT;
136 
137 	return 0;
138 }
139 EXPORT_SYMBOL(copy_fsxattr_to_user);
140 
141 static int file_attr_to_fileattr(const struct file_attr *fattr,
142 				 struct file_kattr *fa)
143 {
144 	__u64 mask = FS_XFLAGS_MASK;
145 
146 	if (fattr->fa_xflags & ~mask)
147 		return -EINVAL;
148 
149 	fileattr_fill_xflags(fa, fattr->fa_xflags & ~FS_XFLAG_RDONLY_MASK);
150 	fa->fsx_extsize = fattr->fa_extsize;
151 	fa->fsx_projid = fattr->fa_projid;
152 	fa->fsx_cowextsize = fattr->fa_cowextsize;
153 
154 	return 0;
155 }
156 
157 static int copy_fsxattr_from_user(struct file_kattr *fa,
158 				  struct fsxattr __user *ufa)
159 {
160 	struct fsxattr xfa;
161 	__u32 mask = FS_XFLAGS_MASK;
162 
163 	if (copy_from_user(&xfa, ufa, sizeof(xfa)))
164 		return -EFAULT;
165 
166 	if (xfa.fsx_xflags & ~mask)
167 		return -EOPNOTSUPP;
168 
169 	fileattr_fill_xflags(fa, xfa.fsx_xflags & ~FS_XFLAG_RDONLY_MASK);
170 	fa->fsx_extsize = xfa.fsx_extsize;
171 	fa->fsx_nextents = xfa.fsx_nextents;
172 	fa->fsx_projid = xfa.fsx_projid;
173 	fa->fsx_cowextsize = xfa.fsx_cowextsize;
174 
175 	return 0;
176 }
177 
178 /*
179  * Generic function to check FS_IOC_FSSETXATTR/FS_IOC_SETFLAGS values and reject
180  * any invalid configurations.
181  *
182  * Note: must be called with inode lock held.
183  */
184 static int fileattr_set_prepare(struct inode *inode,
185 			      const struct file_kattr *old_ma,
186 			      struct file_kattr *fa)
187 {
188 	int err;
189 
190 	/*
191 	 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
192 	 * the relevant capability.
193 	 */
194 	if ((fa->flags ^ old_ma->flags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) &&
195 	    !capable(CAP_LINUX_IMMUTABLE))
196 		return -EPERM;
197 
198 	err = fscrypt_prepare_setflags(inode, old_ma->flags, fa->flags);
199 	if (err)
200 		return err;
201 
202 	/*
203 	 * Project Quota ID state is only allowed to change from within the init
204 	 * namespace. Enforce that restriction only if we are trying to change
205 	 * the quota ID state. Everything else is allowed in user namespaces.
206 	 */
207 	if (current_user_ns() != &init_user_ns) {
208 		if (old_ma->fsx_projid != fa->fsx_projid)
209 			return -EINVAL;
210 		if ((old_ma->fsx_xflags ^ fa->fsx_xflags) &
211 				FS_XFLAG_PROJINHERIT)
212 			return -EINVAL;
213 	} else {
214 		/*
215 		 * Caller is allowed to change the project ID. If it is being
216 		 * changed, make sure that the new value is valid.
217 		 */
218 		if (old_ma->fsx_projid != fa->fsx_projid &&
219 		    !projid_valid(make_kprojid(&init_user_ns, fa->fsx_projid)))
220 			return -EINVAL;
221 	}
222 
223 	/* Check extent size hints. */
224 	if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(inode->i_mode))
225 		return -EINVAL;
226 
227 	if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) &&
228 			!S_ISDIR(inode->i_mode))
229 		return -EINVAL;
230 
231 	if ((fa->fsx_xflags & FS_XFLAG_COWEXTSIZE) &&
232 	    !S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
233 		return -EINVAL;
234 
235 	/*
236 	 * It is only valid to set the DAX flag on regular files and
237 	 * directories on filesystems.
238 	 */
239 	if ((fa->fsx_xflags & FS_XFLAG_DAX) &&
240 	    !(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
241 		return -EINVAL;
242 
243 	/* Extent size hints of zero turn off the flags. */
244 	if (fa->fsx_extsize == 0)
245 		fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT);
246 	if (fa->fsx_cowextsize == 0)
247 		fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE;
248 
249 	return 0;
250 }
251 
252 /**
253  * vfs_fileattr_set - change miscellaneous file attributes
254  * @idmap:	idmap of the mount
255  * @dentry:	the object to change
256  * @fa:		fileattr pointer
257  *
258  * After verifying permissions, call i_op->fileattr_set() callback, if
259  * exists.
260  *
261  * Verifying attributes involves retrieving current attributes with
262  * i_op->fileattr_get(), this also allows initializing attributes that have
263  * not been set by the caller to current values.  Inode lock is held
264  * thoughout to prevent racing with another instance.
265  *
266  * Return: 0 on success, or a negative error on failure.
267  */
268 int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
269 		     struct file_kattr *fa)
270 {
271 	struct inode *inode = d_inode(dentry);
272 	struct file_kattr old_ma = {};
273 	int err;
274 
275 	if (!inode->i_op->fileattr_set)
276 		return -ENOIOCTLCMD;
277 
278 	if (!inode_owner_or_capable(idmap, inode))
279 		return -EPERM;
280 
281 	inode_lock(inode);
282 	err = vfs_fileattr_get(dentry, &old_ma);
283 	if (!err) {
284 		/* initialize missing bits from old_ma */
285 		if (fa->flags_valid) {
286 			fa->fsx_xflags |= old_ma.fsx_xflags & ~FS_XFLAG_COMMON;
287 			fa->fsx_extsize = old_ma.fsx_extsize;
288 			fa->fsx_nextents = old_ma.fsx_nextents;
289 			fa->fsx_projid = old_ma.fsx_projid;
290 			fa->fsx_cowextsize = old_ma.fsx_cowextsize;
291 		} else {
292 			fa->flags |= old_ma.flags & ~FS_COMMON_FL;
293 		}
294 
295 		err = fileattr_set_prepare(inode, &old_ma, fa);
296 		if (err)
297 			goto out;
298 		err = security_inode_file_setattr(dentry, fa);
299 		if (err)
300 			goto out;
301 		err = inode->i_op->fileattr_set(idmap, dentry, fa);
302 		if (err)
303 			goto out;
304 		fsnotify_xattr(dentry);
305 	}
306 
307 out:
308 	inode_unlock(inode);
309 	return err;
310 }
311 EXPORT_SYMBOL(vfs_fileattr_set);
312 
313 int ioctl_getflags(struct file *file, unsigned int __user *argp)
314 {
315 	struct file_kattr fa = { .flags_valid = true }; /* hint only */
316 	int err;
317 
318 	err = vfs_fileattr_get(file->f_path.dentry, &fa);
319 	if (!err)
320 		err = put_user(fa.flags, argp);
321 	return err;
322 }
323 
324 int ioctl_setflags(struct file *file, unsigned int __user *argp)
325 {
326 	struct mnt_idmap *idmap = file_mnt_idmap(file);
327 	struct dentry *dentry = file->f_path.dentry;
328 	struct file_kattr fa;
329 	unsigned int flags;
330 	int err;
331 
332 	err = get_user(flags, argp);
333 	if (!err) {
334 		err = mnt_want_write_file(file);
335 		if (!err) {
336 			fileattr_fill_flags(&fa, flags);
337 			err = vfs_fileattr_set(idmap, dentry, &fa);
338 			mnt_drop_write_file(file);
339 		}
340 	}
341 	return err;
342 }
343 
344 int ioctl_fsgetxattr(struct file *file, void __user *argp)
345 {
346 	struct file_kattr fa = { .fsx_valid = true }; /* hint only */
347 	int err;
348 
349 	err = vfs_fileattr_get(file->f_path.dentry, &fa);
350 	if (!err)
351 		err = copy_fsxattr_to_user(&fa, argp);
352 
353 	return err;
354 }
355 
356 int ioctl_fssetxattr(struct file *file, void __user *argp)
357 {
358 	struct mnt_idmap *idmap = file_mnt_idmap(file);
359 	struct dentry *dentry = file->f_path.dentry;
360 	struct file_kattr fa;
361 	int err;
362 
363 	err = copy_fsxattr_from_user(&fa, argp);
364 	if (!err) {
365 		err = mnt_want_write_file(file);
366 		if (!err) {
367 			err = vfs_fileattr_set(idmap, dentry, &fa);
368 			mnt_drop_write_file(file);
369 		}
370 	}
371 	return err;
372 }
373 
374 SYSCALL_DEFINE5(file_getattr, int, dfd, const char __user *, filename,
375 		struct file_attr __user *, ufattr, size_t, usize,
376 		unsigned int, at_flags)
377 {
378 	struct path filepath __free(path_put) = {};
379 	unsigned int lookup_flags = 0;
380 	struct file_attr fattr;
381 	struct file_kattr fa;
382 	int error;
383 
384 	BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
385 	BUILD_BUG_ON(sizeof(struct file_attr) != FILE_ATTR_SIZE_LATEST);
386 
387 	if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
388 		return -EINVAL;
389 
390 	if (!(at_flags & AT_SYMLINK_NOFOLLOW))
391 		lookup_flags |= LOOKUP_FOLLOW;
392 
393 	if (usize > PAGE_SIZE)
394 		return -E2BIG;
395 
396 	if (usize < FILE_ATTR_SIZE_VER0)
397 		return -EINVAL;
398 
399 	CLASS(filename_maybe_null, name)(filename, at_flags);
400 	if (!name && dfd >= 0) {
401 		CLASS(fd, f)(dfd);
402 		if (fd_empty(f))
403 			return -EBADF;
404 
405 		filepath = fd_file(f)->f_path;
406 		path_get(&filepath);
407 	} else {
408 		error = filename_lookup(dfd, name, lookup_flags, &filepath,
409 					NULL);
410 		if (error)
411 			return error;
412 	}
413 
414 	error = vfs_fileattr_get(filepath.dentry, &fa);
415 	if (error == -ENOIOCTLCMD || error == -ENOTTY)
416 		error = -EOPNOTSUPP;
417 	if (error)
418 		return error;
419 
420 	fileattr_to_file_attr(&fa, &fattr);
421 	error = copy_struct_to_user(ufattr, usize, &fattr,
422 				    sizeof(struct file_attr), NULL);
423 
424 	return error;
425 }
426 
427 SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
428 		struct file_attr __user *, ufattr, size_t, usize,
429 		unsigned int, at_flags)
430 {
431 	struct path filepath __free(path_put) = {};
432 	unsigned int lookup_flags = 0;
433 	struct file_attr fattr;
434 	struct file_kattr fa;
435 	int error;
436 
437 	BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
438 	BUILD_BUG_ON(sizeof(struct file_attr) != FILE_ATTR_SIZE_LATEST);
439 
440 	if ((at_flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
441 		return -EINVAL;
442 
443 	if (!(at_flags & AT_SYMLINK_NOFOLLOW))
444 		lookup_flags |= LOOKUP_FOLLOW;
445 
446 	if (usize > PAGE_SIZE)
447 		return -E2BIG;
448 
449 	if (usize < FILE_ATTR_SIZE_VER0)
450 		return -EINVAL;
451 
452 	error = copy_struct_from_user(&fattr, sizeof(struct file_attr), ufattr,
453 				      usize);
454 	if (error)
455 		return error;
456 
457 	error = file_attr_to_fileattr(&fattr, &fa);
458 	if (error)
459 		return error;
460 
461 	CLASS(filename_maybe_null, name)(filename, at_flags);
462 	if (!name && dfd >= 0) {
463 		CLASS(fd, f)(dfd);
464 		if (fd_empty(f))
465 			return -EBADF;
466 
467 		filepath = fd_file(f)->f_path;
468 		path_get(&filepath);
469 	} else {
470 		error = filename_lookup(dfd, name, lookup_flags, &filepath,
471 					NULL);
472 		if (error)
473 			return error;
474 	}
475 
476 	error = mnt_want_write(filepath.mnt);
477 	if (!error) {
478 		error = vfs_fileattr_set(mnt_idmap(filepath.mnt),
479 					 filepath.dentry, &fa);
480 		if (error == -ENOIOCTLCMD || error == -ENOTTY)
481 			error = -EOPNOTSUPP;
482 		mnt_drop_write(filepath.mnt);
483 	}
484 
485 	return error;
486 }
487