History

Merge tag 'fuse-update-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi: - Fix an issue with reusing the bdi in case of block based filesystems - Allow root (in init namespace) to access fuse filesystems in user namespaces if expicitly enabled with a module param - Misc fixes * tag 'fuse-update-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: retire block-device-based superblock on force unmount vfs: function to prevent re-use of block-device-based superblocks virtio_fs: Modify format for virtio_fs_direct_access virtiofs: delete unused parameter for virtio_fs_cleanup_vqs fuse: Add module param for CAP_SYS_ADMIN access bypassing allow_other fuse: Remove the control interface for virtio-fs fuse: ioctl: translate ENOSYS fuse: limit nsec fuse: avoid unnecessary spinlock bump fuse: fix deadlock between atomic O_TRUNC and page invalidation fuse: write inode in fuse_release()

Linus Torvalds committed 4 years ago

Commit 2bd5d412 parents 65512eb 247861c10 files · +132 −33Browse files

Unified · Split

10 files
  1. Documentation/filesystems/fuse.rst +24 −5
  2. fs/fuse/control.c +2 −2
  3. fs/fuse/dax.c +1 −1
  4. fs/fuse/dir.c +15 −1
  5. fs/fuse/file.c +26 −13
  6. fs/fuse/inode.c +14 −2
  7. fs/fuse/ioctl.c +13 −2
  8. fs/fuse/virtio_fs.c +4 −5
  9. fs/super.c +31 −2
  10. include/linux/fs.h +2 −0
Documentation/filesystems/fuse.rst+24−5
@@ -279,7 +279,7 @@ How are requirements fulfilled? · 278 unmodified lines
279 the filesystem or not.279 the filesystem or not.
280 280
281 Note that the *ptrace* check is not strictly necessary to281 Note that the *ptrace* check is not strictly necessary to
282 prevent B/2/i, it is enough to check if mount owner has enough282 prevent C/2/i, it is enough to check if mount owner has enough
283 privilege to send signal to the process accessing the283 privilege to send signal to the process accessing the
284 filesystem, since *SIGSTOP* can be used to get a similar effect.284 filesystem, since *SIGSTOP* can be used to get a similar effect.
285 285
@@ -288,10 +288,29 @@ I think these limitations are unacceptable? · 2 unmodified lines
288 288
289If a sysadmin trusts the users enough, or can ensure through other289If a sysadmin trusts the users enough, or can ensure through other
290measures, that system processes will never enter non-privileged290measures, that system processes will never enter non-privileged
291mounts, it can relax the last limitation with a 'user_allow_other'291mounts, it can relax the last limitation in several ways:
292config option. If this config option is set, the mounting user can292
293add the 'allow_other' mount option which disables the check for other293 - With the 'user_allow_other' config option. If this config option is
294users' processes.294 set, the mounting user can add the 'allow_other' mount option which
295 disables the check for other users' processes.
296
297 User namespaces have an unintuitive interaction with 'allow_other':
298 an unprivileged user - normally restricted from mounting with
299 'allow_other' - could do so in a user namespace where they're
300 privileged. If any process could access such an 'allow_other' mount
301 this would give the mounting user the ability to manipulate
302 processes in user namespaces where they're unprivileged. For this
303 reason 'allow_other' restricts access to users in the same userns
304 or a descendant.
305
306 - With the 'allow_sys_admin_access' module option. If this option is
307 set, super user's processes have unrestricted access to mounts
308 irrespective of allow_other setting or user namespace of the
309 mounting user.
310
311Note that both of these relaxations expose the system to potential
312information leak or *DoS* as described in points B and C/2/i-ii in the
313preceding section.
295 314
296Kernel - userspace interface315Kernel - userspace interface
297============================316============================
fs/fuse/control.c+2−2
@@ -258,7 +258,7 @@ int fuse_ctl_add_conn(struct fuse_conn *fc) · 257 unmodified lines
258 struct dentry *parent;258 struct dentry *parent;
259 char name[32];259 char name[32];
260 260
261 if (!fuse_control_sb)261 if (!fuse_control_sb || fc->no_control)
262 return 0;262 return 0;
263 263
264 parent = fuse_control_sb->s_root;264 parent = fuse_control_sb->s_root;
@@ -296,7 +296,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) · 31 unmodified lines
296{296{
297 int i;297 int i;
298 298
299 if (!fuse_control_sb)299 if (!fuse_control_sb || fc->no_control)
300 return;300 return;
301 301
302 for (i = fc->ctl_ndents - 1; i >= 0; i--) {302 for (i = fc->ctl_ndents - 1; i >= 0; i--) {
fs/fuse/dax.c+1−1
@@ -138,9 +138,9 @@ static struct fuse_dax_mapping *alloc_dax_mapping(struct fuse_conn_dax *fcd) · 137 unmodified lines
138 WARN_ON(fcd->nr_free_ranges <= 0);138 WARN_ON(fcd->nr_free_ranges <= 0);
139 fcd->nr_free_ranges--;139 fcd->nr_free_ranges--;
140 }140 }
141 __kick_dmap_free_worker(fcd, 0);
141 spin_unlock(&fcd->lock);142 spin_unlock(&fcd->lock);
142 143
143 kick_dmap_free_worker(fcd, 0);
144 return dmap;144 return dmap;
145}145}
146 146
fs/fuse/dir.c+15−1
@@ -11,6 +11,7 @@ · 10 unmodified lines
11#include <linux/pagemap.h>11#include <linux/pagemap.h>
12#include <linux/file.h>12#include <linux/file.h>
13#include <linux/fs_context.h>13#include <linux/fs_context.h>
14#include <linux/moduleparam.h>
14#include <linux/sched.h>15#include <linux/sched.h>
15#include <linux/namei.h>16#include <linux/namei.h>
16#include <linux/slab.h>17#include <linux/slab.h>
@@ -21,6 +22,11 @@ · 4 unmodified lines
21#include <linux/types.h>22#include <linux/types.h>
22#include <linux/kernel.h>23#include <linux/kernel.h>
23 24
25static bool __read_mostly allow_sys_admin_access;
26module_param(allow_sys_admin_access, bool, 0644);
27MODULE_PARM_DESC(allow_sys_admin_access,
28 "Allow users with CAP_SYS_ADMIN in initial userns to bypass allow_other access check");
29
24static void fuse_advise_use_readdirplus(struct inode *dir)30static void fuse_advise_use_readdirplus(struct inode *dir)
25{31{
26 struct fuse_inode *fi = get_fuse_inode(dir);32 struct fuse_inode *fi = get_fuse_inode(dir);
@@ -537,6 +543,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, · 510 unmodified lines
537 struct fuse_file *ff;543 struct fuse_file *ff;
538 void *security_ctx = NULL;544 void *security_ctx = NULL;
539 u32 security_ctxlen;545 u32 security_ctxlen;
546 bool trunc = flags & O_TRUNC;
540 547
541 /* Userspace expects S_IFREG in create mode */548 /* Userspace expects S_IFREG in create mode */
542 BUG_ON((mode & S_IFMT) != S_IFREG);549 BUG_ON((mode & S_IFMT) != S_IFREG);
@@ -561,7 +568,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, · 18 unmodified lines
561 inarg.mode = mode;568 inarg.mode = mode;
562 inarg.umask = current_umask();569 inarg.umask = current_umask();
563 570
564 if (fm->fc->handle_killpriv_v2 && (flags & O_TRUNC) &&571 if (fm->fc->handle_killpriv_v2 && trunc &&
565 !(flags & O_EXCL) && !capable(CAP_FSETID)) {572 !(flags & O_EXCL) && !capable(CAP_FSETID)) {
566 inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID;573 inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID;
567 }574 }
@@ -623,6 +630,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, · 55 unmodified lines
623 } else {630 } else {
624 file->private_data = ff;631 file->private_data = ff;
625 fuse_finish_open(inode, file);632 fuse_finish_open(inode, file);
633 if (fm->fc->atomic_o_trunc && trunc)
634 truncate_pagecache(inode, 0);
635 else if (!(ff->open_flags & FOPEN_KEEP_CACHE))
636 invalidate_inode_pages2(inode->i_mapping);
626 }637 }
627 return err;638 return err;
628 639
@@ -1224,6 +1235,9 @@ int fuse_allow_current_process(struct fuse_conn *fc) · 595 unmodified lines
1224{1235{
1225 const struct cred *cred;1236 const struct cred *cred;
1226 1237
1238 if (allow_sys_admin_access && capable(CAP_SYS_ADMIN))
1239 return 1;
1240
1227 if (fc->allow_other)1241 if (fc->allow_other)
1228 return current_in_userns(fc->user_ns);1242 return current_in_userns(fc->user_ns);
1229 1243
fs/fuse/file.c+26−13
@@ -210,13 +210,9 @@ void fuse_finish_open(struct inode *inode, struct file *file) · 209 unmodified lines
210 fi->attr_version = atomic64_inc_return(&fc->attr_version);210 fi->attr_version = atomic64_inc_return(&fc->attr_version);
211 i_size_write(inode, 0);211 i_size_write(inode, 0);
212 spin_unlock(&fi->lock);212 spin_unlock(&fi->lock);
213 truncate_pagecache(inode, 0);
214 file_update_time(file);213 file_update_time(file);
215 fuse_invalidate_attr_mask(inode, FUSE_STATX_MODSIZE);214 fuse_invalidate_attr_mask(inode, FUSE_STATX_MODSIZE);
216 } else if (!(ff->open_flags & FOPEN_KEEP_CACHE)) {
217 invalidate_inode_pages2(inode->i_mapping);
218 }215 }
219
220 if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache)216 if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache)
221 fuse_link_write_file(file);217 fuse_link_write_file(file);
222}218}
@@ -239,30 +235,38 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) · 16 unmodified lines
239 if (err)235 if (err)
240 return err;236 return err;
241 237
242 if (is_wb_truncate || dax_truncate) {238 if (is_wb_truncate || dax_truncate)
243 inode_lock(inode);239 inode_lock(inode);
244 fuse_set_nowrite(inode);
245 }
246 240
247 if (dax_truncate) {241 if (dax_truncate) {
248 filemap_invalidate_lock(inode->i_mapping);242 filemap_invalidate_lock(inode->i_mapping);
249 err = fuse_dax_break_layouts(inode, 0, 0);243 err = fuse_dax_break_layouts(inode, 0, 0);
250 if (err)244 if (err)
251 goto out;245 goto out_inode_unlock;
252 }246 }
253 247
248 if (is_wb_truncate || dax_truncate)
249 fuse_set_nowrite(inode);
250
254 err = fuse_do_open(fm, get_node_id(inode), file, isdir);251 err = fuse_do_open(fm, get_node_id(inode), file, isdir);
255 if (!err)252 if (!err)
256 fuse_finish_open(inode, file);253 fuse_finish_open(inode, file);
257 254
258out:255 if (is_wb_truncate || dax_truncate)
256 fuse_release_nowrite(inode);
257 if (!err) {
258 struct fuse_file *ff = file->private_data;
259
260 if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC))
261 truncate_pagecache(inode, 0);
262 else if (!(ff->open_flags & FOPEN_KEEP_CACHE))
263 invalidate_inode_pages2(inode->i_mapping);
264 }
259 if (dax_truncate)265 if (dax_truncate)
260 filemap_invalidate_unlock(inode->i_mapping);266 filemap_invalidate_unlock(inode->i_mapping);
261 267out_inode_unlock:
262 if (is_wb_truncate | dax_truncate) {268 if (is_wb_truncate || dax_truncate)
263 fuse_release_nowrite(inode);
264 inode_unlock(inode);269 inode_unlock(inode);
265 }
266 270
267 return err;271 return err;
268}272}
@@ -338,6 +342,15 @@ static int fuse_open(struct inode *inode, struct file *file) · 69 unmodified lines
338 342
339static int fuse_release(struct inode *inode, struct file *file)343static int fuse_release(struct inode *inode, struct file *file)
340{344{
345 struct fuse_conn *fc = get_fuse_conn(inode);
346
347 /*
348 * Dirty pages might remain despite write_inode_now() call from
349 * fuse_flush() due to writes racing with the close.
350 */
351 if (fc->writeback_cache)
352 write_inode_now(inode, 1);
353
341 fuse_release_common(file, false);354 fuse_release_common(file, false);
342 355
343 /* return value is ignored by VFS */356 /* return value is ignored by VFS */
fs/fuse/inode.c+14−2
@@ -180,6 +180,12 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, · 179 unmodified lines
180 inode->i_uid = make_kuid(fc->user_ns, attr->uid);180 inode->i_uid = make_kuid(fc->user_ns, attr->uid);
181 inode->i_gid = make_kgid(fc->user_ns, attr->gid);181 inode->i_gid = make_kgid(fc->user_ns, attr->gid);
182 inode->i_blocks = attr->blocks;182 inode->i_blocks = attr->blocks;
183
184 /* Sanitize nsecs */
185 attr->atimensec = min_t(u32, attr->atimensec, NSEC_PER_SEC - 1);
186 attr->mtimensec = min_t(u32, attr->mtimensec, NSEC_PER_SEC - 1);
187 attr->ctimensec = min_t(u32, attr->ctimensec, NSEC_PER_SEC - 1);
188
183 inode->i_atime.tv_sec = attr->atime;189 inode->i_atime.tv_sec = attr->atime;
184 inode->i_atime.tv_nsec = attr->atimensec;190 inode->i_atime.tv_nsec = attr->atimensec;
185 /* mtime from server may be stale due to local buffered write */191 /* mtime from server may be stale due to local buffered write */
@@ -476,8 +482,14 @@ static void fuse_umount_begin(struct super_block *sb) · 290 unmodified lines
476{482{
477 struct fuse_conn *fc = get_fuse_conn_super(sb);483 struct fuse_conn *fc = get_fuse_conn_super(sb);
478 484
479 if (!fc->no_force_umount)485 if (fc->no_force_umount)
480 fuse_abort_conn(fc);486 return;
487
488 fuse_abort_conn(fc);
489
490 // Only retire block-device-based superblocks.
491 if (sb->s_bdev != NULL)
492 retire_super(sb);
481}493}
482 494
483static void fuse_send_destroy(struct fuse_mount *fm)495static void fuse_send_destroy(struct fuse_mount *fm)
fs/fuse/ioctl.c+13−2
@@ -9,6 +9,17 @@ · 8 unmodified lines
9#include <linux/compat.h>9#include <linux/compat.h>
10#include <linux/fileattr.h>10#include <linux/fileattr.h>
11 11
12static ssize_t fuse_send_ioctl(struct fuse_mount *fm, struct fuse_args *args)
13{
14 ssize_t ret = fuse_simple_request(fm, args);
15
16 /* Translate ENOSYS, which shouldn't be returned from fs */
17 if (ret == -ENOSYS)
18 ret = -ENOTTY;
19
20 return ret;
21}
22
12/*23/*
13 * CUSE servers compiled on 32bit broke on 64bit kernels because the24 * CUSE servers compiled on 32bit broke on 64bit kernels because the
14 * ABI was defined to be 'struct iovec' which is different on 32bit25 * ABI was defined to be 'struct iovec' which is different on 32bit
@@ -259,7 +270,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, · 244 unmodified lines
259 ap.args.out_pages = true;270 ap.args.out_pages = true;
260 ap.args.out_argvar = true;271 ap.args.out_argvar = true;
261 272
262 transferred = fuse_simple_request(fm, &ap.args);273 transferred = fuse_send_ioctl(fm, &ap.args);
263 err = transferred;274 err = transferred;
264 if (transferred < 0)275 if (transferred < 0)
265 goto out;276 goto out;
@@ -393,7 +404,7 @@ static int fuse_priv_ioctl(struct inode *inode, struct fuse_file *ff, · 127 unmodified lines
393 args.out_args[1].size = inarg.out_size;404 args.out_args[1].size = inarg.out_size;
394 args.out_args[1].value = ptr;405 args.out_args[1].value = ptr;
395 406
396 err = fuse_simple_request(fm, &args);407 err = fuse_send_ioctl(fm, &args);
397 if (!err) {408 if (!err) {
398 if (outarg.result < 0)409 if (outarg.result < 0)
399 err = outarg.result;410 err = outarg.result;
fs/fuse/virtio_fs.c+4−5
@@ -741,8 +741,7 @@ out: · 740 unmodified lines
741}741}
742 742
743/* Free virtqueues (device must already be reset) */743/* Free virtqueues (device must already be reset) */
744static void virtio_fs_cleanup_vqs(struct virtio_device *vdev,744static void virtio_fs_cleanup_vqs(struct virtio_device *vdev)
745 struct virtio_fs *fs)
746{745{
747 vdev->config->del_vqs(vdev);746 vdev->config->del_vqs(vdev);
748}747}
@@ -757,7 +756,7 @@ static long virtio_fs_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, · 8 unmodified lines
757{756{
758 struct virtio_fs *fs = dax_get_private(dax_dev);757 struct virtio_fs *fs = dax_get_private(dax_dev);
759 phys_addr_t offset = PFN_PHYS(pgoff);758 phys_addr_t offset = PFN_PHYS(pgoff);
760 size_t max_nr_pages = fs->window_len/PAGE_SIZE - pgoff;759 size_t max_nr_pages = fs->window_len / PAGE_SIZE - pgoff;
761 760
762 if (kaddr)761 if (kaddr)
763 *kaddr = fs->window_kaddr + offset;762 *kaddr = fs->window_kaddr + offset;
@@ -895,7 +894,7 @@ static int virtio_fs_probe(struct virtio_device *vdev) · 131 unmodified lines
895 894
896out_vqs:895out_vqs:
897 virtio_reset_device(vdev);896 virtio_reset_device(vdev);
898 virtio_fs_cleanup_vqs(vdev, fs);897 virtio_fs_cleanup_vqs(vdev);
899 kfree(fs->vqs);898 kfree(fs->vqs);
900 899
901out:900out:
@@ -927,7 +926,7 @@ static void virtio_fs_remove(struct virtio_device *vdev) · 25 unmodified lines
927 virtio_fs_stop_all_queues(fs);926 virtio_fs_stop_all_queues(fs);
928 virtio_fs_drain_all_queues_locked(fs);927 virtio_fs_drain_all_queues_locked(fs);
929 virtio_reset_device(vdev);928 virtio_reset_device(vdev);
930 virtio_fs_cleanup_vqs(vdev, fs);929 virtio_fs_cleanup_vqs(vdev);
931 930
932 vdev->priv = NULL;931 vdev->priv = NULL;
933 /* Put device reference on virtio_fs object */932 /* Put device reference on virtio_fs object */
fs/super.c+31−2
@@ -422,6 +422,35 @@ bool trylock_super(struct super_block *sb) · 421 unmodified lines
422 return false;422 return false;
423}423}
424 424
425/**
426 * retire_super - prevents superblock from being reused
427 * @sb: superblock to retire
428 *
429 * The function marks superblock to be ignored in superblock test, which
430 * prevents it from being reused for any new mounts. If the superblock has
431 * a private bdi, it also unregisters it, but doesn't reduce the refcount
432 * of the superblock to prevent potential races. The refcount is reduced
433 * by generic_shutdown_super(). The function can not be called
434 * concurrently with generic_shutdown_super(). It is safe to call the
435 * function multiple times, subsequent calls have no effect.
436 *
437 * The marker will affect the re-use only for block-device-based
438 * superblocks. Other superblocks will still get marked if this function
439 * is used, but that will not affect their reusability.
440 */
441void retire_super(struct super_block *sb)
442{
443 WARN_ON(!sb->s_bdev);
444 down_write(&sb->s_umount);
445 if (sb->s_iflags & SB_I_PERSB_BDI) {
446 bdi_unregister(sb->s_bdi);
447 sb->s_iflags &= ~SB_I_PERSB_BDI;
448 }
449 sb->s_iflags |= SB_I_RETIRED;
450 up_write(&sb->s_umount);
451}
452EXPORT_SYMBOL(retire_super);
453
425/**454/**
426 * generic_shutdown_super - common helper for ->kill_sb()455 * generic_shutdown_super - common helper for ->kill_sb()
427 * @sb: superblock to kill456 * @sb: superblock to kill
@@ -1216,7 +1245,7 @@ static int set_bdev_super_fc(struct super_block *s, struct fs_context *fc) · 788 unmodified lines
1216 1245
1217static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc)1246static int test_bdev_super_fc(struct super_block *s, struct fs_context *fc)
1218{1247{
1219 return s->s_bdev == fc->sget_key;1248 return !(s->s_iflags & SB_I_RETIRED) && s->s_bdev == fc->sget_key;
1220}1249}
1221 1250
1222/**1251/**
@@ -1309,7 +1338,7 @@ EXPORT_SYMBOL(get_tree_bdev); · 86 unmodified lines
1309 1338
1310static int test_bdev_super(struct super_block *s, void *data)1339static int test_bdev_super(struct super_block *s, void *data)
1311{1340{
1312 return (void *)s->s_bdev == data;1341 return !(s->s_iflags & SB_I_RETIRED) && (void *)s->s_bdev == data;
1313}1342}
1314 1343
1315struct dentry *mount_bdev(struct file_system_type *fs_type,1344struct dentry *mount_bdev(struct file_system_type *fs_type,
include/linux/fs.h+2−0
@@ -1433,6 +1433,7 @@ extern int send_sigurg(struct fown_struct *fown); · 1432 unmodified lines
1433#define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */1433#define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */
1434#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */1434#define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */
1435#define SB_I_TS_EXPIRY_WARNED 0x00000400 /* warned about timestamp range expiry */1435#define SB_I_TS_EXPIRY_WARNED 0x00000400 /* warned about timestamp range expiry */
1436#define SB_I_RETIRED 0x00000800 /* superblock shouldn't be reused */
1436 1437
1437/* Possible states of 'frozen' field */1438/* Possible states of 'frozen' field */
1438enum {1439enum {
@@ -2565,6 +2566,7 @@ extern struct dentry *mount_nodev(struct file_system_type *fs_type, · 1126 unmodified lines
2565 int flags, void *data,2566 int flags, void *data,
2566 int (*fill_super)(struct super_block *, void *, int));2567 int (*fill_super)(struct super_block *, void *, int));
2567extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path);2568extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path);
2569void retire_super(struct super_block *sb);
2568void generic_shutdown_super(struct super_block *sb);2570void generic_shutdown_super(struct super_block *sb);
2569void kill_block_super(struct super_block *sb);2571void kill_block_super(struct super_block *sb);
2570void kill_anon_super(struct super_block *sb);2572void kill_anon_super(struct super_block *sb);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t