Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

Pull fuse updates from Miklos Szeredi:

- Fix regression in fileattr permission checking

- Fix possible hang during PID namespace destruction

- Add generic support for request extensions

- Add supplementary group list extension

- Add limited support for supplying supplementary groups in create
requests

- Documentation fixes

* tag 'fuse-update-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: add inode/permission checks to fileattr_get/fileattr_set
fuse: fix all W=1 kernel-doc warnings
fuse: in fuse_flush only wait if someone wants the return code
fuse: optional supplementary group in create requests
fuse: add request extension

+225 -62
+1 -1
fs/fuse/cuse.c
··· 256 256 } 257 257 258 258 /** 259 - * cuse_parse_dev_info - parse device info 259 + * cuse_parse_devinfo - parse device info 260 260 * @p: device info string 261 261 * @len: length of device info string 262 262 * @devinfo: out parameter for parsed device info
+3 -1
fs/fuse/dev.c
··· 204 204 return hash_long(unique & ~FUSE_INT_REQ_BIT, FUSE_PQ_HASH_BITS); 205 205 } 206 206 207 - /** 207 + /* 208 208 * A new request is available, wake fiq->waitq 209 209 */ 210 210 static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq) ··· 476 476 req->in.h.opcode = args->opcode; 477 477 req->in.h.nodeid = args->nodeid; 478 478 req->args = args; 479 + if (args->is_ext) 480 + req->in.h.total_extlen = args->in_args[args->ext_idx].size / 8; 479 481 if (args->end) 480 482 __set_bit(FR_ASYNC, &req->flags); 481 483 }
+97 -29
fs/fuse/dir.c
··· 145 145 inode_maybe_inc_iversion(dir, false); 146 146 } 147 147 148 - /** 148 + /* 149 149 * Mark the attributes as stale due to an atime change. Avoid the invalidate if 150 150 * atime is not used. 151 151 */ ··· 466 466 } 467 467 468 468 static int get_security_context(struct dentry *entry, umode_t mode, 469 - void **security_ctx, u32 *security_ctxlen) 469 + struct fuse_in_arg *ext) 470 470 { 471 471 struct fuse_secctx *fctx; 472 472 struct fuse_secctx_header *header; ··· 513 513 514 514 memcpy(ptr, ctx, ctxlen); 515 515 } 516 - *security_ctxlen = total_len; 517 - *security_ctx = header; 516 + ext->size = total_len; 517 + ext->value = header; 518 518 err = 0; 519 519 out_err: 520 520 kfree(ctx); 521 521 return err; 522 + } 523 + 524 + static void *extend_arg(struct fuse_in_arg *buf, u32 bytes) 525 + { 526 + void *p; 527 + u32 newlen = buf->size + bytes; 528 + 529 + p = krealloc(buf->value, newlen, GFP_KERNEL); 530 + if (!p) { 531 + kfree(buf->value); 532 + buf->size = 0; 533 + buf->value = NULL; 534 + return NULL; 535 + } 536 + 537 + memset(p + buf->size, 0, bytes); 538 + buf->value = p; 539 + buf->size = newlen; 540 + 541 + return p + newlen - bytes; 542 + } 543 + 544 + static u32 fuse_ext_size(size_t size) 545 + { 546 + return FUSE_REC_ALIGN(sizeof(struct fuse_ext_header) + size); 547 + } 548 + 549 + /* 550 + * This adds just a single supplementary group that matches the parent's group. 551 + */ 552 + static int get_create_supp_group(struct inode *dir, struct fuse_in_arg *ext) 553 + { 554 + struct fuse_conn *fc = get_fuse_conn(dir); 555 + struct fuse_ext_header *xh; 556 + struct fuse_supp_groups *sg; 557 + kgid_t kgid = dir->i_gid; 558 + gid_t parent_gid = from_kgid(fc->user_ns, kgid); 559 + u32 sg_len = fuse_ext_size(sizeof(*sg) + sizeof(sg->groups[0])); 560 + 561 + if (parent_gid == (gid_t) -1 || gid_eq(kgid, current_fsgid()) || 562 + !in_group_p(kgid)) 563 + return 0; 564 + 565 + xh = extend_arg(ext, sg_len); 566 + if (!xh) 567 + return -ENOMEM; 568 + 569 + xh->size = sg_len; 570 + xh->type = FUSE_EXT_GROUPS; 571 + 572 + sg = (struct fuse_supp_groups *) &xh[1]; 573 + sg->nr_groups = 1; 574 + sg->groups[0] = parent_gid; 575 + 576 + return 0; 577 + } 578 + 579 + static int get_create_ext(struct fuse_args *args, 580 + struct inode *dir, struct dentry *dentry, 581 + umode_t mode) 582 + { 583 + struct fuse_conn *fc = get_fuse_conn_super(dentry->d_sb); 584 + struct fuse_in_arg ext = { .size = 0, .value = NULL }; 585 + int err = 0; 586 + 587 + if (fc->init_security) 588 + err = get_security_context(dentry, mode, &ext); 589 + if (!err && fc->create_supp_group) 590 + err = get_create_supp_group(dir, &ext); 591 + 592 + if (!err && ext.size) { 593 + WARN_ON(args->in_numargs >= ARRAY_SIZE(args->in_args)); 594 + args->is_ext = true; 595 + args->ext_idx = args->in_numargs++; 596 + args->in_args[args->ext_idx] = ext; 597 + } else { 598 + kfree(ext.value); 599 + } 600 + 601 + return err; 602 + } 603 + 604 + static void free_ext_value(struct fuse_args *args) 605 + { 606 + if (args->is_ext) 607 + kfree(args->in_args[args->ext_idx].value); 522 608 } 523 609 524 610 /* ··· 627 541 struct fuse_entry_out outentry; 628 542 struct fuse_inode *fi; 629 543 struct fuse_file *ff; 630 - void *security_ctx = NULL; 631 - u32 security_ctxlen; 632 544 bool trunc = flags & O_TRUNC; 633 545 634 546 /* Userspace expects S_IFREG in create mode */ ··· 670 586 args.out_args[1].size = sizeof(outopen); 671 587 args.out_args[1].value = &outopen; 672 588 673 - if (fm->fc->init_security) { 674 - err = get_security_context(entry, mode, &security_ctx, 675 - &security_ctxlen); 676 - if (err) 677 - goto out_put_forget_req; 678 - 679 - args.in_numargs = 3; 680 - args.in_args[2].size = security_ctxlen; 681 - args.in_args[2].value = security_ctx; 682 - } 589 + err = get_create_ext(&args, dir, entry, mode); 590 + if (err) 591 + goto out_put_forget_req; 683 592 684 593 err = fuse_simple_request(fm, &args); 685 - kfree(security_ctx); 594 + free_ext_value(&args); 686 595 if (err) 687 596 goto out_free_ff; 688 597 ··· 782 705 struct dentry *d; 783 706 int err; 784 707 struct fuse_forget_link *forget; 785 - void *security_ctx = NULL; 786 - u32 security_ctxlen; 787 708 788 709 if (fuse_is_bad(dir)) 789 710 return -EIO; ··· 796 721 args->out_args[0].size = sizeof(outarg); 797 722 args->out_args[0].value = &outarg; 798 723 799 - if (fm->fc->init_security && args->opcode != FUSE_LINK) { 800 - err = get_security_context(entry, mode, &security_ctx, 801 - &security_ctxlen); 724 + if (args->opcode != FUSE_LINK) { 725 + err = get_create_ext(args, dir, entry, mode); 802 726 if (err) 803 727 goto out_put_forget_req; 804 - 805 - BUG_ON(args->in_numargs != 2); 806 - 807 - args->in_numargs = 3; 808 - args->in_args[2].size = security_ctxlen; 809 - args->in_args[2].value = security_ctx; 810 728 } 811 729 812 730 err = fuse_simple_request(fm, args); 813 - kfree(security_ctx); 731 + free_ext_value(args); 814 732 if (err) 815 733 goto out_put_forget_req; 816 734
+64 -27
fs/fuse/file.c
··· 19 19 #include <linux/uio.h> 20 20 #include <linux/fs.h> 21 21 #include <linux/filelock.h> 22 + #include <linux/file.h> 22 23 23 24 static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, 24 25 unsigned int open_flags, int opcode, ··· 479 478 fuse_release_nowrite(inode); 480 479 } 481 480 482 - static int fuse_flush(struct file *file, fl_owner_t id) 483 - { 484 - struct inode *inode = file_inode(file); 485 - struct fuse_mount *fm = get_fuse_mount(inode); 486 - struct fuse_file *ff = file->private_data; 481 + struct fuse_flush_args { 482 + struct fuse_args args; 487 483 struct fuse_flush_in inarg; 488 - FUSE_ARGS(args); 484 + struct work_struct work; 485 + struct file *file; 486 + }; 487 + 488 + static int fuse_do_flush(struct fuse_flush_args *fa) 489 + { 489 490 int err; 490 - 491 - if (fuse_is_bad(inode)) 492 - return -EIO; 493 - 494 - if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) 495 - return 0; 491 + struct inode *inode = file_inode(fa->file); 492 + struct fuse_mount *fm = get_fuse_mount(inode); 496 493 497 494 err = write_inode_now(inode, 1); 498 495 if (err) 499 - return err; 496 + goto out; 500 497 501 498 inode_lock(inode); 502 499 fuse_sync_writes(inode); 503 500 inode_unlock(inode); 504 501 505 - err = filemap_check_errors(file->f_mapping); 502 + err = filemap_check_errors(fa->file->f_mapping); 506 503 if (err) 507 - return err; 504 + goto out; 508 505 509 506 err = 0; 510 507 if (fm->fc->no_flush) 511 508 goto inval_attr_out; 512 509 513 - memset(&inarg, 0, sizeof(inarg)); 514 - inarg.fh = ff->fh; 515 - inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); 516 - args.opcode = FUSE_FLUSH; 517 - args.nodeid = get_node_id(inode); 518 - args.in_numargs = 1; 519 - args.in_args[0].size = sizeof(inarg); 520 - args.in_args[0].value = &inarg; 521 - args.force = true; 522 - 523 - err = fuse_simple_request(fm, &args); 510 + err = fuse_simple_request(fm, &fa->args); 524 511 if (err == -ENOSYS) { 525 512 fm->fc->no_flush = 1; 526 513 err = 0; ··· 521 532 */ 522 533 if (!err && fm->fc->writeback_cache) 523 534 fuse_invalidate_attr_mask(inode, STATX_BLOCKS); 535 + 536 + out: 537 + fput(fa->file); 538 + kfree(fa); 524 539 return err; 540 + } 541 + 542 + static void fuse_flush_async(struct work_struct *work) 543 + { 544 + struct fuse_flush_args *fa = container_of(work, typeof(*fa), work); 545 + 546 + fuse_do_flush(fa); 547 + } 548 + 549 + static int fuse_flush(struct file *file, fl_owner_t id) 550 + { 551 + struct fuse_flush_args *fa; 552 + struct inode *inode = file_inode(file); 553 + struct fuse_mount *fm = get_fuse_mount(inode); 554 + struct fuse_file *ff = file->private_data; 555 + 556 + if (fuse_is_bad(inode)) 557 + return -EIO; 558 + 559 + if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) 560 + return 0; 561 + 562 + fa = kzalloc(sizeof(*fa), GFP_KERNEL); 563 + if (!fa) 564 + return -ENOMEM; 565 + 566 + fa->inarg.fh = ff->fh; 567 + fa->inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); 568 + fa->args.opcode = FUSE_FLUSH; 569 + fa->args.nodeid = get_node_id(inode); 570 + fa->args.in_numargs = 1; 571 + fa->args.in_args[0].size = sizeof(fa->inarg); 572 + fa->args.in_args[0].value = &fa->inarg; 573 + fa->args.force = true; 574 + fa->file = get_file(file); 575 + 576 + /* Don't wait if the task is exiting */ 577 + if (current->flags & PF_EXITING) { 578 + INIT_WORK(&fa->work, fuse_flush_async); 579 + schedule_work(&fa->work); 580 + return 0; 581 + } 582 + 583 + return fuse_do_flush(fa); 525 584 } 526 585 527 586 int fuse_fsync_common(struct file *file, loff_t start, loff_t end, ··· 690 653 return io->bytes < 0 ? io->size : io->bytes; 691 654 } 692 655 693 - /** 656 + /* 694 657 * In case of short read, the caller sets 'pos' to the position of 695 658 * actual end of fuse request in IO request. Otherwise, if bytes_requested 696 659 * == bytes_transferred or rw == WRITE, the caller sets 'pos' to -1.
+7 -2
fs/fuse/fuse_i.h
··· 249 249 struct fuse_args { 250 250 uint64_t nodeid; 251 251 uint32_t opcode; 252 - unsigned short in_numargs; 253 - unsigned short out_numargs; 252 + uint8_t in_numargs; 253 + uint8_t out_numargs; 254 + uint8_t ext_idx; 254 255 bool force:1; 255 256 bool noreply:1; 256 257 bool nocreds:1; ··· 262 261 bool page_zeroing:1; 263 262 bool page_replace:1; 264 263 bool may_block:1; 264 + bool is_ext:1; 265 265 struct fuse_in_arg in_args[3]; 266 266 struct fuse_arg out_args[2]; 267 267 void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error); ··· 782 780 783 781 /* Initialize security xattrs when creating a new inode */ 784 782 unsigned int init_security:1; 783 + 784 + /* Add supplementary group info when creating a new inode */ 785 + unsigned int create_supp_group:1; 785 786 786 787 /* Does the filesystem support per inode DAX? */ 787 788 unsigned int inode_dax:1;
+3 -1
fs/fuse/inode.c
··· 1207 1207 fc->setxattr_ext = 1; 1208 1208 if (flags & FUSE_SECURITY_CTX) 1209 1209 fc->init_security = 1; 1210 + if (flags & FUSE_CREATE_SUPP_GROUP) 1211 + fc->create_supp_group = 1; 1210 1212 } else { 1211 1213 ra_pages = fc->max_read / PAGE_SIZE; 1212 1214 fc->no_lock = 1; ··· 1254 1252 FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS | 1255 1253 FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | 1256 1254 FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT | 1257 - FUSE_SECURITY_CTX; 1255 + FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP; 1258 1256 #ifdef CONFIG_FUSE_DAX 1259 1257 if (fm->fc->dax) 1260 1258 flags |= FUSE_MAP_ALIGNMENT;
+6
fs/fuse/ioctl.c
··· 419 419 struct fuse_mount *fm = get_fuse_mount(inode); 420 420 bool isdir = S_ISDIR(inode->i_mode); 421 421 422 + if (!fuse_allow_current_process(fm->fc)) 423 + return ERR_PTR(-EACCES); 424 + 425 + if (fuse_is_bad(inode)) 426 + return ERR_PTR(-EIO); 427 + 422 428 if (!S_ISREG(inode->i_mode) && !isdir) 423 429 return ERR_PTR(-ENOTTY); 424 430
+44 -1
include/uapi/linux/fuse.h
··· 201 201 * 7.38 202 202 * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry 203 203 * - add FOPEN_PARALLEL_DIRECT_WRITES 204 + * - add total_extlen to fuse_in_header 205 + * - add FUSE_MAX_NR_SECCTX 206 + * - add extension header 207 + * - add FUSE_EXT_GROUPS 208 + * - add FUSE_CREATE_SUPP_GROUP 204 209 */ 205 210 206 211 #ifndef _LINUX_FUSE_H ··· 367 362 * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and 368 363 * mknod 369 364 * FUSE_HAS_INODE_DAX: use per inode DAX 365 + * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, 366 + * symlink and mknod (single group that matches parent) 370 367 */ 371 368 #define FUSE_ASYNC_READ (1 << 0) 372 369 #define FUSE_POSIX_LOCKS (1 << 1) ··· 405 398 /* bits 32..63 get shifted down 32 bits into the flags2 field */ 406 399 #define FUSE_SECURITY_CTX (1ULL << 32) 407 400 #define FUSE_HAS_INODE_DAX (1ULL << 33) 401 + #define FUSE_CREATE_SUPP_GROUP (1ULL << 34) 408 402 409 403 /** 410 404 * CUSE INIT request/reply flags ··· 510 502 * FUSE_EXPIRE_ONLY 511 503 */ 512 504 #define FUSE_EXPIRE_ONLY (1 << 0) 505 + 506 + /** 507 + * extension type 508 + * FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx 509 + * FUSE_EXT_GROUPS: &fuse_supp_groups extension 510 + */ 511 + enum fuse_ext_type { 512 + /* Types 0..31 are reserved for fuse_secctx_header */ 513 + FUSE_MAX_NR_SECCTX = 31, 514 + FUSE_EXT_GROUPS = 32, 515 + }; 513 516 514 517 enum fuse_opcode { 515 518 FUSE_LOOKUP = 1, ··· 905 886 uint32_t uid; 906 887 uint32_t gid; 907 888 uint32_t pid; 908 - uint32_t padding; 889 + uint16_t total_extlen; /* length of extensions in 8byte units */ 890 + uint16_t padding; 909 891 }; 910 892 911 893 struct fuse_out_header { ··· 1065 1045 struct fuse_secctx_header { 1066 1046 uint32_t size; 1067 1047 uint32_t nr_secctx; 1048 + }; 1049 + 1050 + /** 1051 + * struct fuse_ext_header - extension header 1052 + * @size: total size of this extension including this header 1053 + * @type: type of extension 1054 + * 1055 + * This is made compatible with fuse_secctx_header by using type values > 1056 + * FUSE_MAX_NR_SECCTX 1057 + */ 1058 + struct fuse_ext_header { 1059 + uint32_t size; 1060 + uint32_t type; 1061 + }; 1062 + 1063 + /** 1064 + * struct fuse_supp_groups - Supplementary group extension 1065 + * @nr_groups: number of supplementary groups 1066 + * @groups: flexible array of group IDs 1067 + */ 1068 + struct fuse_supp_groups { 1069 + uint32_t nr_groups; 1070 + uint32_t groups[]; 1068 1071 }; 1069 1072 1070 1073 #endif /* _LINUX_FUSE_H */