--- example/passthrough_ll.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) --- a/example/passthrough_ll.c +++ b/example/passthrough_ll.c @@ -56,6 +56,7 @@ #include #include #include +#include /* We are re-using pointers to our `struct lo_inode` and `struct lo_dirp` elements as inodes. This means that we must be able to @@ -965,6 +966,11 @@ static void lo_write_buf(fuse_req_t req, (void) ino; ssize_t res; struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf)); + struct __user_cap_header_struct cap_hdr = { + .version = _LINUX_CAPABILITY_VERSION_1, + }; + struct __user_cap_data_struct cap_orig; + struct __user_cap_data_struct cap_new; out_buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; out_buf.buf[0].fd = fi->fh; @@ -974,7 +980,28 @@ static void lo_write_buf(fuse_req_t req, fprintf(stderr, "lo_write(ino=%" PRIu64 ", size=%zd, off=%lu)\n", ino, out_buf.buf[0].size, (unsigned long) off); + if (fi->write_kill_priv) { + res = capget(&cap_hdr, &cap_orig); + if (res == -1) { + fuse_reply_err(req, errno); + return; + } + cap_new = cap_orig; + cap_new.effective &= ~(1 << CAP_FSETID); + res = capset(&cap_hdr, &cap_new); + if (res == -1) { + fuse_reply_err(req, errno); + return; + } + } + res = fuse_buf_copy(&out_buf, in_buf, 0); + + if (fi->write_kill_priv) { + if (capset(&cap_hdr, &cap_orig) != 0) + abort(); + } + if(res < 0) fuse_reply_err(req, -res); else @@ -1215,7 +1242,7 @@ static void lo_copy_file_range(fuse_req_ res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len, flags); if (res < 0) - fuse_reply_err(req, -errno); + fuse_reply_err(req, errno); else fuse_reply_write(req, res); }