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()
Unified · Split
| @@ -279,7 +279,7 @@ How are requirements fulfilled? · 278 unmodified lines | ||
| 279 | 279 | the filesystem or not. |
| 280 | 280 | |
| 281 | 281 | Note that the *ptrace* check is not strictly necessary to |
| 282 | − prevent B/2/i, it is enough to check if mount owner has enough | |
| 282 | + prevent C/2/i, it is enough to check if mount owner has enough | |
| 283 | 283 | privilege to send signal to the process accessing the |
| 284 | 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 | |
| 289 | 289 | If a sysadmin trusts the users enough, or can ensure through other |
| 290 | 290 | measures, that system processes will never enter non-privileged |
| 291 | −mounts, it can relax the last limitation with a 'user_allow_other' | |
| 292 | −config option. If this config option is set, the mounting user can | |
| 293 | −add the 'allow_other' mount option which disables the check for other | |
| 294 | −users' processes. | |
| 291 | +mounts, it can relax the last limitation in several ways: | |
| 292 | + | |
| 293 | + - With the 'user_allow_other' config option. If this config option is | |
| 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 | + | |
| 311 | +Note that both of these relaxations expose the system to potential | |
| 312 | +information leak or *DoS* as described in points B and C/2/i-ii in the | |
| 313 | +preceding section. | |
| 295 | 314 | |
| 296 | 315 | Kernel - userspace interface |
| 297 | 316 | ============================ |
| @@ -258,7 +258,7 @@ int fuse_ctl_add_conn(struct fuse_conn *fc) · 257 unmodified lines | ||
| 258 | 258 | struct dentry *parent; |
| 259 | 259 | char name[32]; |
| 260 | 260 | |
| 261 | − if (!fuse_control_sb) | |
| 261 | + if (!fuse_control_sb || fc->no_control) | |
| 262 | 262 | return 0; |
| 263 | 263 | |
| 264 | 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 | 297 | int i; |
| 298 | 298 | |
| 299 | − if (!fuse_control_sb) | |
| 299 | + if (!fuse_control_sb || fc->no_control) | |
| 300 | 300 | return; |
| 301 | 301 | |
| 302 | 302 | for (i = fc->ctl_ndents - 1; i >= 0; i--) { |
| @@ -138,9 +138,9 @@ static struct fuse_dax_mapping *alloc_dax_mapping(struct fuse_conn_dax *fcd) · 137 unmodified lines | ||
| 138 | 138 | WARN_ON(fcd->nr_free_ranges <= 0); |
| 139 | 139 | fcd->nr_free_ranges--; |
| 140 | 140 | } |
| 141 | + __kick_dmap_free_worker(fcd, 0); | |
| 141 | 142 | spin_unlock(&fcd->lock); |
| 142 | 143 | |
| 143 | − kick_dmap_free_worker(fcd, 0); | |
| 144 | 144 | return dmap; |
| 145 | 145 | } |
| 146 | 146 | |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | #include <linux/pagemap.h> |
| 12 | 12 | #include <linux/file.h> |
| 13 | 13 | #include <linux/fs_context.h> |
| 14 | +#include <linux/moduleparam.h> | |
| 14 | 15 | #include <linux/sched.h> |
| 15 | 16 | #include <linux/namei.h> |
| 16 | 17 | #include <linux/slab.h> |
| @@ -21,6 +22,11 @@ · 4 unmodified lines | ||
| 21 | 22 | #include <linux/types.h> |
| 22 | 23 | #include <linux/kernel.h> |
| 23 | 24 | |
| 25 | +static bool __read_mostly allow_sys_admin_access; | |
| 26 | +module_param(allow_sys_admin_access, bool, 0644); | |
| 27 | +MODULE_PARM_DESC(allow_sys_admin_access, | |
| 28 | + "Allow users with CAP_SYS_ADMIN in initial userns to bypass allow_other access check"); | |
| 29 | + | |
| 24 | 30 | static void fuse_advise_use_readdirplus(struct inode *dir) |
| 25 | 31 | { |
| 26 | 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 | 543 | struct fuse_file *ff; |
| 538 | 544 | void *security_ctx = NULL; |
| 539 | 545 | u32 security_ctxlen; |
| 546 | + bool trunc = flags & O_TRUNC; | |
| 540 | 547 | |
| 541 | 548 | /* Userspace expects S_IFREG in create mode */ |
| 542 | 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 | 568 | inarg.mode = mode; |
| 562 | 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 | 572 | !(flags & O_EXCL) && !capable(CAP_FSETID)) { |
| 566 | 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 | 630 | } else { |
| 624 | 631 | file->private_data = ff; |
| 625 | 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 | 638 | return err; |
| 628 | 639 | |
| @@ -1224,6 +1235,9 @@ int fuse_allow_current_process(struct fuse_conn *fc) · 595 unmodified lines | ||
| 1224 | 1235 | { |
| 1225 | 1236 | const struct cred *cred; |
| 1226 | 1237 | |
| 1238 | + if (allow_sys_admin_access && capable(CAP_SYS_ADMIN)) | |
| 1239 | + return 1; | |
| 1240 | + | |
| 1227 | 1241 | if (fc->allow_other) |
| 1228 | 1242 | return current_in_userns(fc->user_ns); |
| 1229 | 1243 | |
| @@ -210,13 +210,9 @@ void fuse_finish_open(struct inode *inode, struct file *file) · 209 unmodified lines | ||
| 210 | 210 | fi->attr_version = atomic64_inc_return(&fc->attr_version); |
| 211 | 211 | i_size_write(inode, 0); |
| 212 | 212 | spin_unlock(&fi->lock); |
| 213 | − truncate_pagecache(inode, 0); | |
| 214 | 213 | file_update_time(file); |
| 215 | 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 | 216 | if ((file->f_mode & FMODE_WRITE) && fc->writeback_cache) |
| 221 | 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 | 235 | if (err) |
| 240 | 236 | return err; |
| 241 | 237 | |
| 242 | − if (is_wb_truncate || dax_truncate) { | |
| 238 | + if (is_wb_truncate || dax_truncate) | |
| 243 | 239 | inode_lock(inode); |
| 244 | − fuse_set_nowrite(inode); | |
| 245 | − } | |
| 246 | 240 | |
| 247 | 241 | if (dax_truncate) { |
| 248 | 242 | filemap_invalidate_lock(inode->i_mapping); |
| 249 | 243 | err = fuse_dax_break_layouts(inode, 0, 0); |
| 250 | 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 | 251 | err = fuse_do_open(fm, get_node_id(inode), file, isdir); |
| 255 | 252 | if (!err) |
| 256 | 253 | fuse_finish_open(inode, file); |
| 257 | 254 | |
| 258 | −out: | |
| 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 | 265 | if (dax_truncate) |
| 260 | 266 | filemap_invalidate_unlock(inode->i_mapping); |
| 261 | − | |
| 262 | − if (is_wb_truncate | dax_truncate) { | |
| 263 | − fuse_release_nowrite(inode); | |
| 267 | +out_inode_unlock: | |
| 268 | + if (is_wb_truncate || dax_truncate) | |
| 264 | 269 | inode_unlock(inode); |
| 265 | − } | |
| 266 | 270 | |
| 267 | 271 | return err; |
| 268 | 272 | } |
| @@ -338,6 +342,15 @@ static int fuse_open(struct inode *inode, struct file *file) · 69 unmodified lines | ||
| 338 | 342 | |
| 339 | 343 | static 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 | 354 | fuse_release_common(file, false); |
| 342 | 355 | |
| 343 | 356 | /* return value is ignored by VFS */ |
| @@ -180,6 +180,12 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, · 179 unmodified lines | ||
| 180 | 180 | inode->i_uid = make_kuid(fc->user_ns, attr->uid); |
| 181 | 181 | inode->i_gid = make_kgid(fc->user_ns, attr->gid); |
| 182 | 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 | 189 | inode->i_atime.tv_sec = attr->atime; |
| 184 | 190 | inode->i_atime.tv_nsec = attr->atimensec; |
| 185 | 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 | 483 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
| 478 | 484 | |
| 479 | − if (!fc->no_force_umount) | |
| 480 | − fuse_abort_conn(fc); | |
| 485 | + if (fc->no_force_umount) | |
| 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 | |
| 483 | 495 | static void fuse_send_destroy(struct fuse_mount *fm) |
| @@ -9,6 +9,17 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/compat.h> |
| 10 | 10 | #include <linux/fileattr.h> |
| 11 | 11 | |
| 12 | +static 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 | 24 | * CUSE servers compiled on 32bit broke on 64bit kernels because the |
| 14 | 25 | * 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 | 270 | ap.args.out_pages = true; |
| 260 | 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 | 274 | err = transferred; |
| 264 | 275 | if (transferred < 0) |
| 265 | 276 | goto out; |
| @@ -393,7 +404,7 @@ static int fuse_priv_ioctl(struct inode *inode, struct fuse_file *ff, · 127 unmodified lines | ||
| 393 | 404 | args.out_args[1].size = inarg.out_size; |
| 394 | 405 | args.out_args[1].value = ptr; |
| 395 | 406 | |
| 396 | − err = fuse_simple_request(fm, &args); | |
| 407 | + err = fuse_send_ioctl(fm, &args); | |
| 397 | 408 | if (!err) { |
| 398 | 409 | if (outarg.result < 0) |
| 399 | 410 | err = outarg.result; |
| @@ -741,8 +741,7 @@ out: · 740 unmodified lines | ||
| 741 | 741 | } |
| 742 | 742 | |
| 743 | 743 | /* Free virtqueues (device must already be reset) */ |
| 744 | −static void virtio_fs_cleanup_vqs(struct virtio_device *vdev, | |
| 745 | − struct virtio_fs *fs) | |
| 744 | +static void virtio_fs_cleanup_vqs(struct virtio_device *vdev) | |
| 746 | 745 | { |
| 747 | 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 | 757 | struct virtio_fs *fs = dax_get_private(dax_dev); |
| 759 | 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 | 761 | if (kaddr) |
| 763 | 762 | *kaddr = fs->window_kaddr + offset; |
| @@ -895,7 +894,7 @@ static int virtio_fs_probe(struct virtio_device *vdev) · 131 unmodified lines | ||
| 895 | 894 | |
| 896 | 895 | out_vqs: |
| 897 | 896 | virtio_reset_device(vdev); |
| 898 | − virtio_fs_cleanup_vqs(vdev, fs); | |
| 897 | + virtio_fs_cleanup_vqs(vdev); | |
| 899 | 898 | kfree(fs->vqs); |
| 900 | 899 | |
| 901 | 900 | out: |
| @@ -927,7 +926,7 @@ static void virtio_fs_remove(struct virtio_device *vdev) · 25 unmodified lines | ||
| 927 | 926 | virtio_fs_stop_all_queues(fs); |
| 928 | 927 | virtio_fs_drain_all_queues_locked(fs); |
| 929 | 928 | virtio_reset_device(vdev); |
| 930 | − virtio_fs_cleanup_vqs(vdev, fs); | |
| 929 | + virtio_fs_cleanup_vqs(vdev); | |
| 931 | 930 | |
| 932 | 931 | vdev->priv = NULL; |
| 933 | 932 | /* Put device reference on virtio_fs object */ |
| @@ -422,6 +422,35 @@ bool trylock_super(struct super_block *sb) · 421 unmodified lines | ||
| 422 | 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 | + */ | |
| 441 | +void 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 | +} | |
| 452 | +EXPORT_SYMBOL(retire_super); | |
| 453 | + | |
| 425 | 454 | /** |
| 426 | 455 | * generic_shutdown_super - common helper for ->kill_sb() |
| 427 | 456 | * @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 | |
| 1217 | 1246 | static 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 | |
| 1310 | 1339 | static 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 | |
| 1315 | 1344 | struct dentry *mount_bdev(struct file_system_type *fs_type, |
| @@ -1433,6 +1433,7 @@ extern int send_sigurg(struct fown_struct *fown); · 1432 unmodified lines | ||
| 1433 | 1433 | #define SB_I_SKIP_SYNC 0x00000100 /* Skip superblock at global sync */ |
| 1434 | 1434 | #define SB_I_PERSB_BDI 0x00000200 /* has a per-sb bdi */ |
| 1435 | 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 | 1438 | /* Possible states of 'frozen' field */ |
| 1438 | 1439 | enum { |
| @@ -2565,6 +2566,7 @@ extern struct dentry *mount_nodev(struct file_system_type *fs_type, · 1126 unmodified lines | ||
| 2565 | 2566 | int flags, void *data, |
| 2566 | 2567 | int (*fill_super)(struct super_block *, void *, int)); |
| 2567 | 2568 | extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path); |
| 2569 | +void retire_super(struct super_block *sb); | |
| 2568 | 2570 | void generic_shutdown_super(struct super_block *sb); |
| 2569 | 2571 | void kill_block_super(struct super_block *sb); |
| 2570 | 2572 | void kill_anon_super(struct super_block *sb); |