From 4930d6c6149f02d94ac9326afa06ccda680dacc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=8F=E7=A7=8B=E5=88=A9=2000335937?= Date: Thu, 9 Mar 2023 15:08:54 +0800 Subject: [PATCH 1/2] ipv6: raw: Deduct extension header length in rawv6_push_pending_frames --- net/ipv6/raw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 410bb97ae394..69827b290118 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -544,6 +544,7 @@ static int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, struct raw6_sock *rp) { + struct ipv6_txoptions *opt; struct sk_buff *skb; int err = 0; int offset; @@ -561,6 +562,9 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, offset = rp->offset; total_len = inet_sk(sk)->cork.base.length; + opt = inet6_sk(sk)->cork.opt; + total_len -= opt ? opt->opt_flen : 0; + if (offset >= total_len - 1) { err = -EINVAL; ip6_flush_pending_frames(sk); -- Gitee From 0e2b9ff77a61af14368d9507d88281ab381e67ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=8F=E7=A7=8B=E5=88=A9=2000335937?= Date: Mon, 22 Jan 2024 18:44:16 +0800 Subject: [PATCH 2/2] fuse: in fuse_flush only wait if someone wants the return code ANBZ: #8005 commit 5a8bee63b10f6f2f52f6d22e109a4a147409842a upstream. If a fuse filesystem is mounted inside a container, there is a problem during pid namespace destruction. The scenario is: 1. task (a thread in the fuse server, with a fuse file open) starts exiting, does exit_signals(), goes into fuse_flush() -> wait 2. fuse daemon gets killed, tries to wake everyone up 3. task from 1 is stuck because complete_signal() doesn't wake it up, since it has PF_EXITING. The result is that the thread will never be woken up, and pid namespace destruction will block indefinitely. To add insult to injury, nobody is waiting for these return codes, since the pid namespace is being destroyed. To fix this, let's not block on flush operations when the current task has PF_EXITING. This does change the semantics slightly: the wait here is for posix locks to be unlocked, so the task will exit before things are unlocked. To quote Miklos: "remote" posix locks are almost never used due to problems like this, so I think it's safe to do this. Signed-off-by: "Eric W. Biederman" Signed-off-by: Tycho Andersen Link: https://lore.kernel.org/all/YrShFXRLtRt6T%2Fj+@risky/ Tested-by: Tycho Andersen Signed-off-by: Miklos Szeredi --- fs/fuse/file.c | 93 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 6244283b01ef..95e8f2fc075e 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -19,6 +19,7 @@ #include #include #include +#include static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file, int opcode, struct fuse_open_out *outargp) @@ -430,49 +431,39 @@ static void fuse_sync_writes(struct inode *inode) fuse_release_nowrite(inode); } -static int fuse_flush(struct file *file, fl_owner_t id) -{ - struct inode *inode = file_inode(file); - struct fuse_conn *fc = get_fuse_conn(inode); - struct fuse_file *ff = file->private_data; - struct fuse_req *req; + +struct fuse_flush_args { + struct fuse_args args; struct fuse_flush_in inarg; - int err; + struct work_struct work; + struct file *file; +}; - if (is_bad_inode(inode)) - return -EIO; +static int fuse_do_flush(struct fuse_flush_args *fa) +{ + int err; + struct inode *inode = file_inode(fa->file); + struct fuse_mount *fm = get_fuse_mount(inode); err = write_inode_now(inode, 1); if (err) - return err; + goto out; inode_lock(inode); fuse_sync_writes(inode); inode_unlock(inode); - err = filemap_check_errors(file->f_mapping); + err = filemap_check_errors(fa->file->f_mapping); if (err) - return err; + goto out; err = 0; - if (fc->no_flush) + if (fm->fc->no_flush) goto inval_attr_out; - req = fuse_get_req_nofail_nopages(fc, file); - memset(&inarg, 0, sizeof(inarg)); - inarg.fh = ff->fh; - inarg.lock_owner = fuse_lock_owner_id(fc, id); - req->in.h.opcode = FUSE_FLUSH; - req->in.h.nodeid = get_node_id(inode); - req->in.numargs = 1; - req->in.args[0].size = sizeof(inarg); - req->in.args[0].value = &inarg; - __set_bit(FR_FORCE, &req->flags); - fuse_request_send(fc, req); - err = req->out.h.error; - fuse_put_request(fc, req); + err = fuse_simple_request(fm, &fa->args); if (err == -ENOSYS) { - fc->no_flush = 1; + fm->fc->no_flush = 1; err = 0; } @@ -481,11 +472,57 @@ static int fuse_flush(struct file *file, fl_owner_t id) * In memory i_blocks is not maintained by fuse, if writeback cache is * enabled, i_blocks from cached attr may not be accurate. */ - if (!err && fc->writeback_cache) + if (!err && fm->fc->writeback_cache) fuse_invalidate_attr(inode); +out: + fput(fa->file); + kfree(fa); return err; } +static void fuse_flush_async(struct work_struct *work) +{ + struct fuse_flush_args *fa = container_of(work, typeof(*fa), work); + + fuse_do_flush(fa); +} + +static int fuse_flush(struct file *file, fl_owner_t id) +{ + struct fuse_flush_args *fa; + struct inode *inode = file_inode(file); + struct fuse_mount *fm = get_fuse_mount(inode); + struct fuse_file *ff = file->private_data; + + if (fuse_is_bad(inode)) + return -EIO; + + fa = kzalloc(sizeof(*fa), GFP_KERNEL); + if (!fa) + return -ENOMEM; + + fa->inarg.fh = ff->fh; + fa->inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); + fa->args.opcode = FUSE_FLUSH; + fa->args.nodeid = get_node_id(inode); + fa->args.in_numargs = 1; + fa->args.in_args[0].size = sizeof(fa->inarg); + fa->args.in_args[0].value = &fa->inarg; + fa->args.force = true; + fa->file = get_file(file); + + /* Don't wait if the task is exiting */ + if (current->flags & PF_EXITING) { + INIT_WORK(&fa->work, fuse_flush_async); + schedule_work(&fa->work); + return 0; + } + + return fuse_do_flush(fa); +} + + + int fuse_fsync_common(struct file *file, loff_t start, loff_t end, int datasync, int isdir) { -- Gitee