Linux kernel -stable discussions
 help / color / mirror / Atom feed
From: Greg KH <greg@kroah.com>
To: Sasha Levin <sashal@kernel.org>
Cc: stable@vger.kernel.org, Miklos Szeredi <mszeredi@redhat.com>
Subject: Re: [PATCH 6.18.y 1/4] fuse: abort related layering cleanup
Date: Wed, 9 Sep 2026 14:33:20 +0200	[thread overview]
Message-ID: <2026090913-courier-static-e571@gregkh> (raw)
In-Reply-To: <20260831164256.270090-1-sashal@kernel.org>

On Mon, Aug 31, 2026 at 12:42:53PM -0400, Sasha Levin wrote:
> From: Miklos Szeredi <mszeredi@redhat.com>
> 
> [ Upstream commit 4eeb5e6cb0fd89b343fcf755ae3aad76fdb5b2c2 ]
> 
>  - rename fuse_abort_conn() to fuse_chan_abort(), pass fuse_chan pointer
>    instead of fuse_conn
> 
>  - pass an abort_with_err argument that tells fuse_dev_(read|write) to
>    return with ECONNABORTED instead of ENODEV
> 
>  - move fc->aborted to fch->abort_with_err
> 
>  - rename fuse_wait_aborted() to fuse_chan_wait_aborted()
> 
> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
> 
> [ 6.18 has no "struct fuse_chan" -- the connection object still plays
>   that role, and the surrounding series that splits it out is not in
>   stable.  Adapted as follows:
> 
>   - the renames (fuse_abort_conn() -> fuse_chan_abort(),
>     fuse_wait_aborted() -> fuse_chan_wait_aborted(), the "abort_conn"
>     label in fuse_check_timeout() -> "chan_abort") and the new
>     abort_with_err argument are taken as-is, but both helpers keep
>     taking "struct fuse_conn *".
> 
>   - the "move fc->aborted to fch->abort_with_err" bullet is dropped:
>     there is no fuse_chan to move the flag into, so fc->aborted stays
>     in struct fuse_conn.  fuse_chan_abort() only ever *sets* it, as
>     control.c did before, rather than assigning the new argument
>     unconditionally the way upstream does: on this tree the flag is
>     write-once and is what makes fuse_dev_do_read() and
>     fuse_uring_cmd() report ECONNABORTED instead of ENODEV, so letting
>     a later abort with abort_with_err=false clear it (umount -f,
>     fuse_conn_destroy(), fuse_dev_release(), the timeout worker) would
>     change what userspace sees after a sysfs abort on an abort_err
>     mount.  Consequently the fuse_dev_i.h and dev_uring.c hunks, which
>     only rename the field access, are dropped as well.
> 
>   - fs/fuse/dev.h and fs/fuse/req_timeout.c do not exist here: the
>     declarations stay in fuse_i.h and fuse_check_timeout() lives in
>     dev.c, so those two hunks were replayed there.
> 
>   - in request_wait_answer() the connection pointer is named "fch",
>     matching the name upstream gives it in 28d733cc3ecad ("fuse: change
>     req->fm to req->chan"), so that the follow-up fix applies here
>     unchanged. ]
> 
> [ sashal: Reduced backport -- upstream 4eeb5e6cb0fd8 touches 9 file(s), this
>   backport carries 5. Not backported here:
>   fs/fuse/dev.h
>   fs/fuse/dev_uring.c
>   fs/fuse/fuse_dev_i.h
>   fs/fuse/req_timeout.c
>   This note is generated from the file lists only; see the resolution record
>   for the reasoning. ]
> 
> Stable-dep-of: 64b0b5cacbd2 ("fuse: wait for FR_FINISHED on abort_on_kill to prevent use-after-free")
> Signed-off-by: Sasha Levin <sashal@kernel.org>
> ---
>  fs/fuse/control.c |  4 +---
>  fs/fuse/cuse.c    |  4 ++--
>  fs/fuse/dev.c     | 35 +++++++++++++++++++----------------
>  fs/fuse/fuse_i.h  |  4 ++--
>  fs/fuse/inode.c   |  6 +++---
>  5 files changed, 27 insertions(+), 26 deletions(-)
> 
> diff --git a/fs/fuse/control.c b/fs/fuse/control.c
> index 2e300f6d646c3..5536d6ee65514 100644
> --- a/fs/fuse/control.c
> +++ b/fs/fuse/control.c
> @@ -37,9 +37,7 @@ static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf,
>  {
>  	struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
>  	if (fc) {
> -		if (fc->abort_err)
> -			fc->aborted = true;
> -		fuse_abort_conn(fc);
> +		fuse_chan_abort(fc, fc->abort_err);
>  		fuse_conn_put(fc);
>  	}
>  	return count;
> diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
> index 2bb98bf81b079..d90f138321fe9 100644
> --- a/fs/fuse/cuse.c
> +++ b/fs/fuse/cuse.c
> @@ -425,7 +425,7 @@ static void cuse_process_init_reply(struct fuse_mount *fm,
>  err_region:
>  	unregister_chrdev_region(devt, 1);
>  err:
> -	fuse_abort_conn(fc);
> +	fuse_chan_abort(fc, false);
>  	goto out;
>  }
>  
> @@ -593,7 +593,7 @@ static ssize_t cuse_class_abort_store(struct device *dev,
>  {
>  	struct cuse_conn *cc = dev_get_drvdata(dev);
>  
> -	fuse_abort_conn(&cc->fc);
> +	fuse_chan_abort(&cc->fc, false);
>  	return count;
>  }
>  static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
> diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
> index 77c3982bca3d7..934f9ac5056ed 100644
> --- a/fs/fuse/dev.c
> +++ b/fs/fuse/dev.c
> @@ -87,13 +87,13 @@ void fuse_check_timeout(struct work_struct *work)
>  	expired = fuse_request_expired(fc, &fiq->pending);
>  	spin_unlock(&fiq->lock);
>  	if (expired)
> -		goto abort_conn;
> +		goto chan_abort;
>  
>  	spin_lock(&fc->bg_lock);
>  	expired = fuse_request_expired(fc, &fc->bg_queue);
>  	spin_unlock(&fc->bg_lock);
>  	if (expired)
> -		goto abort_conn;
> +		goto chan_abort;
>  
>  	spin_lock(&fc->lock);
>  	if (!fc->connected) {
> @@ -107,7 +107,7 @@ void fuse_check_timeout(struct work_struct *work)
>  		    fuse_fpq_processing_expired(fc, fpq->processing)) {
>  			spin_unlock(&fpq->lock);
>  			spin_unlock(&fc->lock);
> -			goto abort_conn;
> +			goto chan_abort;
>  		}
>  
>  		spin_unlock(&fpq->lock);
> @@ -115,15 +115,15 @@ void fuse_check_timeout(struct work_struct *work)
>  	spin_unlock(&fc->lock);
>  
>  	if (fuse_uring_request_expired(fc))
> -	    goto abort_conn;
> +	    goto chan_abort;
>  
>  out:
>  	queue_delayed_work(system_percpu_wq, &fc->timeout.work,
>  			   fuse_timeout_timer_freq);
>  	return;
>  
> -abort_conn:
> -	fuse_abort_conn(fc);
> +chan_abort:
> +	fuse_chan_abort(fc, false);
>  }
>  
>  static void fuse_request_init(struct fuse_mount *fm, struct fuse_req *req)
> @@ -180,7 +180,7 @@ static void fuse_drop_waiting(struct fuse_conn *fc)
>  {
>  	/*
>  	 * lockess check of fc->connected is okay, because atomic_dec_and_test()
> -	 * provides a memory barrier matched with the one in fuse_wait_aborted()
> +	 * provides a memory barrier matched with the one in fuse_chan_wait_aborted()
>  	 * to ensure no wake-up is missed.
>  	 */
>  	if (atomic_dec_and_test(&fc->num_waiting) &&
> @@ -551,11 +551,11 @@ bool fuse_remove_pending_req(struct fuse_req *req, spinlock_t *lock)
>  
>  static void request_wait_answer(struct fuse_req *req)
>  {
> -	struct fuse_conn *fc = req->fm->fc;
> -	struct fuse_iqueue *fiq = &fc->iq;
> +	struct fuse_conn *fch = req->fm->fc;
> +	struct fuse_iqueue *fiq = &fch->iq;
>  	int err;
>  
> -	if (!fc->no_interrupt) {
> +	if (!fch->no_interrupt) {
>  		/* Any signal may interrupt this */
>  		err = wait_event_interruptible(req->waitq,
>  					test_bit(FR_FINISHED, &req->flags));
> @@ -579,7 +579,7 @@ static void request_wait_answer(struct fuse_req *req)
>  			return;
>  
>  		if (req->args->abort_on_kill) {
> -			fuse_abort_conn(fc);
> +			fuse_chan_abort(fch, false);
>  			return;
>  		}
>  
> @@ -1491,7 +1491,7 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
>  	spin_lock(&fpq->lock);
>  	/*
>  	 *  Must not put request on fpq->io queue after having been shut down by
> -	 *  fuse_abort_conn()
> +	 *  fuse_chan_abort()
>  	 */
>  	if (!fpq->connected) {
>  		req->out.h.error = err = -ECONNABORTED;
> @@ -2475,10 +2475,13 @@ static void end_polls(struct fuse_conn *fc)
>   * is OK, the request will in that case be removed from the list before we touch
>   * it.
>   */
> -void fuse_abort_conn(struct fuse_conn *fc)
> +void fuse_chan_abort(struct fuse_conn *fc, bool abort_with_err)
>  {
>  	struct fuse_iqueue *fiq = &fc->iq;
>  
> +	if (abort_with_err)
> +		fc->aborted = true;
> +
>  	spin_lock(&fc->lock);
>  	if (fc->connected) {
>  		struct fuse_dev *fud;
> @@ -2547,9 +2550,9 @@ void fuse_abort_conn(struct fuse_conn *fc)
>  		spin_unlock(&fc->lock);
>  	}
>  }
> -EXPORT_SYMBOL_GPL(fuse_abort_conn);
> +EXPORT_SYMBOL_GPL(fuse_chan_abort);
>  
> -void fuse_wait_aborted(struct fuse_conn *fc)
> +void fuse_chan_wait_aborted(struct fuse_conn *fc)
>  {
>  	/* matches implicit memory barrier in fuse_drop_waiting() */
>  	smp_mb();
> @@ -2579,7 +2582,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
>  		/* Are we the last open device? */
>  		if (atomic_dec_and_test(&fc->dev_count)) {
>  			WARN_ON(fc->iq.fasync != NULL);
> -			fuse_abort_conn(fc);
> +			fuse_chan_abort(fc, false);
>  		}
>  		fuse_dev_free(fud);
>  	}
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index c288f28f6c6ea..8b745045f1ab3 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -1272,8 +1272,8 @@ void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req);
>  void fuse_request_end(struct fuse_req *req);
>  
>  /* Abort all requests */
> -void fuse_abort_conn(struct fuse_conn *fc);
> -void fuse_wait_aborted(struct fuse_conn *fc);
> +void fuse_chan_abort(struct fuse_conn *fc, bool abort_with_err);
> +void fuse_chan_wait_aborted(struct fuse_conn *fc);
>  
>  /* Check if any requests timed out */
>  void fuse_check_timeout(struct work_struct *work);
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index e9ed693fc7b37..399298816dea0 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -621,7 +621,7 @@ static void fuse_umount_begin(struct super_block *sb)
>  	if (fc->no_force_umount)
>  		return;
>  
> -	fuse_abort_conn(fc);
> +	fuse_chan_abort(fc, false);
>  
>  	// Only retire block-device-based superblocks.
>  	if (sb->s_bdev != NULL)
> @@ -2099,8 +2099,8 @@ void fuse_conn_destroy(struct fuse_mount *fm)
>  	if (fc->destroy)
>  		fuse_send_destroy(fm);
>  
> -	fuse_abort_conn(fc);
> -	fuse_wait_aborted(fc);
> +	fuse_chan_abort(fc, false);
> +	fuse_chan_wait_aborted(fc);
>  
>  	if (!list_empty(&fc->entry)) {
>  		mutex_lock(&fuse_mutex);
> -- 
> 2.53.0
> 
> 

Series did not apply :(

      parent reply	other threads:[~2026-09-09 12:34 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 12:23 FAILED: patch "[PATCH] fuse: wait for FR_FINISHED on abort_on_kill to prevent" failed to apply to 6.18-stable tree gregkh
2026-08-31 16:42 ` [PATCH 6.18.y 1/4] fuse: abort related layering cleanup Sasha Levin
2026-08-31 16:42   ` [PATCH 6.18.y 2/4] fuse: split off fuse_args and related definitions into a separate header Sasha Levin
2026-08-31 16:42   ` [PATCH 6.18.y 3/4] fuse: remove fm arg of args->end callback Sasha Levin
2026-08-31 16:42   ` [PATCH 6.18.y 4/4] fuse: wait for FR_FINISHED on abort_on_kill to prevent use-after-free Sasha Levin
2026-09-09 12:33   ` Greg KH [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2026090913-courier-static-e571@gregkh \
    --to=greg@kroah.com \
    --cc=mszeredi@redhat.com \
    --cc=sashal@kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox