With FUSE_HANDLE_KILLPRIV_V2 support, server will need to kill suid/sgid/ security.capability on open(O_TRUNC), if server supports FUSE_ATOMIC_O_TRUNC. But server needs to kill suid/sgid only if caller does not have CAP_FSETID. Given server does not have this information, client needs to send this info to server. So add a flag FUSE_OPEN_KILL_SUIDGID to fuse_open_in request which tells server to kill suid/sgid (only if group execute is set). This flag is added to the FUSE_OPEN request, as well as the FUSE_CREATE request if the create was non-exclusive, since that might result in an existing file being opened/truncated.
Unified · Split
| @@ -541,6 +541,12 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, · 540 unmodified lines | |||
| 541 | inarg.flags = flags; | 541 | inarg.flags = flags; |
| 542 | inarg.mode = mode; | 542 | inarg.mode = mode; |
| 543 | inarg.umask = current_umask(); | 543 | inarg.umask = current_umask(); |
| 544 | |||
| 545 | if (fm->fc->handle_killpriv_v2 && (flags & O_TRUNC) && | ||
| 546 | !(flags & O_EXCL) && !capable(CAP_FSETID)) { | ||
| 547 | inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID; | ||
| 548 | } | ||
| 549 | |||
| 544 | args.opcode = FUSE_CREATE; | 550 | args.opcode = FUSE_CREATE; |
| 545 | args.nodeid = get_node_id(dir); | 551 | args.nodeid = get_node_id(dir); |
| 546 | args.in_numargs = 2; | 552 | args.in_numargs = 2; |
| @@ -42,6 +42,12 @@ static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, struct file *file, · 41 unmodified lines | |||
| 42 | inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); | 42 | inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY); |
| 43 | if (!fm->fc->atomic_o_trunc) | 43 | if (!fm->fc->atomic_o_trunc) |
| 44 | inarg.flags &= ~O_TRUNC; | 44 | inarg.flags &= ~O_TRUNC; |
| 45 | |||
| 46 | if (fm->fc->handle_killpriv_v2 && | ||
| 47 | (inarg.flags & O_TRUNC) && !capable(CAP_FSETID)) { | ||
| 48 | inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID; | ||
| 49 | } | ||
| 50 | |||
| 45 | args.opcode = opcode; | 51 | args.opcode = opcode; |
| 46 | args.nodeid = nodeid; | 52 | args.nodeid = nodeid; |
| 47 | args.in_numargs = 1; | 53 | args.in_numargs = 1; |
| @@ -178,6 +178,7 @@ · 177 unmodified lines | |||
| 178 | * | 178 | * |
| 179 | * 7.33 | 179 | * 7.33 |
| 180 | * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID | 180 | * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID |
| 181 | * - add FUSE_OPEN_KILL_SUIDGID | ||
| 181 | */ | 182 | */ |
| 182 | 183 | ||
| 183 | #ifndef _LINUX_FUSE_H | 184 | #ifndef _LINUX_FUSE_H |
| @@ -444,6 +445,12 @@ struct fuse_file_lock { · 260 unmodified lines | |||
| 444 | */ | 445 | */ |
| 445 | #define FUSE_ATTR_SUBMOUNT (1 << 0) | 446 | #define FUSE_ATTR_SUBMOUNT (1 << 0) |
| 446 | 447 | ||
| 448 | /** | ||
| 449 | * Open flags | ||
| 450 | * FUSE_OPEN_KILL_SUIDGID: Kill suid and sgid if executable | ||
| 451 | */ | ||
| 452 | #define FUSE_OPEN_KILL_SUIDGID (1 << 0) | ||
| 453 | |||
| 447 | enum fuse_opcode { | 454 | enum fuse_opcode { |
| 448 | FUSE_LOOKUP = 1, | 455 | FUSE_LOOKUP = 1, |
| 449 | FUSE_FORGET = 2, /* no reply */ | 456 | FUSE_FORGET = 2, /* no reply */ |
| @@ -605,14 +612,14 @@ struct fuse_setattr_in { · 155 unmodified lines | |||
| 605 | 612 | ||
| 606 | struct fuse_open_in { | 613 | struct fuse_open_in { |
| 607 | uint32_t flags; | 614 | uint32_t flags; |
| 608 | uint32_t unused; | 615 | uint32_t open_flags; /* FUSE_OPEN_... */ |
| 609 | }; | 616 | }; |
| 610 | 617 | ||
| 611 | struct fuse_create_in { | 618 | struct fuse_create_in { |
| 612 | uint32_t flags; | 619 | uint32_t flags; |
| 613 | uint32_t mode; | 620 | uint32_t mode; |
| 614 | uint32_t umask; | 621 | uint32_t umask; |
| 615 | uint32_t padding; | 622 | uint32_t open_flags; /* FUSE_OPEN_... */ |
| 616 | }; | 623 | }; |
| 617 | 624 | ||
| 618 | struct fuse_open_out { | 625 | struct fuse_open_out { |