Linux Security Modules development
 help / color / mirror / Atom feed
* Re: [PATCH] lsm: move inode IS_PRIVATE checks to individual LSMs
From: Paul Moore @ 2026-02-23 22:21 UTC (permalink / raw)
  To: Casey Schaufler
  Cc: danieldurning.work, linux-security-module, selinux,
	linux-integrity, stephen.smalley.work, jmorris, serge,
	john.johansen, zohar, roberto.sassu, dmitry.kasatkin, mic,
	takedakn, penguin-kernel
In-Reply-To: <9229d70d-aa7a-459f-b005-695e99888783@schaufler-ca.com>

On Fri, Feb 20, 2026 at 4:13 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 2/20/2026 11:54 AM, danieldurning.work@gmail.com wrote:
> > From: Daniel Durning <danieldurning.work@gmail.com>
> >
> > Move responsibility of bypassing S_PRIVATE inodes to the
> > individual LSMs. Originally the LSM framework would skip calling
> > the hooks on any inode that was marked S_PRIVATE. This would
> > prevent the LSMs from controlling access to any inodes marked as
> > such (ie. pidfds). We now perform the same IS_PRIVATE checks
> > within the LSMs instead. This is consistent with the general goal
> > of deferring as much as possible to the individual LSMs.
>
> Um ... ick?
>
> Sure, we generally want the LSMs to be responsible for their own
> decisions, but that doesn't look like the point to me. What appears
> to be the issue is that pidfs isn't using S_PRIVATE in a way that
> conveys the necessary information to the LSMs.

First off, consider this the annual reminder for everyone to *please*
trim their replies when discussing things on-list.  Everything is
archived on lore, we're not losing anything, and it makes things *so*
much easier to read if we don't have to skim over the entire email to
make sure we haven't missed any comments.

Now, back to the S_PRIVATE issue ...

I was the one who first suggested (it may have been on the SELinux
list, or in an off-list discussion, not sure?) that moving the
S_PRIVATE check into the individual LSMs was a way to work around the
issue with pidfd/pidfs, so please don't blame Daniel for this, he has
been doing good work trying to solve a rather ugly problem.

> > This reorganization enables the LSMs to eventually implement
> > checks or labeling for some specific S_PRIVATE inodes like pidfds.
>
> We could consider these or similar changes when that eventuality occurs.

To be clear, that time is now, that is just a dependency of that which
needs to be sorted out first.

> I would strongly suggest that this is a pidfs issue, not an LSM
> infrastructure issue.

I'm not going to argue with that, and perhaps that is a good next
step: send a quick RFC patch to the VFS folks, with the LSM list CC'd,
that drops setting the S_PRIVATE flag to see if they complain too
loudly.  Based on other threads, Christian is aware that we are
starting to look at better/proper handling of pidfds/pidfs so he may
be open to dropping S_PRIVATE since it doesn't really have much impact
outside of the LSM, but who knows; the VFS folks have been growing a
bit more anti-LSM as of late.

diff --git a/fs/pidfs.c b/fs/pidfs.c
index 318253344b5c..4cec73b4cbcf 100644
--- a/fs/pidfs.c
+++ b/fs/pidfs.c
@@ -921,7 +921,7 @@ static int pidfs_init_inode(struct inode *inode, void *data)
       const struct pid *pid = data;

       inode->i_private = data;
-       inode->i_flags |= S_PRIVATE | S_ANON_INODE;
+       inode->i_flags |= S_ANON_INODE;
       /* We allow to set xattrs. */
       inode->i_flags &= ~S_IMMUTABLE;
       inode->i_mode |= S_IRWXU;

-- 
paul-moore.com

^ permalink raw reply related

* Re: [PATCH v2 09/15] ovl: Simplify ovl_lookup_real_one()
From: NeilBrown @ 2026-02-23 22:21 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Chris Mason, Christian Brauner, Alexander Viro, David Howells,
	Jan Kara, Chuck Lever, Jeff Layton, Miklos Szeredi, John Johansen,
	Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
	Darrick J. Wong, linux-kernel, netfs, linux-fsdevel, linux-nfs,
	linux-unionfs, apparmor, linux-security-module, selinux
In-Reply-To: <CAOQ4uxirM8dW9rOw4SvGtfH-s0Eg9LGuFk1aZooMvEDc=2tbyA@mail.gmail.com>

On Tue, 24 Feb 2026, Amir Goldstein wrote:
> On Mon, Feb 23, 2026 at 2:20 PM Chris Mason <clm@meta.com> wrote:
> >
> > NeilBrown <neilb@ownmail.net> wrote:
> > > From: NeilBrown <neil@brown.name>
> > >
> > > The primary purpose of this patch is to remove the locking from
> > > ovl_lookup_real_one() as part of centralising all locking of directories
> > > for name operations.
> > >
> > > The locking here isn't needed.  By performing consistency tests after
> > > the lookup we can be sure that the result of the lookup was valid at
> > > least for a moment, which is all the original code promised.
> > >
> > > lookup_noperm_unlocked() is used for the lookup and it will take the
> > > lock if needed only where it is needed.
> > >
> > > Also:
> > >  - don't take a reference to real->d_parent.  The parent is
> > >    only use for a pointer comparison, and no reference is needed for
> > >    that.
> > >  - Several "if" statements have a "goto" followed by "else" - the
> > >    else isn't needed: the following statement can directly follow
> > >    the "if" as a new statement
> > >  - Use a consistent pattern of setting "err" before performing a test
> > >    and possibly going to "fail".
> > >  - remove the "out" label (now that we don't need to dput(parent) or
> > >    unlock) and simply return from fail:.
> >
> > Hi everyone,
> >
> > Amir asked me to run these through, and this commit was flagged.  I recently
> > changed the prompts to include some vfs knowledge:
> 
> Thanks Chris!
> 
> >
> > https://github.com/masoncl/review-prompts/blob/main/kernel/subsystem/vfs.md
> >
> > And I also put in some words to make it prefer reporting problems that might
> > not be bugs, but that do violate some rule in the .md files.  This might
> > be a false positive from that new shift toward blindly trusting the guides,
> > but I'll let everyone here decide:
> >
> > commit d1bfcef048896cdc9e4c57e3249b6ad344d64c02
> > Author: NeilBrown <neil@brown.name>
> >
> > ovl: Simplify ovl_lookup_real_one()
> >
> > This patch removes locking from ovl_lookup_real_one() and reorganizes the
> > control flow. The function now uses lookup_noperm_unlocked() instead of
> > lookup_noperm() and performs consistency validation after the lookup rather
> > than holding a lock during the operation.
> >
> > > diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
> > > index 83f80fdb15674..b448fc9424b64 100644
> > > --- a/fs/overlayfs/export.c
> > > +++ b/fs/overlayfs/export.c
> > > @@ -349,69 +349,64 @@ static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
> > >       return NULL;
> > >  }
> > >
> > > -/*
> > > - * Lookup a child overlay dentry to get a connected overlay dentry whose real
> > > - * dentry is @real. If @real is on upper layer, we lookup a child overlay
> > > - * dentry with the same name as the real dentry. Otherwise, we need to consult
> > > - * index for lookup.
> > > +/**
> > > + * ovl_lookup_real_one -  Lookup a child overlay dentry to get an overlay dentry whose real dentry is given
> > > + * @connected: parent overlay dentry
> > > + * @real: given child real dentry
> > > + * @layer: layer in which @real exists
> > > + *
> > > + *
> > > + * Lookup a child overlay dentry in @connected with the same name as the @real
> > > + * dentry.  Then check that the parent of the result is the real dentry for
> > > + * @connected, and @real is the real dentry for the result.
> > > + *
> > > + * Returns:
> > > + *   %-ECHILD if the parent of @real is no longer the real dentry for @connected.
> > > + *   %-ESTALE if @real is no the real dentry of the found dentry.
> >                                        ^^
> > There's a typo here: "is no the" should be "is not the".
> >
> > > + *   Otherwise the found dentry is returned.
> > >   */
> > >  static struct dentry *ovl_lookup_real_one(struct dentry *connected,
> > >                                         struct dentry *real,
> > >                                         const struct ovl_layer *layer)
> > >  {
> > > -     struct inode *dir = d_inode(connected);
> > > -     struct dentry *this, *parent = NULL;
> > > +     struct dentry *this;
> > >       struct name_snapshot name;
> > >       int err;
> > >
> > >       /*
> > > -      * Lookup child overlay dentry by real name. The dir mutex protects us
> > > -      * from racing with overlay rename. If the overlay dentry that is above
> > > -      * real has already been moved to a parent that is not under the
> > > -      * connected overlay dir, we return -ECHILD and restart the lookup of
> > > -      * connected real path from the top.
> > > -      */
> > > -     inode_lock_nested(dir, I_MUTEX_PARENT);
> > > -     err = -ECHILD;
> > > -     parent = dget_parent(real);
> > > -     if (ovl_dentry_real_at(connected, layer->idx) != parent)
> > > -             goto fail;
> > > -
> > > -     /*
> > > -      * We also need to take a snapshot of real dentry name to protect us
> > > +      * We need to take a snapshot of real dentry name to protect us
> > >        * from racing with underlying layer rename. In this case, we don't
> > >        * care about returning ESTALE, only from dereferencing a free name
> > >        * pointer because we hold no lock on the real dentry.
> > >        */
> > >       take_dentry_name_snapshot(&name, real);
> > > -     /*
> > > -      * No idmap handling here: it's an internal lookup.
> > > -      */
> > > -     this = lookup_noperm(&name.name, connected);
> > > +     this = lookup_noperm_unlocked(&name.name, connected);
> > >       release_dentry_name_snapshot(&name);
> > > +
> > > +     err = -ECHILD;
> > > +     if (ovl_dentry_real_at(connected, layer->idx) != real->d_parent)
> > > +             goto fail;
> > > +
> >
> > A subsystem pattern flags this as potentially concerning: the VFS subsystem
> > guide indicates that TOCTOU validation checking d_parent should also check
> > d_unhashed() because a dentry can be unhashed (removed from dcache by
> > concurrent operations) while its d_parent pointer remains unchanged.
> >
> > The old code held inode_lock_nested(dir, I_MUTEX_PARENT) during the entire
> > lookup and validation, which serialized with operations that could unhash the
> > dentry. The new lockless pattern creates a window where:
> >
> > 1. lookup_noperm_unlocked() completes and returns dentry `this`
> > 2. A concurrent unlink/remove operation unhashes `this`
> > 3. The d_parent validation passes (parent pointer unchanged)
> > 4. The function returns an unhashed dentry
> >
> > Other overlayfs code uses the complete pattern. For example, in
> > ovl_lock_rename_workdir() at fs/overlayfs/util.c:
> >
> >     if (work->d_parent != workdir || d_unhashed(work)) {
> >         ...
> >     }
> >
> > Could this validation miss a race where the dentry is unhashed but d_parent
> > still matches? The subsequent checks (!this->d_inode for -ENOENT,
> > wrong real dentry for -ESTALE) might catch some cases, but is that
> > sufficient for all the scenarios where an unhashed dentry could cause
> > problems?
> >
> 
> It's a very good comment and very important rule to check, since
> we have at least 3 fix commits on breaking this rule, but as this
> code is utterly confusing to most human I do not blame LLM for getting
> confused here.
> 
> The lock not taken on 'dir' which is the overlayfs inode and the checked
> 'real' dentry is on the underlying fs.
> 
> Therefore, the check of real->d_parent was not protected in old code as
> well as in new code - it is a mere best effort sanity check, so I think
> there is no added risk here.
> 
> Neil, do you agree?

Yes, I agree.

The relevant part of Chris' prompt is:

 When a dentry reference is obtained without holding the parent inode
 lock (e.g., via lookup, creation, or cached reference), and the lock is
 acquired later, a TOCTOU window exists 

"the lock is acquired later" is significant.  In this code the lock
hasn't been acquired so the rule doesn't apply.

In this code I don't think we are testing real->d_parent, we are testing
ovl_dentry_real_at(connected, layer->idx) and making sure it is
consistent.
It is true that "real" might have been renamed and that would cause a
failure too, but that isn't really interesting.  It could be renamed
just after the test just as easily (as we don't hold any locks).
In general overlayfs doesn't try to handle independent changes in the
underlying filesystems beyond "don't crash".

So it was a good comment to get, but I don't think there is any need to
change the code (though I have fixed the typo).

Thanks,
NeilBrown


> 
> Thanks,
> Amir.
> 


^ permalink raw reply

* Re: [PATCH v2 12/15] ovl: change ovl_create_real() to get a new lock when re-opening created file.
From: NeilBrown @ 2026-02-23 22:30 UTC (permalink / raw)
  To: Chris Mason
  Cc: Christian Brauner, Alexander Viro, David Howells, Jan Kara,
	Chuck Lever, Jeff Layton, Miklos Szeredi, Amir Goldstein,
	John Johansen, Paul Moore, James Morris, Serge E. Hallyn,
	Stephen Smalley, Darrick J. Wong, linux-kernel, netfs,
	linux-fsdevel, linux-nfs, linux-unionfs, apparmor,
	linux-security-module, selinux
In-Reply-To: <20260223132424.105125-1-clm@meta.com>

On Tue, 24 Feb 2026, Chris Mason wrote:
> NeilBrown <neilb@ownmail.net> wrote:
> > From: NeilBrown <neil@brown.name>
> > 
> > When ovl_create_real() is used to create a file on the upper filesystem
> > it needs to return the resulting dentry - positive and hashed.
> > It is usually the case the that dentry passed to the create function
> > (e.g.  vfs_create()) will be suitable but this is not guaranteed.  The
> > filesystem may unhash that dentry forcing a repeat lookup next time the
> > name is wanted.
> > 
> 
> Hi everyone,
> 
> Amir suggested I run these through, and this commit was flagged:
> 
> commit 62d49d1e44667e4f93bec415faabec5526992ac0
> Author: NeilBrown <neil@brown.name>
> 
> ovl: change ovl_create_real() to get a new lock when re-opening created file.
> 
> This commit changes ovl_create_real() to drop the directory lock and
> reacquire a new lock for lookup when the created dentry is unhashed. It
> also removes ovl_lookup_upper() which is no longer used.
> 
> Signed-off-by: NeilBrown <neil@brown.name>
> 
> > diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> > index c4feb89ad1e39..6285069ccc590 100644
> > --- a/fs/overlayfs/dir.c
> > +++ b/fs/overlayfs/dir.c
> > @@ -159,7 +159,8 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct dentry *dir,
> >  }
> >
> >  struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent,
> > -			       struct dentry *newdentry, struct ovl_cattr *attr)
> > +			       struct dentry *newdentry, struct qstr *qname,
> > +			       struct ovl_cattr *attr)
> >  {
> >  	struct inode *dir = parent->d_inode;
> >  	int err;
> > @@ -221,19 +222,29 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent,
> >  		struct dentry *d;
> >  		/*
> >  		 * Some filesystems (i.e. casefolded) may return an unhashed
> > -		 * negative dentry from the ovl_lookup_upper() call before
> > +		 * negative dentry from the ovl_start_creating_upper() call before
> >  		 * ovl_create_real().
> >  		 * In that case, lookup again after making the newdentry
> >  		 * positive, so ovl_create_upper() always returns a hashed
> > -		 * positive dentry.
> > +		 * positive dentry.  We lookup using qname which should be
> > +		 * the same name as newentry, but is certain not to change.
> > +		 * As we have to drop the lock before the lookup a race
> > +		 * could result in a lookup failure.  In that case we return
> > +		 * an error.
> >  		 */
> > -		d = ovl_lookup_upper(ofs, newdentry->d_name.name, parent,
> > -				     newdentry->d_name.len);
> > -		dput(newdentry);
> > -		if (IS_ERR_OR_NULL(d))
> > +		end_creating_keep(newdentry);
> > +		d = ovl_start_creating_upper(ofs, parent, qname);
> > +
> > +		if (IS_ERR_OR_NULL(d)) {
> >  			err = d ? PTR_ERR(d) : -ENOENT;
> > +		} else if (d->d_inode != newdentry->d_inode) {
> > +			err = -EIO;
> > +			dput(newdentry);
> > +		} else {
> > +			dput(newdentry);
> >  			return d;
> > +		}
> > +		return ERR_PTR(err);
> >  	}
> 
> Does this leak the newdentry reference when IS_ERR_OR_NULL(d) is true?
> 
> The code now calls end_creating_keep(newdentry) which keeps the reference,
> then calls ovl_start_creating_upper(). If that returns an error or NULL,
> the function returns ERR_PTR(err) without cleaning up newdentry:
> 
> 	end_creating_keep(newdentry);
> 	d = ovl_start_creating_upper(ofs, parent, qname);
> 
> 	if (IS_ERR_OR_NULL(d)) {
> 		err = d ? PTR_ERR(d) : -ENOENT;
> 	} ...
> 	return ERR_PTR(err);
> 
> The old code always went through the 'out:' label which called
> end_creating(newdentry) on error. The new code bypasses that cleanup.
> 
> 
> Does this leak both the parent lock and the dentry 'd' when the lookup
> returns a different inode?
> 
> When d->d_inode != newdentry->d_inode, the code sets err = -EIO and calls
> dput(newdentry), but doesn't clean up 'd':
> 
> 	} else if (d->d_inode != newdentry->d_inode) {
> 		err = -EIO;
> 		dput(newdentry);
> 	} ...
> 	return ERR_PTR(err);
> 
> The dentry 'd' was returned by ovl_start_creating_upper() with the parent
> directory lock held. The code needs to call end_creating(d) to release the
> lock via end_dirop()->inode_unlock() and release the dentry reference via
> end_dirop()->dput().
> 
> 

Yes, that code is rather messed up - thanks.

I've made it:

		end_creating_keep(newdentry);
		d = ovl_start_creating_upper(ofs, parent, qname);

		if (IS_ERR_OR_NULL(d)) {
			err = d ? PTR_ERR(d) : -ENOENT;
		} else if (d->d_inode != newdentry->d_inode) {
			err = -EIO;
		} else {
			dput(newdentry);
			return d;
		}
		end_creating(d);
		dput(newdentry);
		return ERR_PTR(err);

Thanks,
NeilBrown

^ permalink raw reply

* Re: [syzbot] [kernel?] INFO: task hung in restrict_one_thread_callback
From: syzbot @ 2026-02-24  3:03 UTC (permalink / raw)
  To: dingyihan
  Cc: dingyihan, gnoack3000, gnoack, jannh, linux-security-module, mic,
	paul, linux-kernel, syzkaller-bugs
In-Reply-To: <D0013EA515055145+3e08a07b-e384-4c08-ab17-f558f0130d30@uniontech.com>

> Hi Günther,
>
> Thank you for the detailed analysis! I completely agree that serializing the TSYNC 
> operations is the right way to prevent this deadlock. I have drafted a patch using 
> `exec_update_lock` (similar to how seccomp uses `cred_guard_mutex`).
>
> Regarding your proposal to split this into two patches (one for the cleanup 
> path and one for the lock): Maybe combining them into a single patch is a better choice. Here is why:
>
> We actually *cannot* remove `wait_for_completion(&shared_ctx.all_prepared)` 
> in the interrupt recovery path. Since `shared_ctx` is allocated on the local 
> stack of the caller, removing the wait would cause a severe Use-After-Free (UAF) if the 
> thread returns to userspace while sibling task_works are still executing and dereferencing `ctx`. 
>
> By adding the lock, we inherently resolve the deadlock, meaning the sibling task_works 
> will never get stuck. Thus, `wait_for_completion` becomes perfectly safe to keep, 
> and it remains strictly necessary to protect the stack memory. Therefore, the "fix" for the 
> cleanup path is simply updating the comments to reflect this reality, which is tightly coupled with the locking fix. 
> It felt more cohesive as a single patch.
>
> I have test the patch on my laptop,and it will not trigger the issue.Let's have syzbot test this combined logic:
>
> #syz test: 

"---" does not look like a valid git repo address.

>
> --- a/security/landlock/tsync.c
>
> +++ b/security/landlock/tsync.c
>
> @@ -447,6 +447,12 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
>
>         shared_ctx.new_cred = new_cred;
>
>         shared_ctx.set_no_new_privs = task_no_new_privs(current);
>
>  
>
> +       /*
>
> +        * Serialize concurrent TSYNC operations to prevent deadlocks
>
> +        * when multiple threads call landlock_restrict_self() simultaneously.
>
> +        */
>
> +       down_write(&current->signal->exec_update_lock);
>
> +
>
>         /*
>
>          * We schedule a pseudo-signal task_work for each of the calling task's
>
>          * sibling threads.  In the task work, each thread:
>
> @@ -527,14 +533,17 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
>
>                                            -ERESTARTNOINTR);
>
>  
>
>                                 /*
>
> -                                * Cancel task works for tasks that did not start running yet,
>
> -                                * and decrement all_prepared and num_unfinished accordingly.
>
> +                                * Opportunistic improvement: try to cancel task works
>
> +                                * for tasks that did not start running yet. We do not
>
> +                                * have a guarantee that it cancels any of the enqueued
>
> +                                * task works (because task_work_run() might already have
>
> +                                * dequeued them).
>
>                                  */
>
>                                 cancel_tsync_works(&works, &shared_ctx);
>
>  
>
>                                 /*
>
> -                                * The remaining task works have started running, so waiting for
>
> -                                * their completion will finish.
>
> +                                * We must wait for the remaining task works to finish to
>
> +                                * prevent a use-after-free of the local shared_ctx.
>
>                                  */
>
>                                 wait_for_completion(&shared_ctx.all_prepared);
>
>                         }
>
> @@ -557,5 +566,7 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
>
>  
>
>         tsync_works_release(&works);
>
>  
>
> +       up_write(&current->signal->exec_update_lock);
>
> +
>
>         return atomic_read(&shared_ctx.preparation_error);
>
>  }
>
> --
> 在 2026/2/23 23:16, Günther Noack 写道:
>> Hello!
>> 
>> On Mon, Feb 23, 2026 at 07:29:56PM +0800, Ding Yihan wrote:
>>> Thank you for the detailed analysis and the clear breakdown. 
>>> Apologies for the delayed response. I spent the last couple of days
>>> thoroughly reading through the previous mailing list discussions. I
>>> was trying hard to see if there was any viable pure lockless design
>>> that could solve this concurrency issue while preserving the original
>>> architecture. 
>>> 
>>> However, after looking at the complexities you outlined, I completely
>>> agree with your conclusion: serializing the TSYNC operations is indeed
>>> the most robust and reasonable path forward to prevent the deadlock.
>>> 
>>> Regarding the lock choice, since 'cred_guard_mutex' is explicitly
>>> marked as deprecated for new code in the kernel,maybe we can use its
>>> modern replacement: 'exec_update_lock' (using down_write_trylock /
>>> up_write on current->signal). This aligns with the current subsystem
>>> standards and was also briefly touched upon by Jann in the older
>>> discussions.
>>> 
>>> I fully understand the requirement for the two-part patch series:
>>> 1. Cleaning up the cancellation logic and comments.
>>> 2. Introducing the serialization lock for TSYNC.
>>> 
>>> I will take some time to draft and test this patch series properly. 
>>> I also plan to discuss this with my kernel colleagues here at 
>>> UnionTech to see if they have any additional suggestions on the 
>>> implementation details before I submit it.
>>> 
>>> I will send out the v1 patch series to the list as soon as it is
>>> ready. Thanks again for your guidance and the great discussion!
>> 
>> Thank you, Ding, this is much appreciated!
>> 
>> I agree, the `exec_update_lock` might be the better solution;
>> I also need to familiarize myself more with it to double-check.
>> 
>> —Günther
>> 
>

^ permalink raw reply

* Re: [syzbot] [kernel?] INFO: task hung in restrict_one_thread_callback
From: Ding Yihan @ 2026-02-24  3:02 UTC (permalink / raw)
  To: Günther Noack
  Cc: Günther Noack, syzbot, Mickaël Salaün,
	linux-security-module, Jann Horn, Paul Moore
In-Reply-To: <aZxvXARvYf6aQBUv@google.com>

Hi Günther,

Thank you for the detailed analysis! I completely agree that serializing the TSYNC 
operations is the right way to prevent this deadlock. I have drafted a patch using 
`exec_update_lock` (similar to how seccomp uses `cred_guard_mutex`).

Regarding your proposal to split this into two patches (one for the cleanup 
path and one for the lock): Maybe combining them into a single patch is a better choice. Here is why:

We actually *cannot* remove `wait_for_completion(&shared_ctx.all_prepared)` 
in the interrupt recovery path. Since `shared_ctx` is allocated on the local 
stack of the caller, removing the wait would cause a severe Use-After-Free (UAF) if the 
thread returns to userspace while sibling task_works are still executing and dereferencing `ctx`. 

By adding the lock, we inherently resolve the deadlock, meaning the sibling task_works 
will never get stuck. Thus, `wait_for_completion` becomes perfectly safe to keep, 
and it remains strictly necessary to protect the stack memory. Therefore, the "fix" for the 
cleanup path is simply updating the comments to reflect this reality, which is tightly coupled with the locking fix. 
It felt more cohesive as a single patch.

I have test the patch on my laptop,and it will not trigger the issue.Let's have syzbot test this combined logic:

#syz test: 

--- a/security/landlock/tsync.c

+++ b/security/landlock/tsync.c

@@ -447,6 +447,12 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,

        shared_ctx.new_cred = new_cred;

        shared_ctx.set_no_new_privs = task_no_new_privs(current);

 

+       /*

+        * Serialize concurrent TSYNC operations to prevent deadlocks

+        * when multiple threads call landlock_restrict_self() simultaneously.

+        */

+       down_write(&current->signal->exec_update_lock);

+

        /*

         * We schedule a pseudo-signal task_work for each of the calling task's

         * sibling threads.  In the task work, each thread:

@@ -527,14 +533,17 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,

                                           -ERESTARTNOINTR);

 

                                /*

-                                * Cancel task works for tasks that did not start running yet,

-                                * and decrement all_prepared and num_unfinished accordingly.

+                                * Opportunistic improvement: try to cancel task works

+                                * for tasks that did not start running yet. We do not

+                                * have a guarantee that it cancels any of the enqueued

+                                * task works (because task_work_run() might already have

+                                * dequeued them).

                                 */

                                cancel_tsync_works(&works, &shared_ctx);

 

                                /*

-                                * The remaining task works have started running, so waiting for

-                                * their completion will finish.

+                                * We must wait for the remaining task works to finish to

+                                * prevent a use-after-free of the local shared_ctx.

                                 */

                                wait_for_completion(&shared_ctx.all_prepared);

                        }

@@ -557,5 +566,7 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,

 

        tsync_works_release(&works);

 

+       up_write(&current->signal->exec_update_lock);

+

        return atomic_read(&shared_ctx.preparation_error);

 }

--
在 2026/2/23 23:16, Günther Noack 写道:
> Hello!
> 
> On Mon, Feb 23, 2026 at 07:29:56PM +0800, Ding Yihan wrote:
>> Thank you for the detailed analysis and the clear breakdown. 
>> Apologies for the delayed response. I spent the last couple of days
>> thoroughly reading through the previous mailing list discussions. I
>> was trying hard to see if there was any viable pure lockless design
>> that could solve this concurrency issue while preserving the original
>> architecture. 
>> 
>> However, after looking at the complexities you outlined, I completely
>> agree with your conclusion: serializing the TSYNC operations is indeed
>> the most robust and reasonable path forward to prevent the deadlock.
>> 
>> Regarding the lock choice, since 'cred_guard_mutex' is explicitly
>> marked as deprecated for new code in the kernel,maybe we can use its
>> modern replacement: 'exec_update_lock' (using down_write_trylock /
>> up_write on current->signal). This aligns with the current subsystem
>> standards and was also briefly touched upon by Jann in the older
>> discussions.
>> 
>> I fully understand the requirement for the two-part patch series:
>> 1. Cleaning up the cancellation logic and comments.
>> 2. Introducing the serialization lock for TSYNC.
>> 
>> I will take some time to draft and test this patch series properly. 
>> I also plan to discuss this with my kernel colleagues here at 
>> UnionTech to see if they have any additional suggestions on the 
>> implementation details before I submit it.
>> 
>> I will send out the v1 patch series to the list as soon as it is
>> ready. Thanks again for your guidance and the great discussion!
> 
> Thank you, Ding, this is much appreciated!
> 
> I agree, the `exec_update_lock` might be the better solution;
> I also need to familiarize myself more with it to double-check.
> 
> —Günther
> 


^ permalink raw reply

* [PATCH] landlock: Fix deadlock in restrict_one_thread_callback
From: Yihan Ding @ 2026-02-24  6:27 UTC (permalink / raw)
  To: Mickaël Salaün, Günther Noack
  Cc: Paul Moore, Jann Horn, linux-security-module, linux-kernel,
	syzbot+7ea2f5e9dfd468201817, Yihan Ding
In-Reply-To: <20260223.52c45aed20f8@gnoack.org>

syzbot found a deadlock in landlock_restrict_sibling_threads().
When multiple threads concurrently call landlock_restrict_self() with
sibling thread restriction enabled, they can deadlock by mutually
queueing task_works on each other and then blocking in kernel space
(waiting for the other to finish).

Fix this by serializing the TSYNC operations within the same process
using the exec_update_lock. This prevents concurrent invocations
from deadlocking.

Additionally, update the comments in the interrupt recovery path to
clarify that cancel_tsync_works() is an opportunistic cleanup, and
waiting for completion is strictly necessary to prevent a Use-After-Free
of the stack-allocated shared_ctx.

Fixes: 42fc7e6543f6 ("landlock: Multithreading support for landlock_restrict_self()")
Reported-by: syzbot+7ea2f5e9dfd468201817@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=7ea2f5e9dfd468201817
Signed-off-by: Yihan Ding <dingyihan@uniontech.com>
---
 security/landlock/tsync.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index de01aa899751..4e91af271f3b 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -447,6 +447,12 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
 	shared_ctx.new_cred = new_cred;
 	shared_ctx.set_no_new_privs = task_no_new_privs(current);
 
+	/*
+	 * Serialize concurrent TSYNC operations to prevent deadlocks
+	 * when multiple threads call landlock_restrict_self() simultaneously.
+	 */
+	down_write(&current->signal->exec_update_lock);
+
 	/*
 	 * We schedule a pseudo-signal task_work for each of the calling task's
 	 * sibling threads.  In the task work, each thread:
@@ -527,14 +533,17 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
 					   -ERESTARTNOINTR);
 
 				/*
-				 * Cancel task works for tasks that did not start running yet,
-				 * and decrement all_prepared and num_unfinished accordingly.
+				 * Opportunistic improvement: try to cancel task works
+				 * for tasks that did not start running yet. We do not
+				 * have a guarantee that it cancels any of the enqueued
+				 * task works (because task_work_run() might already have
+				 * dequeued them).
 				 */
 				cancel_tsync_works(&works, &shared_ctx);
 
 				/*
-				 * The remaining task works have started running, so waiting for
-				 * their completion will finish.
+				 * We must wait for the remaining task works to finish to
+				 * prevent a use-after-free of the local shared_ctx.
 				 */
 				wait_for_completion(&shared_ctx.all_prepared);
 			}
@@ -557,5 +566,7 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
 
 	tsync_works_release(&works);
 
+	up_write(&current->signal->exec_update_lock);
+
 	return atomic_read(&shared_ctx.preparation_error);
 }
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH v15 1/9] rust: types: Add Ownable/Owned types
From: aliceryhl @ 2026-02-24  7:37 UTC (permalink / raw)
  To: Andreas Hindborg
  Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, linux-kernel, rust-for-linux, linux-block,
	linux-security-module, dri-devel, linux-fsdevel, linux-mm,
	linux-pm, linux-pci, Asahi Lina, Oliver Mangold
In-Reply-To: <87wm0333qt.fsf@t14s.mail-host-address-is-not-set>

On Mon, Feb 23, 2026 at 03:59:22PM +0100, Andreas Hindborg wrote:
> Alice Ryhl <aliceryhl@google.com> writes:
> 
> > On Fri, Feb 20, 2026 at 10:51:10AM +0100, Andreas Hindborg wrote:
> >> From: Asahi Lina <lina+kernel@asahilina.net>
> >> 
> >> By analogy to `AlwaysRefCounted` and `ARef`, an `Ownable` type is a
> >> (typically C FFI) type that *may* be owned by Rust, but need not be. Unlike
> >> `AlwaysRefCounted`, this mechanism expects the reference to be unique
> >> within Rust, and does not allow cloning.
> >> 
> >> Conceptually, this is similar to a `KBox<T>`, except that it delegates
> >> resource management to the `T` instead of using a generic allocator.
> >> 
> >> [ om:
> >>   - Split code into separate file and `pub use` it from types.rs.
> >>   - Make from_raw() and into_raw() public.
> >>   - Remove OwnableMut, and make DerefMut dependent on Unpin instead.
> >>   - Usage example/doctest for Ownable/Owned.
> >>   - Fixes to documentation and commit message.
> >> ]
> >> 
> >> Link: https://lore.kernel.org/all/20250202-rust-page-v1-1-e3170d7fe55e@asahilina.net/
> >> Signed-off-by: Asahi Lina <lina+kernel@asahilina.net>
> >> Co-developed-by: Oliver Mangold <oliver.mangold@pm.me>
> >> Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
> >> Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
> >> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
> >> [ Andreas: Updated documentation, examples, and formatting ]
> >> Reviewed-by: Gary Guo <gary@garyguo.net>
> >> Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
> >> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
> >
> >> +///         let result = NonNull::new(KBox::into_raw(result))
> >> +///             .expect("Raw pointer to newly allocation KBox is null, this should never happen.");
> >
> > KBox should probably have an into_raw_nonnull().
> 
> I can add that.
> 
> >
> >> +///    let foo = Foo::new().expect("Failed to allocate a Foo. This shouldn't happen");
> >> +///    assert!(*FOO_ALLOC_COUNT.lock() == 1);
> >
> > Use ? here.
> 
> Ok.
> 
> >
> >> +/// }
> >> +/// // `foo` is out of scope now, so we expect no live allocations.
> >> +/// assert!(*FOO_ALLOC_COUNT.lock() == 0);
> >> +/// ```
> >> +pub unsafe trait Ownable {
> >> +    /// Releases the object.
> >> +    ///
> >> +    /// # Safety
> >> +    ///
> >> +    /// Callers must ensure that:
> >> +    /// - `this` points to a valid `Self`.
> >> +    /// - `*this` is no longer used after this call.
> >> +    unsafe fn release(this: NonNull<Self>);
> >
> > Honestly, not using it after this call may be too strong. I can imagine
> > wanting a value where I have both an ARef<_> and Owned<_> reference to
> > something similar to the existing Arc<_>/ListArc<_> pattern, and in that
> > case the value may in fact be accessed after this call if you still have
> > an ARef<_>.
> 
> I do not understand your use case.
> 
> You are not supposed to have both an `ARef` and an `Owned` at the same
> time. The `Owned` is to `ARef` what `UniqueArc` is to `Arc`. It is
> supposed to be unique and no `ARef` can be live while the `Owned` is
> live.
> 
> A `ListArc` is "at most one per list link" and it takes a refcount on
> the object by owning an `Arc`. As far as I recall, it does not provide
> mutable access to anything but the list link. To me, that is a very
> different situation.

I mean, even Page is kind of an example like that.

Pages are refcounted, but when you have a higher-order page, the
__free_pages() call does something special beyond what put_page(). For
example, if you have an order-2 page, which consists of 4 pages, then
the refcount only keeps the first page alive, and __free_pages() frees
the 3 extra pages right away even if refcount is still non-zero. The
first page then stays alive until the last put_page() is called.

> > If you modify Owned<_> invariants and Owned::from_raw() safety
> > requirements along the lines of what I say below, then this could just
> > say that the caller must have permission to call this function. The
> > concrete implementer can specify what that means more directly, but here
> > all it means is that a prior call to Owned::from_raw() promised to give
> > you permission to call it.
> 
> I don't think we need the "permission" wording. How about this:
> 
> 
> /// A mutable reference to an owned `T`.
> ///
> /// The [`Ownable`] is automatically freed or released when an instance of [`Owned`] is
> /// dropped.
> ///
> /// # Invariants
> ///
> /// - Until `T::release` is called, this `Owned<T>` exclusively owns the underlying `T`.
> /// - The `T` value is pinned.
> pub struct Owned<T: Ownable> {...}
> 
> 
> impl<T: Ownable> Owned<T> {
>     /// Creates a new instance of [`Owned`].
>     ///
>     /// This function takes over ownership of the underlying object.
>     ///
>     /// # Safety
>     ///
>     /// Callers must ensure that:
>     /// - `ptr` points to a valid instance of `T`.
>     /// - Until `T::release` is called, the returned `Owned<T>` exclusively owns the underlying `T`.
>     pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {...}
> }
> 
> pub trait Ownable {
>     /// Tear down this `Ownable`.
>     ///
>     /// Implementers of `Ownable` can use this function to clean up the use of `Self`. This can
>     /// include freeing the underlying object.
>     ///
>     /// # Safety
>     ///
>     /// Callers must ensure that the caller has exclusive ownership of `T`, and this ownership can
>     /// be transferred to the `release` method.
>     unsafe fn release(&mut self);
> }
> 
> 
> Note `Ownable` not being an unsafe trait.

It looks ok but see my above reply.

> >> +/// A mutable reference to an owned `T`.
> >> +///
> >> +/// The [`Ownable`] is automatically freed or released when an instance of [`Owned`] is
> >> +/// dropped.
> >> +///
> >> +/// # Invariants
> >> +///
> >> +/// - The [`Owned<T>`] has exclusive access to the instance of `T`.
> >> +/// - The instance of `T` will stay alive at least as long as the [`Owned<T>`] is alive.
> >> +pub struct Owned<T: Ownable> {
> >> +    ptr: NonNull<T>,
> >> +}
> >
> > I think some more direct and less fuzzy invariants would be:
> >
> > - This `Owned<T>` holds permissions to call `T::release()` on the value once.
> > - Until `T::release()` is called, this `Owned<T>` may perform mutable access on the `T`.
> 
> I do not like the wording for mutable access. Formulating safety
> requirements for `from_raw` and safety comments for that function
> becomes convoluted like this. I'd rather formulate the
> access capability in terms of ownership;
> 
>  - Until `T::release()` is called, this `Owned<T>` exclusively owns the
>    underlying `T`.
> 
> How is that?
> 
> > - The `T` value is pinned.
> 
> I am unsure about the pinning terminology. If we say that `T` is pinned,
> does this mean that it will never move, even if `T: Unpin`? Or is it
> implied that `T` may move if it is `Unpin`?

Values that are `Unpin` can always move - pinning is a no-op for them.

Alice

^ permalink raw reply

* Re: [PATCH] landlock: Fix deadlock in restrict_one_thread_callback
From: Günther Noack @ 2026-02-24  8:48 UTC (permalink / raw)
  To: Yihan Ding
  Cc: Mickaël Salaün, Paul Moore, Jann Horn,
	linux-security-module, linux-kernel, syzbot+7ea2f5e9dfd468201817
In-Reply-To: <20260224062729.2908692-1-dingyihan@uniontech.com>

Hello!

Thanks for sending the patch!

On Tue, Feb 24, 2026 at 02:27:29PM +0800, Yihan Ding wrote:
> syzbot found a deadlock in landlock_restrict_sibling_threads().
> When multiple threads concurrently call landlock_restrict_self() with
> sibling thread restriction enabled, they can deadlock by mutually
> queueing task_works on each other and then blocking in kernel space
> (waiting for the other to finish).
> 
> Fix this by serializing the TSYNC operations within the same process
> using the exec_update_lock. This prevents concurrent invocations
> from deadlocking.
> 
> Additionally, update the comments in the interrupt recovery path to
> clarify that cancel_tsync_works() is an opportunistic cleanup, and
> waiting for completion is strictly necessary to prevent a Use-After-Free
> of the stack-allocated shared_ctx.
> 
> Fixes: 42fc7e6543f6 ("landlock: Multithreading support for landlock_restrict_self()")
> Reported-by: syzbot+7ea2f5e9dfd468201817@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=7ea2f5e9dfd468201817
> Signed-off-by: Yihan Ding <dingyihan@uniontech.com>
> ---
>  security/landlock/tsync.c | 19 +++++++++++++++----
>  1 file changed, 15 insertions(+), 4 deletions(-)
> 
> diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
> index de01aa899751..4e91af271f3b 100644
> --- a/security/landlock/tsync.c
> +++ b/security/landlock/tsync.c
> @@ -447,6 +447,12 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
>  	shared_ctx.new_cred = new_cred;
>  	shared_ctx.set_no_new_privs = task_no_new_privs(current);
>  
> +	/*
> +	 * Serialize concurrent TSYNC operations to prevent deadlocks
> +	 * when multiple threads call landlock_restrict_self() simultaneously.
> +	 */
> +	down_write(&current->signal->exec_update_lock);

Should we use the *_killable variant of this lock acquisition?


>  	/*
>  	 * We schedule a pseudo-signal task_work for each of the calling task's
>  	 * sibling threads.  In the task work, each thread:
> @@ -527,14 +533,17 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
>  					   -ERESTARTNOINTR);
>  
>  				/*
> -				 * Cancel task works for tasks that did not start running yet,
> -				 * and decrement all_prepared and num_unfinished accordingly.
> +				 * Opportunistic improvement: try to cancel task works
> +				 * for tasks that did not start running yet. We do not
> +				 * have a guarantee that it cancels any of the enqueued
> +				 * task works (because task_work_run() might already have
> +				 * dequeued them).
>  				 */
>  				cancel_tsync_works(&works, &shared_ctx);
>  
>  				/*
> -				 * The remaining task works have started running, so waiting for
> -				 * their completion will finish.
> +				 * We must wait for the remaining task works to finish to
> +				 * prevent a use-after-free of the local shared_ctx.
>  				 */
>  				wait_for_completion(&shared_ctx.all_prepared);

I do not think that we must wait for all_prepared here, as your
updated comment says: The landlock_restrict_sibling_threads() function
still waits for all of these task works to finish at the bottom where
it waits for "all_finished", so there is no UAF on the local shared
context?

I would recommend replacing the
wait_for_completion(&shared_ctx.all_prepared) call and its comment
with an explicit "break":

/*
 * Break the loop with error.  The cleanup code after the loop
 * unblocks the remaining task_works.
 */
break;

Please also update the comment above the complete_all(ready_to_commit):

  We now have either (a) all sibling threads blocking and in
  "prepared" state in the task work, or (b) the preparation error is
  set.  Ask all threads to commit (or abort).

Then it is a bit more explicit about the error handling variant of this.


(FYI, I have tested the patch variant where I only removed the
wait_for_completion(all_prepared) call, and where I did *not* add the
additional lock at the top.  In this configuration, I was unable to
get it to hang any more, even with added mdelays.  But as discussed in
section 2.2 of [1], there are still difficult to reproduce scenarios
where this can theoretically fail, and it is better to use the lock at
the top.)

[1] https://lore.kernel.org/all/20260223.52c45aed20f8@gnoack.org/

Please also feel free to split up the change into a part that adds the
exec_guard_lock and a part that changes the path where the calling
thread gets interrupted.  Strictly speaking, the part where we change
the interruption logic is only a nicety once we have the
exec_guard_lock in place.

>  			}
> @@ -557,5 +566,7 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
>  
>  	tsync_works_release(&works);
>  
> +	up_write(&current->signal->exec_update_lock);
> +
>  	return atomic_read(&shared_ctx.preparation_error);
>  }
> -- 
> 2.51.0
> 

Thanks,
–Günther

^ permalink raw reply

* [syzbot] [mm?] INFO: rcu detected stall in sys_rename (8)
From: syzbot @ 2026-02-24  8:50 UTC (permalink / raw)
  To: jmorris, linux-kernel, linux-mm, linux-security-module, paul,
	penguin-kernel, serge, syzkaller-bugs, takedakn

Hello,

syzbot found the following issue on:

HEAD commit:    44982d352c33 Add linux-next specific files for 20260219
git tree:       linux-next
console output: https://syzkaller.appspot.com/x/log.txt?x=10ef3c02580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=51f859f3211496bc
dashboard link: https://syzkaller.appspot.com/bug?extid=1e663068a97140bb66f3
compiler:       Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=1177fe52580000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/173e988354ac/disk-44982d35.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/69062373098e/vmlinux-44982d35.xz
kernel image: https://storage.googleapis.com/syzbot-assets/3dd3887dc600/bzImage-44982d35.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+1e663068a97140bb66f3@syzkaller.appspotmail.com

rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
rcu: 	Tasks blocked on level-0 rcu_node (CPUs 0-1): P1034/2:b..l P5873/1:b..l
rcu: 	(detected by 1, t=10504 jiffies, g=14085, q=669 ncpus=2)
task:udevd           state:R  running task     stack:23784 pid:5873  tgid:5873  ppid:5200   task_flags:0x400140 flags:0x00080800
Call Trace:
 <TASK>
 context_switch kernel/sched/core.c:5295 [inline]
 __schedule+0x1585/0x5340 kernel/sched/core.c:6907
 preempt_schedule_irq+0x4d/0xa0 kernel/sched/core.c:7234
 irqentry_exit+0x599/0x620 kernel/entry/common.c:239
 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697
RIP: 0010:lock_acquire+0x20b/0x2e0 kernel/locking/lockdep.c:5872
Code: e9 30 ff ff ff e8 c5 f3 18 0a f7 c3 00 02 00 00 0f 84 38 ff ff ff 65 48 8b 05 41 01 a0 11 48 3b 44 24 30 75 33 fb 48 83 c4 38 <5b> 41 5c 41 5d 41 5e 41 5f 5d c3 cc cc cc cc cc 48 8d 3d fe 3b 95
RSP: 0018:ffffc90003f073d8 EFLAGS: 00000286
RAX: a296ff60d4053400 RBX: 0000000000000246 RCX: 0000000000000046
RDX: 00000000112c4056 RSI: ffffffff8e287ccb RDI: ffffffff8c2a0a00
RBP: 0000000000000000 R08: ffffffff8176da45 R09: ffffffff8e9602e0
R10: ffffc90003f07538 R11: ffffffff81b115b0 R12: 0000000000000002
R13: ffffffff8e9602e0 R14: 0000000000000000 R15: 0000000000000000
 rcu_lock_acquire include/linux/rcupdate.h:312 [inline]
 rcu_read_lock include/linux/rcupdate.h:850 [inline]
 class_rcu_constructor include/linux/rcupdate.h:1193 [inline]
 unwind_next_frame+0xc2/0x23c0 arch/x86/kernel/unwind_orc.c:495
 arch_stack_walk+0x11b/0x150 arch/x86/kernel/stacktrace.c:25
 stack_trace_save+0xa9/0x100 kernel/stacktrace.c:122
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5219 [inline]
 __kmalloc_noprof+0x35c/0x760 mm/slub.c:5231
 kmalloc_noprof include/linux/slab.h:966 [inline]
 tomoyo_realpath_from_path+0xe3/0x5d0 security/tomoyo/realpath.c:251
 tomoyo_get_realpath security/tomoyo/file.c:151 [inline]
 tomoyo_path2_perm+0x2c5/0x760 security/tomoyo/file.c:927
 tomoyo_path_rename+0x14e/0x1b0 security/tomoyo/tomoyo.c:300
 security_path_rename+0x248/0x460 security/security.c:1518
 filename_renameat2+0x4c1/0x9c0 fs/namei.c:6139
 __do_sys_rename fs/namei.c:6188 [inline]
 __se_sys_rename+0x55/0x2c0 fs/namei.c:6184
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f6cd687acc7
RSP: 002b:00007ffec20235f8 EFLAGS: 00000202 ORIG_RAX: 0000000000000052
RAX: ffffffffffffffda RBX: 000055db72eaa280 RCX: 00007f6cd687acc7
RDX: 000055db72ea2010 RSI: 00007ffec2023610 RDI: 00007ffec2023a10
RBP: 000055db72ebff10 R08: 00000000000001e0 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 00007ffec2023610
R13: 00007ffec2023a10 R14: 0000000000000000 R15: 000055db6bd089dd
 </TASK>
task:kworker/u8:7    state:R  running task     stack:24416 pid:1034  tgid:1034  ppid:2      task_flags:0x4208060 flags:0x00080000
Workqueue: ipv6_addrconf addrconf_dad_work
Call Trace:
 <TASK>
 context_switch kernel/sched/core.c:5295 [inline]
 __schedule+0x1585/0x5340 kernel/sched/core.c:6907
 preempt_schedule_common+0x82/0xd0 kernel/sched/core.c:7091
 preempt_schedule_thunk+0x16/0x30 arch/x86/entry/thunk.S:12
 __local_bh_enable_ip+0xe1/0x130 kernel/softirq.c:457
 local_bh_enable include/linux/bottom_half.h:33 [inline]
 rcu_read_unlock_bh include/linux/rcupdate.h:924 [inline]
 __dev_queue_xmit+0x1e6c/0x38a0 net/core/dev.c:4864
 NF_HOOK_COND include/linux/netfilter.h:307 [inline]
 ip6_output+0x340/0x550 net/ipv6/ip6_output.c:246
 NF_HOOK include/linux/netfilter.h:318 [inline]
 ndisc_send_skb+0xbaa/0x14e0 net/ipv6/ndisc.c:512
 ndisc_send_ns+0xd7/0x160 net/ipv6/ndisc.c:670
 addrconf_dad_work+0xac4/0x14c0 net/ipv6/addrconf.c:4287
 process_one_work+0x949/0x1650 kernel/workqueue.c:3279
 process_scheduled_works kernel/workqueue.c:3362 [inline]
 worker_thread+0xb46/0x1140 kernel/workqueue.c:3443
 kthread+0x388/0x470 kernel/kthread.c:467
 ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
rcu: rcu_preempt kthread starved for 10573 jiffies! g14085 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x0 ->cpu=0
rcu: 	Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
rcu: RCU grace-period kthread stack dump:
task:rcu_preempt     state:R  running task     stack:27616 pid:16    tgid:16    ppid:2      task_flags:0x208040 flags:0x00080000
Call Trace:
 <TASK>
 context_switch kernel/sched/core.c:5295 [inline]
 __schedule+0x1585/0x5340 kernel/sched/core.c:6907
 __schedule_loop kernel/sched/core.c:6989 [inline]
 schedule+0x164/0x360 kernel/sched/core.c:7004
 schedule_timeout+0x158/0x2c0 kernel/time/sleep_timeout.c:99
 rcu_gp_fqs_loop+0x312/0x11d0 kernel/rcu/tree.c:2095
 rcu_gp_kthread+0x9e/0x2b0 kernel/rcu/tree.c:2297
 kthread+0x388/0x470 kernel/kthread.c:467
 ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
rcu: Stack dump where RCU GP kthread last ran:
Sending NMI from CPU 1 to CPUs 0:
NMI backtrace for cpu 0
CPU: 0 UID: 0 PID: 6085 Comm: syz.0.27 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
RIP: 0010:check_kcov_mode kernel/kcov.c:194 [inline]
RIP: 0010:write_comp_data kernel/kcov.c:246 [inline]
RIP: 0010:__sanitizer_cov_trace_const_cmp4+0x36/0x90 kernel/kcov.c:314
Code: 28 e9 7b 11 65 8b 0d 49 e9 7b 11 81 e1 00 01 ff 00 74 11 81 f9 00 01 00 00 75 5b 83 ba 54 16 00 00 00 74 52 8b 8a 30 16 00 00 <83> f9 03 75 47 48 8b 8a 38 16 00 00 44 8b 8a 34 16 00 00 49 c1 e1
RSP: 0018:ffffc900025e7a88 EFLAGS: 00000046
RAX: ffffffff81b67144 RBX: ffff8880b8423e40 RCX: 0000000000000000
RDX: ffff88802df49e40 RSI: 0000000000000000 RDI: 0000000000000000
RBP: 0000000000000000 R08: ffffffff81b32095 R09: ffffffff9a518508
R10: 0000000000000003 R11: ffffffff81742750 R12: 00000000100006b5
R13: dffffc0000000000 R14: 00000000000001ed R15: 0000000000000020
FS:  00007f9fec4f96c0(0000) GS:ffff888125002000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000200000000058 CR3: 0000000075658000 CR4: 00000000003526f0
Call Trace:
 <TASK>
 clockevents_program_event+0x1d4/0x350 kernel/time/clockevents.c:336
 hrtimer_start_range_ns+0x1687/0x1ff0 kernel/time/hrtimer.c:1331
 __posixtimer_deliver_signal kernel/time/posix-timers.c:314 [inline]
 posixtimer_deliver_signal+0x1ce/0x410 kernel/time/posix-timers.c:340
 dequeue_signal+0x249/0x370 kernel/signal.c:660
 get_signal+0x55d/0x1330 kernel/signal.c:2914
 arch_do_signal_or_restart+0xbc/0x830 arch/x86/kernel/signal.c:337
 __exit_to_user_mode_loop kernel/entry/common.c:64 [inline]
 exit_to_user_mode_loop+0x86/0x480 kernel/entry/common.c:98
 __exit_to_user_mode_prepare include/linux/irq-entry-common.h:226 [inline]
 syscall_exit_to_user_mode_prepare include/linux/irq-entry-common.h:256 [inline]
 syscall_exit_to_user_mode include/linux/entry-common.h:325 [inline]
 do_syscall_64+0x32d/0xf80 arch/x86/entry/syscall_64.c:100
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f9feb59c629
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f9fec4f90e8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca
RAX: fffffffffffffe00 RBX: 00007f9feb815fa8 RCX: 00007f9feb59c629
RDX: 0000000000000000 RSI: 0000000000000080 RDI: 00007f9feb815fa8
RBP: 00007f9feb815fa0 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f9feb816038 R14: 00007ffda92b66d0 R15: 00007ffda92b67b8
 </TASK>


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply

* Re: [PATCH v2 12/15] ovl: change ovl_create_real() to get a new lock when re-opening created file.
From: Christian Brauner @ 2026-02-24  9:20 UTC (permalink / raw)
  To: Chris Mason
  Cc: NeilBrown, Alexander Viro, David Howells, Jan Kara, Chuck Lever,
	Jeff Layton, Miklos Szeredi, Amir Goldstein, John Johansen,
	Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
	Darrick J. Wong, linux-kernel, netfs, linux-fsdevel, linux-nfs,
	linux-unionfs, apparmor, linux-security-module, selinux
In-Reply-To: <20260223132424.105125-1-clm@meta.com>

On Mon, Feb 23, 2026 at 05:23:00AM -0800, Chris Mason wrote:
> NeilBrown <neilb@ownmail.net> wrote:
> > From: NeilBrown <neil@brown.name>
> > 
> > When ovl_create_real() is used to create a file on the upper filesystem
> > it needs to return the resulting dentry - positive and hashed.
> > It is usually the case the that dentry passed to the create function
> > (e.g.  vfs_create()) will be suitable but this is not guaranteed.  The
> > filesystem may unhash that dentry forcing a repeat lookup next time the
> > name is wanted.
> > 
> 
> Hi everyone,
> 
> Amir suggested I run these through, and this commit was flagged:
> 
> commit 62d49d1e44667e4f93bec415faabec5526992ac0
> Author: NeilBrown <neil@brown.name>
> 
> ovl: change ovl_create_real() to get a new lock when re-opening created file.
> 
> This commit changes ovl_create_real() to drop the directory lock and
> reacquire a new lock for lookup when the created dentry is unhashed. It
> also removes ovl_lookup_upper() which is no longer used.
> 
> Signed-off-by: NeilBrown <neil@brown.name>

Fwiw, all patches that are applied go through AI review. My plan is to
have a discussion on getting automation set up for this at LSFMM so that
we can have the bot directly reply to reviews but under our control so
we can vet reviews.

^ permalink raw reply

* Re: [PATCH v15 1/9] rust: types: Add Ownable/Owned types
From: Andreas Hindborg @ 2026-02-24 10:41 UTC (permalink / raw)
  To: aliceryhl
  Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman, Dave Ertman,
	Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, linux-kernel, rust-for-linux, linux-block,
	linux-security-module, dri-devel, linux-fsdevel, linux-mm,
	linux-pm, linux-pci, Asahi Lina, Oliver Mangold
In-Reply-To: <aZ1VQmtapuoerpVo@google.com>

<aliceryhl@google.com> writes:

> On Mon, Feb 23, 2026 at 03:59:22PM +0100, Andreas Hindborg wrote:
>> Alice Ryhl <aliceryhl@google.com> writes:
>>
>> > On Fri, Feb 20, 2026 at 10:51:10AM +0100, Andreas Hindborg wrote:
>> >> From: Asahi Lina <lina+kernel@asahilina.net>
>> >>
>> >> By analogy to `AlwaysRefCounted` and `ARef`, an `Ownable` type is a
>> >> (typically C FFI) type that *may* be owned by Rust, but need not be. Unlike
>> >> `AlwaysRefCounted`, this mechanism expects the reference to be unique
>> >> within Rust, and does not allow cloning.
>> >>
>> >> Conceptually, this is similar to a `KBox<T>`, except that it delegates
>> >> resource management to the `T` instead of using a generic allocator.
>> >>
>> >> [ om:
>> >>   - Split code into separate file and `pub use` it from types.rs.
>> >>   - Make from_raw() and into_raw() public.
>> >>   - Remove OwnableMut, and make DerefMut dependent on Unpin instead.
>> >>   - Usage example/doctest for Ownable/Owned.
>> >>   - Fixes to documentation and commit message.
>> >> ]
>> >>
>> >> Link: https://lore.kernel.org/all/20250202-rust-page-v1-1-e3170d7fe55e@asahilina.net/
>> >> Signed-off-by: Asahi Lina <lina+kernel@asahilina.net>
>> >> Co-developed-by: Oliver Mangold <oliver.mangold@pm.me>
>> >> Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
>> >> Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
>> >> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
>> >> [ Andreas: Updated documentation, examples, and formatting ]
>> >> Reviewed-by: Gary Guo <gary@garyguo.net>
>> >> Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
>> >> Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
>> >
>> >> +///         let result = NonNull::new(KBox::into_raw(result))
>> >> +///             .expect("Raw pointer to newly allocation KBox is null, this should never happen.");
>> >
>> > KBox should probably have an into_raw_nonnull().
>>
>> I can add that.
>>
>> >
>> >> +///    let foo = Foo::new().expect("Failed to allocate a Foo. This shouldn't happen");
>> >> +///    assert!(*FOO_ALLOC_COUNT.lock() == 1);
>> >
>> > Use ? here.
>>
>> Ok.
>>
>> >
>> >> +/// }
>> >> +/// // `foo` is out of scope now, so we expect no live allocations.
>> >> +/// assert!(*FOO_ALLOC_COUNT.lock() == 0);
>> >> +/// ```
>> >> +pub unsafe trait Ownable {
>> >> +    /// Releases the object.
>> >> +    ///
>> >> +    /// # Safety
>> >> +    ///
>> >> +    /// Callers must ensure that:
>> >> +    /// - `this` points to a valid `Self`.
>> >> +    /// - `*this` is no longer used after this call.
>> >> +    unsafe fn release(this: NonNull<Self>);
>> >
>> > Honestly, not using it after this call may be too strong. I can imagine
>> > wanting a value where I have both an ARef<_> and Owned<_> reference to
>> > something similar to the existing Arc<_>/ListArc<_> pattern, and in that
>> > case the value may in fact be accessed after this call if you still have
>> > an ARef<_>.
>>
>> I do not understand your use case.
>>
>> You are not supposed to have both an `ARef` and an `Owned` at the same
>> time. The `Owned` is to `ARef` what `UniqueArc` is to `Arc`. It is
>> supposed to be unique and no `ARef` can be live while the `Owned` is
>> live.
>>
>> A `ListArc` is "at most one per list link" and it takes a refcount on
>> the object by owning an `Arc`. As far as I recall, it does not provide
>> mutable access to anything but the list link. To me, that is a very
>> different situation.
>
> I mean, even Page is kind of an example like that.
>
> Pages are refcounted, but when you have a higher-order page, the
> __free_pages() call does something special beyond what put_page(). For
> example, if you have an order-2 page, which consists of 4 pages, then
> the refcount only keeps the first page alive, and __free_pages() frees
> the 3 extra pages right away even if refcount is still non-zero. The
> first page then stays alive until the last put_page() is called.

I see. We currently only support order 0 pages. I think we can handle
this situation later, if we need to handle higher order pages.

In that case, we could hand out `Owned<Page>` for the head page and then
provide some way of getting a `&Page` for the tail pages. Obtaining
`Owned<Page>` for a tail page does not make sense.

More likely we will build an abstraction for `struct folio`. We can
still hand some kind of page reference for tail pages from an `Owned<Folio>`.

Best regards,
Andreas Hindborg



^ permalink raw reply

* Re: [RFC PATCH] fs/pidfs: Add permission check to pidfd_info()
From: Christian Brauner @ 2026-02-24 11:18 UTC (permalink / raw)
  To: Daniel Durning
  Cc: linux-fsdevel, linux-security-module, selinux, viro, jack, paul,
	stephen.smalley.work, omosnace, Oleg Nesterov
In-Reply-To: <CAKrb_fFEvf5VzY_-zcc800wjVGOFbiGrpzC7S6Ghy9qhYJrZ1w@mail.gmail.com>

On Fri, Feb 20, 2026 at 03:45:00PM -0500, Daniel Durning wrote:
> On Tue, Feb 17, 2026 at 7:01 AM Christian Brauner <brauner@kernel.org> wrote:
> >
> > On Wed, Feb 11, 2026 at 02:43:21PM -0500, Daniel Durning wrote:
> > > On Mon, Feb 9, 2026 at 9:01 AM Christian Brauner <brauner@kernel.org> wrote:
> > > >
> > > > On Fri, Feb 06, 2026 at 06:02:48PM +0000, danieldurning.work@gmail.com wrote:
> > > > > From: Daniel Durning <danieldurning.work@gmail.com>
> > > > >
> > > > > Added a permission check to pidfd_info(). Originally, process info
> > > > > could be retrieved with a pidfd even if proc was mounted with hidepid
> > > > > enabled, allowing pidfds to be used to bypass those protections. We
> > > > > now call ptrace_may_access() to perform some DAC checking as well
> > > > > as call the appropriate LSM hook.
> > > > >
> > > > > The downside to this approach is that there are now more restrictions
> > > > > on accessing this info from a pidfd than when just using proc (without
> > > > > hidepid). I am open to suggestions if anyone can think of a better way
> > > > > to handle this.
> > > >
> > > > This isn't really workable since this would regress userspace quite a
> > > > bit. I think we need a different approach. I've given it some thought
> > > > and everything's kinda ugly but this might work.
> > > >
> > > > In struct pid_namespace record whether anyone ever mounted a procfs
> > > > with hidepid turned on for this pidns. In pidfd_info() we check whether
> > > > hidepid was ever turned on. If it wasn't we're done and can just return
> > > > the info. This will be the common case. If hidepid was ever turned on
> > > > use kern_path("/proc") to lookup procfs. If not found check
> > > > ptrace_may_access() to decide whether to return the info or not. If
> > > > /proc is found check it's hidepid settings and make a decision based on
> > > > that.
> > > >
> > > > You can probably reorder this to call ptrace_may_access() first and then
> > > > do the procfs lookup dance. Thoughts?
> > >
> > > Thanks for the feedback. I think your solution makes sense.
> > >
> > > Unfortunately, it seems like systemd mounts procfs with hidepid enabled on
> > > boot for services with the ProtectProc option enabled. This means that
> > > procfs will always have been mounted with hidepid in the init pid namespace.
> > > Do you think it would be viable to record whether or not procfs was mounted
> > > with hidepid enabled in the mount namespace instead?
> >
> > I guess we can see what it looks like.
> 
> Having looked into this some more I am not sure if the mount
> namespace is viable either since a single proc instance could be in
> multiple mount namespaces. In addition the mount namespace
> does not seem to be easily accessible in the function where proc
> mount options are applied. I also considered adding an option
> similar to hidepid to pidfs, but since pidfs is not userspace-mounted
> I do not think that is possible without some significant changes.
> 
> Doing a proc lookup with kern_path() does work, but it does not seem
> practical in terms of performance unless we had some other way to
> skip it in the common case.
> 
> Curious if anyone else has any ideas or suggestions on how this
> could be implemented.

Ok, so there's another series that adds support for allowing to mount
procfs with subset=pid. That series currently uses an arcane mechanism
where it walks all mounts in the caller mounts namespace to find procfs
mounts and check its mount options (mount_too_revealing()). To get away
from this barbaric hack I proposed recording all fully visible procfs
mounts in a separate list on struct mnt_namespace that it can walk
whenever a new procfs mount gets plugged in. Once we've done that work
we effectively track whenever a procfs mount comes and goes from a given
mount namespace. When we plug in that mount we simply remember the
option used for the least restrictive procfs mount in that namespace in
a per-mntns "proc_visiblity" field or something.

Then in pidfs we simply do a:

visibility_restricted = READ_ONCE(current->ns_proxy->mnt_ns);

and be done with it. No locks, no lookup, no perf hit. Thoughts?

^ permalink raw reply

* [PATCH v16 07/10] rust: page: update formatting of `use` statements
From: Andreas Hindborg @ 2026-02-24 11:18 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

Update formatting in preparation for next patch

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/page.rs | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index 432fc0297d4a8..bf3bed7e2d3fe 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -3,17 +3,23 @@
 //! Kernel page allocation and management.
 
 use crate::{
-    alloc::{AllocError, Flags},
+    alloc::{
+        AllocError,
+        Flags, //
+    },
     bindings,
     error::code::*,
     error::Result,
-    uaccess::UserSliceReader,
+    uaccess::UserSliceReader, //
 };
 use core::{
     marker::PhantomData,
     mem::ManuallyDrop,
     ops::Deref,
-    ptr::{self, NonNull},
+    ptr::{
+        self,
+        NonNull, //
+    }, //
 };
 
 /// A bitwise shift for the page size.

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 00/10] rust: add `Ownable` trait and `Owned` type
From: Andreas Hindborg @ 2026-02-24 11:17 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg, Asahi Lina, Oliver Mangold, Viresh Kumar,
	Asahi Lina, Andreas Hindborg

Add a new trait `Ownable` and type `Owned` for types that specify their
own way of performing allocation and destruction. This is useful for
types from the C side.

Add the trait `OwnableRefCounted` that allows conversion between
`ARef` and `Owned`. This is analogous to conversion between `Arc` and
`UniqueArc`.

Convert `Page` to be `Ownable` and add a `from_raw` method.

Implement `ForeignOwnable` for `Owned`.

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
Changes in v16:
- Simplify pointer to reference cast in `Page::from_raw`.
- Use `NonNull<Page>` rather than `Owned<Page>` for `BorrowedPage` internals.
- Use "convertible to reference" wording when converting pointers to references.
- Fix formatting for `Page::from_raw` docs.
- Leave imports alone when adding safety comment to aref example.
- Use `KBox::into_nonnull` for examples.
- Add patch for `KBox::into_nonnull`.
- Change invariants and safety comments of `Ownable` and make the trait safe.
- Make `Ownable::release` take a mutable reference.
- Fix error handling in example for `Ownable`
- Link to v15: https://msgid.link/20260220-unique-ref-v15-0-893ed86b06cc@kernel.org

Changes in v15:
- Update series with original SoB's.
- Rename `AlwaysRefCounted` in `kernel::usb`.
- Rename `Owned::get_pin_mut` to `Owned::as_pin_mut`.
- Link to v14: https://msgid.link/20260204-unique-ref-v14-0-17cb29ebacbb@kernel.org

Changes in v14:
- Rebase on v6.19-rc7.
- Rewrite cover letter.
- Update documentation and safety comments based on v13 feedback.
- Update commit messages.
- Reorder implementation blocks in owned.rs.
- Update example in owned.rs to use try operator rather than `expect`.
- Reformat use statements.
- Add patch: rust: page: convert to `Ownable`.
- Add patch: rust: implement `ForeignOwnable` for `Owned`.
- Add patch: rust: page: add `from_raw()`.
- Link to v13: https://lore.kernel.org/r/20251117-unique-ref-v13-0-b5b243df1250@pm.me

Changes in v13:
- Rebase onto v6.18-rc1 (Andreas's work).
- Documentation and style fixes contributed by Andreas
- Link to v12: https://lore.kernel.org/r/20251001-unique-ref-v12-0-fa5c31f0c0c4@pm.me

Changes in v12:
-
- Rebase onto v6.17-rc1 (Andreas's work).
- moved kernel/types/ownable.rs to kernel/owned.rs
- Drop OwnableMut, make DerefMut depend on Unpin instead. I understood
  ML discussion as that being okay, but probably needs further scrunity.
- Lots of more documentation changes suggested by reviewers.
- Usage example for Ownable/Owned.
- Link to v11: https://lore.kernel.org/r/20250618-unique-ref-v11-0-49eadcdc0aa6@pm.me

Changes in v11:
- Rework of documentation. I tried to honor all requests for changes "in
  spirit" plus some clearifications and corrections of my own.
- Dropping `SimpleOwnedRefCounted` by request from Alice, as it creates a
  potentially problematic blanket implementation (which a derive macro that
  could be created later would not have).
- Dropping Miguel's "kbuild: provide `RUSTC_HAS_DO_NOT_RECOMMEND` symbol"
  patch, as it is not needed anymore after dropping `SimpleOwnedRefCounted`.
  (I can add it again, if it is considered useful anyway).
- Link to v10: https://lore.kernel.org/r/20250502-unique-ref-v10-0-25de64c0307f@pm.me

Changes in v10:
- Moved kernel/ownable.rs to kernel/types/ownable.rs
- Fixes in documentation / comments as suggested by Andreas Hindborg
- Added Reviewed-by comment for Andreas Hindborg
- Fix rustfmt of pid_namespace.rs
- Link to v9: https://lore.kernel.org/r/20250325-unique-ref-v9-0-e91618c1de26@pm.me

Changes in v9:
- Rebase onto v6.14-rc7
- Move Ownable/OwnedRefCounted/Ownable, etc., into separate module
- Documentation fixes to Ownable/OwnableMut/OwnableRefCounted
- Add missing SAFETY documentation to ARef example
- Link to v8: https://lore.kernel.org/r/20250313-unique-ref-v8-0-3082ffc67a31@pm.me

Changes in v8:
- Fix Co-developed-by and Suggested-by tags as suggested by Miguel and Boqun
- Some small documentation fixes in Owned/Ownable patch
- removing redundant trait constraint on DerefMut for Owned as suggested by Boqun Feng
- make SimpleOwnedRefCounted no longer implement RefCounted as suggested by Boqun Feng
- documentation for RefCounted as suggested by Boqun Feng
- Link to v7: https://lore.kernel.org/r/20250310-unique-ref-v7-0-4caddb78aa05@pm.me

Changes in v7:
- Squash patch to make Owned::from_raw/into_raw public into parent
- Added Signed-off-by to other people's commits
- Link to v6: https://lore.kernel.org/r/20250310-unique-ref-v6-0-1ff53558617e@pm.me

Changes in v6:
- Changed comments/formatting as suggested by Miguel Ojeda
- Included and used new config flag RUSTC_HAS_DO_NOT_RECOMMEND,
  thus no changes to types.rs will be needed when the attribute
  becomes available.
- Fixed commit message for Owned patch.
- Link to v5: https://lore.kernel.org/r/20250307-unique-ref-v5-0-bffeb633277e@pm.me

Changes in v5:
- Rebase the whole thing on top of the Ownable/Owned traits by Asahi Lina.
- Rename AlwaysRefCounted to RefCounted and make AlwaysRefCounted a
  marker trait instead to allow to obtain an ARef<T> from an &T,
  which (as Alice pointed out) is unsound when combined with UniqueRef/Owned.
- Change the Trait design and naming to implement this feature,
  UniqueRef/UniqueRefCounted is dropped in favor of Ownable/Owned and
  OwnableRefCounted is used to provide the functions to convert
  between Owned and ARef.
- Link to v4: https://lore.kernel.org/r/20250305-unique-ref-v4-1-a8fdef7b1c2c@pm.me

Changes in v4:
- Just a minor change in naming by request from Andreas Hindborg,
  try_shared_to_unique() -> try_from_shared(),
  unique_to_shared() -> into_shared(),
  which is more in line with standard Rust naming conventions.
- Link to v3: https://lore.kernel.org/r/Z8Wuud2UQX6Yukyr@mango

---
Andreas Hindborg (5):
      rust: alloc: add `KBox::into_nonnull`
      rust: aref: update formatting of use statements
      rust: page: update formatting of `use` statements
      rust: implement `ForeignOwnable` for `Owned`
      rust: page: add `from_raw()`

Asahi Lina (2):
      rust: types: Add Ownable/Owned types
      rust: page: convert to `Ownable`

Oliver Mangold (3):
      rust: rename `AlwaysRefCounted` to `RefCounted`.
      rust: Add missing SAFETY documentation for `ARef` example
      rust: Add `OwnableRefCounted`

 rust/kernel/alloc/kbox.rs       |   8 +
 rust/kernel/auxiliary.rs        |   7 +-
 rust/kernel/block/mq/request.rs |  15 +-
 rust/kernel/cred.rs             |  13 +-
 rust/kernel/device.rs           |  10 +-
 rust/kernel/device/property.rs  |   7 +-
 rust/kernel/drm/device.rs       |  10 +-
 rust/kernel/drm/gem/mod.rs      |   8 +-
 rust/kernel/fs/file.rs          |  16 +-
 rust/kernel/i2c.rs              |  16 +-
 rust/kernel/lib.rs              |   1 +
 rust/kernel/mm.rs               |  15 +-
 rust/kernel/mm/mmput_async.rs   |   9 +-
 rust/kernel/opp.rs              |  10 +-
 rust/kernel/owned.rs            | 350 ++++++++++++++++++++++++++++++++++++++++
 rust/kernel/page.rs             |  61 +++++--
 rust/kernel/pci.rs              |  10 +-
 rust/kernel/pid_namespace.rs    |  12 +-
 rust/kernel/platform.rs         |   7 +-
 rust/kernel/sync/aref.rs        |  78 ++++++---
 rust/kernel/task.rs             |  10 +-
 rust/kernel/types.rs            |  13 +-
 rust/kernel/usb.rs              |  15 +-
 23 files changed, 617 insertions(+), 84 deletions(-)
---
base-commit: b8d687c7eeb52d0353ac27c4f71594a2e6aa365f
change-id: 20250305-unique-ref-29fcd675f9e9

Best regards,
-- 
Andreas Hindborg <a.hindborg@kernel.org>



^ permalink raw reply

* [PATCH v16 04/10] rust: Add missing SAFETY documentation for `ARef` example
From: Andreas Hindborg @ 2026-02-24 11:17 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg, Oliver Mangold
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

From: Oliver Mangold <oliver.mangold@pm.me>

SAFETY comment in rustdoc example was just 'TODO'. Fixed.

Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/sync/aref.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index 61caddfd89619..76deab0cb225e 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -134,7 +134,9 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
     ///
     /// struct Empty {}
     ///
-    /// # // SAFETY: TODO.
+    /// // SAFETY: The `RefCounted` implementation for `Empty` does not count references and never
+    /// // frees the underlying object. Thus we can act as owning an increment on the refcount for
+    /// // the object that we pass to the newly created `ARef`.
     /// unsafe impl RefCounted for Empty {
     ///     fn inc_ref(&self) {}
     ///     unsafe fn dec_ref(_obj: NonNull<Self>) {}
@@ -142,7 +144,7 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
     ///
     /// let mut data = Empty {};
     /// let ptr = NonNull::<Empty>::new(&mut data).unwrap();
-    /// # // SAFETY: TODO.
+    /// // SAFETY: We keep `data` around longer than the `ARef`.
     /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
     /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref);
     ///

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 02/10] rust: types: Add Ownable/Owned types
From: Andreas Hindborg @ 2026-02-24 11:17 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg, Asahi Lina, Oliver Mangold
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

From: Asahi Lina <lina+kernel@asahilina.net>

By analogy to `AlwaysRefCounted` and `ARef`, an `Ownable` type is a
(typically C FFI) type that *may* be owned by Rust, but need not be. Unlike
`AlwaysRefCounted`, this mechanism expects the reference to be unique
within Rust, and does not allow cloning.

Conceptually, this is similar to a `KBox<T>`, except that it delegates
resource management to the `T` instead of using a generic allocator.

[ om:
  - Split code into separate file and `pub use` it from types.rs.
  - Make from_raw() and into_raw() public.
  - Remove OwnableMut, and make DerefMut dependent on Unpin instead.
  - Usage example/doctest for Ownable/Owned.
  - Fixes to documentation and commit message.
]

Link: https://lore.kernel.org/all/20250202-rust-page-v1-1-e3170d7fe55e@asahilina.net/
Signed-off-by: Asahi Lina <lina+kernel@asahilina.net>
Co-developed-by: Oliver Mangold <oliver.mangold@pm.me>
Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
[ Andreas: Updated documentation, examples, and formatting. Change safety
  requirements, safety comments. Use a reference for `release`. ]
Reviewed-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/lib.rs       |   1 +
 rust/kernel/owned.rs     | 181 +++++++++++++++++++++++++++++++++++++++++++++++
 rust/kernel/sync/aref.rs |   5 ++
 rust/kernel/types.rs     |  11 ++-
 4 files changed, 197 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 696f62f85eb5f..a2bec807f03f1 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -121,6 +121,7 @@
 pub mod of;
 #[cfg(CONFIG_PM_OPP)]
 pub mod opp;
+pub mod owned;
 pub mod page;
 #[cfg(CONFIG_PCI)]
 pub mod pci;
diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
new file mode 100644
index 0000000000000..26bc325eee406
--- /dev/null
+++ b/rust/kernel/owned.rs
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Unique owned pointer types for objects with custom drop logic.
+//!
+//! These pointer types are useful for C-allocated objects which by API-contract
+//! are owned by Rust, but need to be freed through the C API.
+
+use core::{
+    mem::ManuallyDrop,
+    ops::{
+        Deref,
+        DerefMut, //
+    },
+    pin::Pin,
+    ptr::NonNull, //
+};
+
+/// Types that specify their own way of performing allocation and destruction. Typically, this trait
+/// is implemented on types from the C side.
+///
+/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type. This
+/// is useful when it is desirable to tie the lifetime of the reference to an owned object, rather
+/// than pass around a bare reference. [`Ownable`] types can define custom drop logic that is
+/// executed when the owned reference [`Owned<Self>`] pointing to the object is dropped.
+///
+/// Note: The underlying object is not required to provide internal reference counting, because it
+/// represents a unique, owned reference. If reference counting (on the Rust side) is required,
+/// [`AlwaysRefCounted`](crate::types::AlwaysRefCounted) should be implemented.
+///
+/// # Examples
+///
+/// A minimal example implementation of [`Ownable`] and its usage with [`Owned`] looks like
+/// this:
+///
+/// ```
+/// # #![expect(clippy::disallowed_names)]
+/// # use core::cell::Cell;
+/// # use core::ptr::NonNull;
+/// # use kernel::sync::global_lock;
+/// # use kernel::alloc::{flags, kbox::KBox, AllocError};
+/// # use kernel::types::{Owned, Ownable};
+///
+/// // Let's count the allocations to see if freeing works.
+/// kernel::sync::global_lock! {
+///     // SAFETY: we call `init()` right below, before doing anything else.
+///     unsafe(uninit) static FOO_ALLOC_COUNT: Mutex<usize> = 0;
+/// }
+/// // SAFETY: We call `init()` only once, here.
+/// unsafe { FOO_ALLOC_COUNT.init() };
+///
+/// struct Foo;
+///
+/// impl Foo {
+///     fn new() -> Result<Owned<Self>> {
+///         // We are just using a `KBox` here to handle the actual allocation, as our `Foo` is
+///         // not actually a C-allocated object.
+///         let result = KBox::new(
+///             Foo {},
+///             flags::GFP_KERNEL,
+///         )?;
+///         let result = KBox::into_nonnull(result);
+///         // Count new allocation
+///         *FOO_ALLOC_COUNT.lock() += 1;
+///         // SAFETY:
+///         //  - We just allocated the `Self`, thus it is valid and we own it.
+///         //  - We can transfer this ownership to the `from_raw` method.
+///         Ok(unsafe { Owned::from_raw(result) })
+///     }
+/// }
+///
+/// impl Ownable for Foo {
+///     unsafe fn release(&mut self) {
+///         // SAFETY: The [`KBox<Self>`] is still alive. We can pass ownership to the [`KBox`], as
+///         // by requirement on calling this function.
+///         drop(unsafe { KBox::from_raw(self) });
+///         // Count released allocation
+///         *FOO_ALLOC_COUNT.lock() -= 1;
+///     }
+/// }
+///
+/// {
+///    let foo = Foo::new()?;
+///    assert!(*FOO_ALLOC_COUNT.lock() == 1);
+/// }
+/// // `foo` is out of scope now, so we expect no live allocations.
+/// assert!(*FOO_ALLOC_COUNT.lock() == 0);
+/// # Ok::<(), Error>(())
+/// ```
+pub trait Ownable {
+    /// Tear down this `Ownable`.
+    ///
+    /// Implementers of `Ownable` can use this function to clean up the use of `Self`. This can
+    /// include freeing the underlying object.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that the caller has exclusive ownership of `T`, and this ownership can
+    /// be transferred to the `release` method.
+    unsafe fn release(&mut self);
+}
+
+/// A mutable reference to an owned `T`.
+///
+/// The [`Ownable`] is automatically freed or released when an instance of [`Owned`] is
+/// dropped.
+///
+/// # Invariants
+///
+/// - Until `T::release` is called, this `Owned<T>` exclusively owns the underlying `T`.
+/// - The `T` value is pinned.
+pub struct Owned<T: Ownable> {
+    ptr: NonNull<T>,
+}
+
+impl<T: Ownable> Owned<T> {
+    /// Creates a new instance of [`Owned`].
+    ///
+    /// This function takes over ownership of the underlying object.
+    ///
+    /// # Safety
+    ///
+    /// Callers must ensure that:
+    /// - `ptr` points to a valid instance of `T`.
+    /// - Until `T::release` is called, the returned `Owned<T>` exclusively owns the underlying `T`.
+    pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
+        // INVARIANT: By funvtion safety requirement we satisfy the first invariant of `Self`.
+        // We treat `T` as pinned from now on.
+        Self { ptr }
+    }
+
+    /// Consumes the [`Owned`], returning a raw pointer.
+    ///
+    /// This function does not drop the underlying `T`. When this function returns, ownership of the
+    /// underlying `T` is with the caller.
+    pub fn into_raw(me: Self) -> NonNull<T> {
+        ManuallyDrop::new(me).ptr
+    }
+
+    /// Get a pinned mutable reference to the data owned by this `Owned<T>`.
+    pub fn as_pin_mut(&mut self) -> Pin<&mut T> {
+        // SAFETY: The type invariants guarantee that the object is valid, and that we can safely
+        // return a mutable reference to it.
+        let unpinned = unsafe { self.ptr.as_mut() };
+
+        // SAFETY: By type invariant `T` is pinned.
+        unsafe { Pin::new_unchecked(unpinned) }
+    }
+}
+
+// SAFETY: It is safe to send an [`Owned<T>`] to another thread when the underlying `T` is [`Send`],
+// because of the ownership invariant. Sending an [`Owned<T>`] is equivalent to sending the `T`.
+unsafe impl<T: Ownable + Send> Send for Owned<T> {}
+
+// SAFETY: It is safe to send [`&Owned<T>`] to another thread when the underlying `T` is [`Sync`],
+// because of the ownership invariant. Sending an [`&Owned<T>`] is equivalent to sending the `&T`.
+unsafe impl<T: Ownable + Sync> Sync for Owned<T> {}
+
+impl<T: Ownable> Deref for Owned<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the object is valid.
+        unsafe { self.ptr.as_ref() }
+    }
+}
+
+impl<T: Ownable + Unpin> DerefMut for Owned<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        // SAFETY: The type invariants guarantee that the object is valid, and that we can safely
+        // return a mutable reference to it.
+        unsafe { self.ptr.as_mut() }
+    }
+}
+
+impl<T: Ownable> Drop for Owned<T> {
+    fn drop(&mut self) {
+        // SAFETY: By existence of `&mut self` we exclusively own `self` and the underlying `T`. As
+        // we are dropping `self`, we can transfer ownership of the `T` to the `release` method.
+        unsafe { T::release(self.ptr.as_mut()) };
+    }
+}
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index 0d24a0432015d..e175aefe86151 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -29,6 +29,11 @@
 /// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted
 /// instances of a type.
 ///
+/// Note: Implementing this trait allows types to be wrapped in an [`ARef<Self>`]. It requires an
+/// internal reference count and provides only shared references. If unique references are required
+/// [`Ownable`](crate::types::Ownable) should be implemented which allows types to be wrapped in an
+/// [`Owned<Self>`](crate::types::Owned).
+///
 /// # Safety
 ///
 /// Implementers must ensure that increments to the reference count keep the object alive in memory
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 9c5e7dbf16323..4aec7b699269a 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -11,7 +11,16 @@
 };
 use pin_init::{PinInit, Wrapper, Zeroable};
 
-pub use crate::sync::aref::{ARef, AlwaysRefCounted};
+pub use crate::{
+    owned::{
+        Ownable,
+        Owned, //
+    },
+    sync::aref::{
+        ARef,
+        AlwaysRefCounted, //
+    }, //
+};
 
 /// Used to transfer ownership to and from foreign (non-Rust) languages.
 ///

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 03/10] rust: rename `AlwaysRefCounted` to `RefCounted`.
From: Andreas Hindborg @ 2026-02-24 11:17 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg, Oliver Mangold, Viresh Kumar
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

From: Oliver Mangold <oliver.mangold@pm.me>

There are types where it may both be reference counted in some cases and
owned in others. In such cases, obtaining `ARef<T>` from `&T` would be
unsound as it allows creation of `ARef<T>` copy from `&Owned<T>`.

Therefore, we split `AlwaysRefCounted` into `RefCounted` (which `ARef<T>`
would require) and a marker trait to indicate that the type is always
reference counted (and not `Ownable`) so the `&T` -> `ARef<T>` conversion
is possible.

- Rename `AlwaysRefCounted` to `RefCounted`.
- Add a new unsafe trait `AlwaysRefCounted`.
- Implement the new trait `AlwaysRefCounted` for the newly renamed
  `RefCounted` implementations. This leaves functionality of existing
  implementers of `AlwaysRefCounted` intact.

Suggested-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com>
Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
[ Andreas: Updated commit message and rebase on rust-6.20-7.0 ]
Acked-by: Igor Korotin <igor.korotin.linux@gmail.com>
Acked-by: Danilo Krummrich <dakr@kernel.org>
Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/auxiliary.rs        |  7 +++++-
 rust/kernel/block/mq/request.rs | 15 +++++++------
 rust/kernel/cred.rs             | 13 ++++++++++--
 rust/kernel/device.rs           | 10 ++++++---
 rust/kernel/device/property.rs  |  7 +++++-
 rust/kernel/drm/device.rs       | 10 ++++++---
 rust/kernel/drm/gem/mod.rs      |  8 ++++---
 rust/kernel/fs/file.rs          | 16 ++++++++++----
 rust/kernel/i2c.rs              | 16 +++++++++-----
 rust/kernel/mm.rs               | 15 +++++++++----
 rust/kernel/mm/mmput_async.rs   |  9 ++++++--
 rust/kernel/opp.rs              | 10 ++++++---
 rust/kernel/owned.rs            |  2 +-
 rust/kernel/pci.rs              | 10 ++++++++-
 rust/kernel/pid_namespace.rs    | 12 +++++++++--
 rust/kernel/platform.rs         |  7 +++++-
 rust/kernel/sync/aref.rs        | 47 ++++++++++++++++++++++++++---------------
 rust/kernel/task.rs             | 10 ++++++---
 rust/kernel/types.rs            |  3 ++-
 rust/kernel/usb.rs              | 15 ++++++++++---
 20 files changed, 176 insertions(+), 66 deletions(-)

diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 56f3c180e8f69..234003341294f 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -11,6 +11,7 @@
     driver,
     error::{from_result, to_result, Result},
     prelude::*,
+    sync::aref::{AlwaysRefCounted, RefCounted},
     types::Opaque,
     ThisModule,
 };
@@ -258,7 +259,7 @@ unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx>
 kernel::impl_device_context_into_aref!(Device);
 
 // SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::get_device(self.as_ref().as_raw()) };
@@ -277,6 +278,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
 impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
     fn as_ref(&self) -> &device::Device<Ctx> {
         // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request.rs
index ce3e30c81cb5e..cf013b9e2cacf 100644
--- a/rust/kernel/block/mq/request.rs
+++ b/rust/kernel/block/mq/request.rs
@@ -9,7 +9,7 @@
     block::mq::Operations,
     error::Result,
     sync::{
-        aref::{ARef, AlwaysRefCounted},
+        aref::{ARef, AlwaysRefCounted, RefCounted},
         atomic::Relaxed,
         Refcount,
     },
@@ -229,11 +229,10 @@ unsafe impl<T: Operations> Send for Request<T> {}
 // mutate `self` are internally synchronized`
 unsafe impl<T: Operations> Sync for Request<T> {}
 
-// SAFETY: All instances of `Request<T>` are reference counted. This
-// implementation of `AlwaysRefCounted` ensure that increments to the ref count
-// keeps the object alive in memory at least until a matching reference count
-// decrement is executed.
-unsafe impl<T: Operations> AlwaysRefCounted for Request<T> {
+// SAFETY: All instances of `Request<T>` are reference counted. This implementation of `RefCounted`
+// ensure that increments to the ref count keeps the object alive in memory at least until a
+// matching reference count decrement is executed.
+unsafe impl<T: Operations> RefCounted for Request<T> {
     fn inc_ref(&self) {
         self.wrapper_ref().refcount().inc();
     }
@@ -255,3 +254,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull<Self>) {
         }
     }
 }
+
+// SAFETY: We currently do not implement `Ownable`, thus it is okay to obtain an `ARef<Request>`
+// from a `&Request` (but this will change in the future).
+unsafe impl<T: Operations> AlwaysRefCounted for Request<T> {}
diff --git a/rust/kernel/cred.rs b/rust/kernel/cred.rs
index ffa156b9df377..20ef0144094be 100644
--- a/rust/kernel/cred.rs
+++ b/rust/kernel/cred.rs
@@ -8,7 +8,12 @@
 //!
 //! Reference: <https://www.kernel.org/doc/html/latest/security/credentials.html>
 
-use crate::{bindings, sync::aref::AlwaysRefCounted, task::Kuid, types::Opaque};
+use crate::{
+    bindings,
+    sync::aref::RefCounted,
+    task::Kuid,
+    types::{AlwaysRefCounted, Opaque},
+};
 
 /// Wraps the kernel's `struct cred`.
 ///
@@ -76,7 +81,7 @@ pub fn euid(&self) -> Kuid {
 }
 
 // SAFETY: The type invariants guarantee that `Credential` is always ref-counted.
-unsafe impl AlwaysRefCounted for Credential {
+unsafe impl RefCounted for Credential {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -90,3 +95,7 @@ unsafe fn dec_ref(obj: core::ptr::NonNull<Credential>) {
         unsafe { bindings::put_cred(obj.cast().as_ptr()) };
     }
 }
+
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Credential>` from a
+// `&Credential`.
+unsafe impl AlwaysRefCounted for Credential {}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index 71b200df0f400..2a3bed19b9495 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -7,8 +7,8 @@
 use crate::{
     bindings, fmt,
     prelude::*,
-    sync::aref::ARef,
-    types::{ForeignOwnable, Opaque},
+    sync::aref::{ARef, RefCounted},
+    types::{AlwaysRefCounted, ForeignOwnable, Opaque},
 };
 use core::{any::TypeId, marker::PhantomData, ptr};
 
@@ -490,7 +490,7 @@ pub fn fwnode(&self) -> Option<&property::FwNode> {
 kernel::impl_device_context_into_aref!(Device);
 
 // SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::get_device(self.as_raw()) };
@@ -502,6 +502,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
 // SAFETY: As by the type invariant `Device` can be sent to any thread.
 unsafe impl Send for Device {}
 
diff --git a/rust/kernel/device/property.rs b/rust/kernel/device/property.rs
index 3a332a8c53a9e..a8bb824ad0ec1 100644
--- a/rust/kernel/device/property.rs
+++ b/rust/kernel/device/property.rs
@@ -14,6 +14,7 @@
     fmt,
     prelude::*,
     str::{CStr, CString},
+    sync::aref::{AlwaysRefCounted, RefCounted},
     types::{ARef, Opaque},
 };
 
@@ -359,7 +360,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 // SAFETY: Instances of `FwNode` are always reference-counted.
-unsafe impl crate::types::AlwaysRefCounted for FwNode {
+unsafe impl RefCounted for FwNode {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the
         // refcount is non-zero.
@@ -373,6 +374,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<FwNode>` from a
+// `&FwNode`.
+unsafe impl AlwaysRefCounted for FwNode {}
+
 enum Node<'a> {
     Borrowed(&'a FwNode),
     Owned(ARef<FwNode>),
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 3ce8f62a00569..38ce7f389ed00 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -11,8 +11,8 @@
     error::from_err_ptr,
     error::Result,
     prelude::*,
-    sync::aref::{ARef, AlwaysRefCounted},
-    types::Opaque,
+    sync::aref::{AlwaysRefCounted, RefCounted},
+    types::{ARef, Opaque},
 };
 use core::{alloc::Layout, mem, ops::Deref, ptr, ptr::NonNull};
 
@@ -198,7 +198,7 @@ fn deref(&self) -> &Self::Target {
 
 // SAFETY: DRM device objects are always reference counted and the get/put functions
 // satisfy the requirements.
-unsafe impl<T: drm::Driver> AlwaysRefCounted for Device<T> {
+unsafe impl<T: drm::Driver> RefCounted for Device<T> {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::drm_dev_get(self.as_raw()) };
@@ -213,6 +213,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl<T: drm::Driver> AlwaysRefCounted for Device<T> {}
+
 impl<T: drm::Driver> AsRef<device::Device> for Device<T> {
     fn as_ref(&self) -> &device::Device {
         // SAFETY: `bindings::drm_device::dev` is valid as long as the DRM device itself is valid,
diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs
index a7f682e95c018..ad6840a440165 100644
--- a/rust/kernel/drm/gem/mod.rs
+++ b/rust/kernel/drm/gem/mod.rs
@@ -10,8 +10,7 @@
     drm::driver::{AllocImpl, AllocOps},
     error::{to_result, Result},
     prelude::*,
-    sync::aref::{ARef, AlwaysRefCounted},
-    types::Opaque,
+    types::{ARef, AlwaysRefCounted, Opaque},
 };
 use core::{ops::Deref, ptr::NonNull};
 
@@ -253,7 +252,7 @@ extern "C" fn free_callback(obj: *mut bindings::drm_gem_object) {
 }
 
 // SAFETY: Instances of `Object<T>` are always reference-counted.
-unsafe impl<T: DriverObject> crate::types::AlwaysRefCounted for Object<T> {
+unsafe impl<T: DriverObject> crate::types::RefCounted for Object<T> {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::drm_gem_object_get(self.as_raw()) };
@@ -267,6 +266,9 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
         unsafe { bindings::drm_gem_object_put(obj.as_raw()) }
     }
 }
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Object`.
+unsafe impl<T: DriverObject> crate::types::AlwaysRefCounted for Object<T> {}
 
 impl<T: DriverObject> super::private::Sealed for Object<T> {}
 
diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index 23ee689bd2400..06e457d62a939 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -12,8 +12,8 @@
     cred::Credential,
     error::{code::*, to_result, Error, Result},
     fmt,
-    sync::aref::{ARef, AlwaysRefCounted},
-    types::{NotThreadSafe, Opaque},
+    sync::aref::RefCounted,
+    types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque},
 };
 use core::ptr;
 
@@ -197,7 +197,7 @@ unsafe impl Sync for File {}
 
 // SAFETY: The type invariants guarantee that `File` is always ref-counted. This implementation
 // makes `ARef<File>` own a normal refcount.
-unsafe impl AlwaysRefCounted for File {
+unsafe impl RefCounted for File {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -212,6 +212,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<File>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<File>` from a
+// `&File`.
+unsafe impl AlwaysRefCounted for File {}
+
 /// Wraps the kernel's `struct file`. Not thread safe.
 ///
 /// This type represents a file that is not known to be safe to transfer across thread boundaries.
@@ -233,7 +237,7 @@ pub struct LocalFile {
 
 // SAFETY: The type invariants guarantee that `LocalFile` is always ref-counted. This implementation
 // makes `ARef<LocalFile>` own a normal refcount.
-unsafe impl AlwaysRefCounted for LocalFile {
+unsafe impl RefCounted for LocalFile {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -249,6 +253,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<LocalFile>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<LocalFile>` from a
+// `&LocalFile`.
+unsafe impl AlwaysRefCounted for LocalFile {}
+
 impl LocalFile {
     /// Constructs a new `struct file` wrapper from a file descriptor.
     ///
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 792a71b154630..683950057423d 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -17,8 +17,10 @@
     of,
     prelude::*,
     types::{
+        ARef,
         AlwaysRefCounted,
-        Opaque, //
+        Opaque,
+        RefCounted, //
     }, //
 };
 
@@ -31,8 +33,6 @@
     }, //
 };
 
-use kernel::types::ARef;
-
 /// An I2C device id table.
 #[repr(transparent)]
 #[derive(Clone, Copy)]
@@ -407,7 +407,7 @@ pub fn get(index: i32) -> Result<ARef<Self>> {
 kernel::impl_device_context_into_aref!(I2cAdapter);
 
 // SAFETY: Instances of `I2cAdapter` are always reference-counted.
-unsafe impl crate::types::AlwaysRefCounted for I2cAdapter {
+unsafe impl crate::types::RefCounted for I2cAdapter {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::i2c_get_adapter(self.index()) };
@@ -418,6 +418,9 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
         unsafe { bindings::i2c_put_adapter(obj.as_ref().as_raw()) }
     }
 }
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from an
+// `&I2cAdapter`.
+unsafe impl AlwaysRefCounted for I2cAdapter {}
 
 /// The i2c board info representation
 ///
@@ -483,7 +486,7 @@ unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for I2cClient<C
 kernel::impl_device_context_into_aref!(I2cClient);
 
 // SAFETY: Instances of `I2cClient` are always reference-counted.
-unsafe impl AlwaysRefCounted for I2cClient {
+unsafe impl RefCounted for I2cClient {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::get_device(self.as_ref().as_raw()) };
@@ -494,6 +497,9 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
         unsafe { bindings::put_device(&raw mut (*obj.as_ref().as_raw()).dev) }
     }
 }
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from an
+// `&I2cClient`.
+unsafe impl AlwaysRefCounted for I2cClient {}
 
 impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for I2cClient<Ctx> {
     fn as_ref(&self) -> &device::Device<Ctx> {
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
index 4764d7b68f2a7..dd9e3969e7206 100644
--- a/rust/kernel/mm.rs
+++ b/rust/kernel/mm.rs
@@ -13,8 +13,8 @@
 
 use crate::{
     bindings,
-    sync::aref::{ARef, AlwaysRefCounted},
-    types::{NotThreadSafe, Opaque},
+    sync::aref::RefCounted,
+    types::{ARef, AlwaysRefCounted, NotThreadSafe, Opaque},
 };
 use core::{ops::Deref, ptr::NonNull};
 
@@ -55,7 +55,7 @@ unsafe impl Send for Mm {}
 unsafe impl Sync for Mm {}
 
 // SAFETY: By the type invariants, this type is always refcounted.
-unsafe impl AlwaysRefCounted for Mm {
+unsafe impl RefCounted for Mm {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The pointer is valid since self is a reference.
@@ -69,6 +69,9 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Mm>` from a `&Mm`.
+unsafe impl AlwaysRefCounted for Mm {}
+
 /// A wrapper for the kernel's `struct mm_struct`.
 ///
 /// This type is like [`Mm`], but with non-zero `mm_users`. It can only be used when `mm_users` can
@@ -91,7 +94,7 @@ unsafe impl Send for MmWithUser {}
 unsafe impl Sync for MmWithUser {}
 
 // SAFETY: By the type invariants, this type is always refcounted.
-unsafe impl AlwaysRefCounted for MmWithUser {
+unsafe impl RefCounted for MmWithUser {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The pointer is valid since self is a reference.
@@ -105,6 +108,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<MmWithUser>` from a
+// `&MmWithUser`.
+unsafe impl AlwaysRefCounted for MmWithUser {}
+
 // Make all `Mm` methods available on `MmWithUser`.
 impl Deref for MmWithUser {
     type Target = Mm;
diff --git a/rust/kernel/mm/mmput_async.rs b/rust/kernel/mm/mmput_async.rs
index b8d2f051225c7..aba4ce675c860 100644
--- a/rust/kernel/mm/mmput_async.rs
+++ b/rust/kernel/mm/mmput_async.rs
@@ -10,7 +10,8 @@
 use crate::{
     bindings,
     mm::MmWithUser,
-    sync::aref::{ARef, AlwaysRefCounted},
+    sync::aref::RefCounted,
+    types::{ARef, AlwaysRefCounted},
 };
 use core::{ops::Deref, ptr::NonNull};
 
@@ -34,7 +35,7 @@ unsafe impl Send for MmWithUserAsync {}
 unsafe impl Sync for MmWithUserAsync {}
 
 // SAFETY: By the type invariants, this type is always refcounted.
-unsafe impl AlwaysRefCounted for MmWithUserAsync {
+unsafe impl RefCounted for MmWithUserAsync {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The pointer is valid since self is a reference.
@@ -48,6 +49,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<MmWithUserAsync>`
+// from a `&MmWithUserAsync`.
+unsafe impl AlwaysRefCounted for MmWithUserAsync {}
+
 // Make all `MmWithUser` methods available on `MmWithUserAsync`.
 impl Deref for MmWithUserAsync {
     type Target = MmWithUser;
diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
index a760fac287655..06fe2ca776a4f 100644
--- a/rust/kernel/opp.rs
+++ b/rust/kernel/opp.rs
@@ -16,8 +16,8 @@
     ffi::{c_char, c_ulong},
     prelude::*,
     str::CString,
-    sync::aref::{ARef, AlwaysRefCounted},
-    types::Opaque,
+    sync::aref::RefCounted,
+    types::{ARef, AlwaysRefCounted, Opaque},
 };
 
 #[cfg(CONFIG_CPU_FREQ)]
@@ -1041,7 +1041,7 @@ unsafe impl Send for OPP {}
 unsafe impl Sync for OPP {}
 
 /// SAFETY: The type invariants guarantee that [`OPP`] is always refcounted.
-unsafe impl AlwaysRefCounted for OPP {
+unsafe impl RefCounted for OPP {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
         unsafe { bindings::dev_pm_opp_get(self.0.get()) };
@@ -1053,6 +1053,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<OPP>` from an
+// `&OPP`.
+unsafe impl AlwaysRefCounted for OPP {}
+
 impl OPP {
     /// Creates an owned reference to a [`OPP`] from a valid pointer.
     ///
diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
index 26bc325eee406..41451aa320cff 100644
--- a/rust/kernel/owned.rs
+++ b/rust/kernel/owned.rs
@@ -25,7 +25,7 @@
 ///
 /// Note: The underlying object is not required to provide internal reference counting, because it
 /// represents a unique, owned reference. If reference counting (on the Rust side) is required,
-/// [`AlwaysRefCounted`](crate::types::AlwaysRefCounted) should be implemented.
+/// [`RefCounted`](crate::types::RefCounted) should be implemented.
 ///
 /// # Examples
 ///
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 82e128431f080..a73551dedee8f 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -19,6 +19,10 @@
     },
     prelude::*,
     str::CStr,
+    sync::aref::{
+        AlwaysRefCounted,
+        RefCounted, //
+    },
     types::Opaque,
     ThisModule, //
 };
@@ -458,7 +462,7 @@ unsafe impl<Ctx: device::DeviceContext> device::AsBusDevice<Ctx> for Device<Ctx>
 impl crate::dma::Device for Device<device::Core> {}
 
 // SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::pci_dev_get(self.as_raw()) };
@@ -470,6 +474,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
 impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
     fn as_ref(&self) -> &device::Device<Ctx> {
         // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
diff --git a/rust/kernel/pid_namespace.rs b/rust/kernel/pid_namespace.rs
index 979a9718f153d..4f6a94540e33d 100644
--- a/rust/kernel/pid_namespace.rs
+++ b/rust/kernel/pid_namespace.rs
@@ -7,7 +7,11 @@
 //! C header: [`include/linux/pid_namespace.h`](srctree/include/linux/pid_namespace.h) and
 //! [`include/linux/pid.h`](srctree/include/linux/pid.h)
 
-use crate::{bindings, sync::aref::AlwaysRefCounted, types::Opaque};
+use crate::{
+    bindings,
+    sync::aref::RefCounted,
+    types::{AlwaysRefCounted, Opaque},
+};
 use core::ptr;
 
 /// Wraps the kernel's `struct pid_namespace`. Thread safe.
@@ -41,7 +45,7 @@ pub unsafe fn from_ptr<'a>(ptr: *const bindings::pid_namespace) -> &'a Self {
 }
 
 // SAFETY: Instances of `PidNamespace` are always reference-counted.
-unsafe impl AlwaysRefCounted for PidNamespace {
+unsafe impl RefCounted for PidNamespace {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -55,6 +59,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<PidNamespace>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<PidNamespace>` from
+// a `&PidNamespace`.
+unsafe impl AlwaysRefCounted for PidNamespace {}
+
 // SAFETY:
 // - `PidNamespace::dec_ref` can be called from any thread.
 // - It is okay to send ownership of `PidNamespace` across thread boundaries.
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index ed889f079cab6..9f1cd0b8fb0bc 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -13,6 +13,7 @@
     irq::{self, IrqRequest},
     of,
     prelude::*,
+    sync::aref::{AlwaysRefCounted, RefCounted},
     types::Opaque,
     ThisModule,
 };
@@ -481,7 +482,7 @@ pub fn optional_irq_by_name(&self, name: &CStr) -> Result<IrqRequest<'_>> {
 impl crate::dma::Device for Device<device::Core> {}
 
 // SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
         unsafe { bindings::get_device(self.as_ref().as_raw()) };
@@ -493,6 +494,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
 impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
     fn as_ref(&self) -> &device::Device<Ctx> {
         // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index e175aefe86151..61caddfd89619 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -19,11 +19,9 @@
 
 use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
 
-/// Types that are _always_ reference counted.
+/// Types that are internally reference counted.
 ///
 /// It allows such types to define their own custom ref increment and decrement functions.
-/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
-/// [`ARef<T>`].
 ///
 /// This is usually implemented by wrappers to existing structures on the C side of the code. For
 /// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted
@@ -40,9 +38,8 @@
 /// at least until matching decrements are performed.
 ///
 /// Implementers must also ensure that all instances are reference-counted. (Otherwise they
-/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
-/// alive.)
-pub unsafe trait AlwaysRefCounted {
+/// won't be able to honour the requirement that [`RefCounted::inc_ref`] keep the object alive.)
+pub unsafe trait RefCounted {
     /// Increments the reference count on the object.
     fn inc_ref(&self);
 
@@ -55,11 +52,27 @@ pub unsafe trait AlwaysRefCounted {
     /// Callers must ensure that there was a previous matching increment to the reference count,
     /// and that the object is no longer used after its reference count is decremented (as it may
     /// result in the object being freed), unless the caller owns another increment on the refcount
-    /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
-    /// [`AlwaysRefCounted::dec_ref`] once).
+    /// (e.g., it calls [`RefCounted::inc_ref`] twice, then calls [`RefCounted::dec_ref`] once).
     unsafe fn dec_ref(obj: NonNull<Self>);
 }
 
+/// Always reference-counted type.
+///
+/// It allows deriving a counted reference [`ARef<T>`] from a `&T`.
+///
+/// This provides some convenience, but it allows "escaping" borrow checks on `&T`. As it
+/// complicates attempts to ensure that a reference to T is unique, it is optional to provide for
+/// [`RefCounted`] types. See *Safety* below.
+///
+/// # Safety
+///
+/// Implementers must ensure that no safety invariants are violated by upgrading an `&T` to an
+/// [`ARef<T>`]. In particular that implies [`AlwaysRefCounted`] and [`crate::types::Ownable`]
+/// cannot be implemented for the same type, as this would allow violating the uniqueness guarantee
+/// of [`crate::types::Owned<T>`] by dereferencing it into an `&T` and obtaining an [`ARef`] from
+/// that.
+pub unsafe trait AlwaysRefCounted: RefCounted {}
+
 /// An owned reference to an always-reference-counted object.
 ///
 /// The object's reference count is automatically decremented when an instance of [`ARef`] is
@@ -70,7 +83,7 @@ pub unsafe trait AlwaysRefCounted {
 ///
 /// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
 /// particular, the [`ARef`] instance owns an increment on the underlying object's reference count.
-pub struct ARef<T: AlwaysRefCounted> {
+pub struct ARef<T: RefCounted> {
     ptr: NonNull<T>,
     _p: PhantomData<T>,
 }
@@ -79,16 +92,16 @@ pub struct ARef<T: AlwaysRefCounted> {
 // it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
 // `T` to be `Send` because any thread that has an `ARef<T>` may ultimately access `T` using a
 // mutable reference, for example, when the reference count reaches zero and `T` is dropped.
-unsafe impl<T: AlwaysRefCounted + Sync + Send> Send for ARef<T> {}
+unsafe impl<T: RefCounted + Sync + Send> Send for ARef<T> {}
 
 // SAFETY: It is safe to send `&ARef<T>` to another thread when the underlying `T` is `Sync`
 // because it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally,
 // it needs `T` to be `Send` because any thread that has a `&ARef<T>` may clone it and get an
 // `ARef<T>` on that thread, so the thread may ultimately access `T` using a mutable reference, for
 // example, when the reference count reaches zero and `T` is dropped.
-unsafe impl<T: AlwaysRefCounted + Sync + Send> Sync for ARef<T> {}
+unsafe impl<T: RefCounted + Sync + Send> Sync for ARef<T> {}
 
-impl<T: AlwaysRefCounted> ARef<T> {
+impl<T: RefCounted> ARef<T> {
     /// Creates a new instance of [`ARef`].
     ///
     /// It takes over an increment of the reference count on the underlying object.
@@ -117,12 +130,12 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
     ///
     /// ```
     /// use core::ptr::NonNull;
-    /// use kernel::sync::aref::{ARef, AlwaysRefCounted};
+    /// use kernel::sync::aref::{ARef, RefCounted};
     ///
     /// struct Empty {}
     ///
     /// # // SAFETY: TODO.
-    /// unsafe impl AlwaysRefCounted for Empty {
+    /// unsafe impl RefCounted for Empty {
     ///     fn inc_ref(&self) {}
     ///     unsafe fn dec_ref(_obj: NonNull<Self>) {}
     /// }
@@ -140,7 +153,7 @@ pub fn into_raw(me: Self) -> NonNull<T> {
     }
 }
 
-impl<T: AlwaysRefCounted> Clone for ARef<T> {
+impl<T: RefCounted> Clone for ARef<T> {
     fn clone(&self) -> Self {
         self.inc_ref();
         // SAFETY: We just incremented the refcount above.
@@ -148,7 +161,7 @@ fn clone(&self) -> Self {
     }
 }
 
-impl<T: AlwaysRefCounted> Deref for ARef<T> {
+impl<T: RefCounted> Deref for ARef<T> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -165,7 +178,7 @@ fn from(b: &T) -> Self {
     }
 }
 
-impl<T: AlwaysRefCounted> Drop for ARef<T> {
+impl<T: RefCounted> Drop for ARef<T> {
     fn drop(&mut self) {
         // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
         // decrement.
diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
index 49fad6de06740..0a6e38d984560 100644
--- a/rust/kernel/task.rs
+++ b/rust/kernel/task.rs
@@ -9,8 +9,8 @@
     ffi::{c_int, c_long, c_uint},
     mm::MmWithUser,
     pid_namespace::PidNamespace,
-    sync::aref::ARef,
-    types::{NotThreadSafe, Opaque},
+    sync::aref::{AlwaysRefCounted, RefCounted},
+    types::{ARef, NotThreadSafe, Opaque},
 };
 use core::{
     cmp::{Eq, PartialEq},
@@ -348,7 +348,7 @@ pub fn active_pid_ns(&self) -> Option<&PidNamespace> {
 }
 
 // SAFETY: The type invariants guarantee that `Task` is always refcounted.
-unsafe impl crate::sync::aref::AlwaysRefCounted for Task {
+unsafe impl RefCounted for Task {
     #[inline]
     fn inc_ref(&self) {
         // SAFETY: The existence of a shared reference means that the refcount is nonzero.
@@ -362,6 +362,10 @@ unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Task>` from a
+// `&Task`.
+unsafe impl AlwaysRefCounted for Task {}
+
 impl Kuid {
     /// Get the current euid.
     #[inline]
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 4aec7b699269a..9b96aa2ebdb7e 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -18,7 +18,8 @@
     },
     sync::aref::{
         ARef,
-        AlwaysRefCounted, //
+        AlwaysRefCounted,
+        RefCounted, //
     }, //
 };
 
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index d10b65e9fb6ad..089823b608333 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -12,7 +12,8 @@
     error::{from_result, to_result, Result},
     prelude::*,
     str::CStr,
-    types::{AlwaysRefCounted, Opaque},
+    sync::aref::{AlwaysRefCounted, RefCounted},
+    types::Opaque,
     ThisModule,
 };
 use core::{
@@ -365,7 +366,7 @@ fn as_ref(&self) -> &Device {
 }
 
 // SAFETY: Instances of `Interface` are always reference-counted.
-unsafe impl AlwaysRefCounted for Interface {
+unsafe impl RefCounted for Interface {
     fn inc_ref(&self) {
         // SAFETY: The invariants of `Interface` guarantee that `self.as_raw()`
         // returns a valid `struct usb_interface` pointer, for which we will
@@ -379,6 +380,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Interface>` from a
+// `&Interface`.
+unsafe impl AlwaysRefCounted for Interface {}
+
 // SAFETY: A `Interface` is always reference-counted and can be released from any thread.
 unsafe impl Send for Interface {}
 
@@ -416,7 +421,7 @@ fn as_raw(&self) -> *mut bindings::usb_device {
 kernel::impl_device_context_into_aref!(Device);
 
 // SAFETY: Instances of `Device` are always reference-counted.
-unsafe impl AlwaysRefCounted for Device {
+unsafe impl RefCounted for Device {
     fn inc_ref(&self) {
         // SAFETY: The invariants of `Device` guarantee that `self.as_raw()`
         // returns a valid `struct usb_device` pointer, for which we will
@@ -430,6 +435,10 @@ unsafe fn dec_ref(obj: NonNull<Self>) {
     }
 }
 
+// SAFETY: We do not implement `Ownable`, thus it is okay to obtain an `ARef<Device>` from a
+// `&Device`.
+unsafe impl AlwaysRefCounted for Device {}
+
 impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
     fn as_ref(&self) -> &device::Device<Ctx> {
         // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 09/10] rust: implement `ForeignOwnable` for `Owned`
From: Andreas Hindborg @ 2026-02-24 11:18 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

Implement `ForeignOwnable` for `Owned<T>`. This allows use of `Owned<T>` in
places such as the `XArray`.

Note that `T` does not need to implement `ForeignOwnable` for `Owned<T>` to
implement `ForeignOwnable`.

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/owned.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
index c81c2ea88124b..505ac2200d2d6 100644
--- a/rust/kernel/owned.rs
+++ b/rust/kernel/owned.rs
@@ -16,7 +16,10 @@
 };
 use kernel::{
     sync::aref::ARef,
-    types::RefCounted, //
+    types::{
+        ForeignOwnable, //
+        RefCounted,
+    }, //
 };
 
 /// Types that specify their own way of performing allocation and destruction. Typically, this trait
@@ -114,6 +117,7 @@ pub trait Ownable {
 ///
 /// - Until `T::release` is called, this `Owned<T>` exclusively owns the underlying `T`.
 /// - The `T` value is pinned.
+#[repr(transparent)]
 pub struct Owned<T: Ownable> {
     ptr: NonNull<T>,
 }
@@ -186,6 +190,45 @@ fn drop(&mut self) {
     }
 }
 
+// SAFETY: We derive the pointer to `T` from a valid `T`, so the returned
+// pointer satisfy alignment requirements of `T`.
+unsafe impl<T: Ownable + 'static> ForeignOwnable for Owned<T> {
+    const FOREIGN_ALIGN: usize = core::mem::align_of::<Owned<T>>();
+
+    type Borrowed<'a> = &'a T;
+    type BorrowedMut<'a> = Pin<&'a mut T>;
+
+    fn into_foreign(self) -> *mut kernel::ffi::c_void {
+        let ptr = self.ptr.as_ptr().cast();
+        core::mem::forget(self);
+        ptr
+    }
+
+    unsafe fn from_foreign(ptr: *mut kernel::ffi::c_void) -> Self {
+        Self {
+            // SAFETY: By function safety contract, `ptr` came from
+            // `into_foreign` and cannot be null.
+            ptr: unsafe { NonNull::new_unchecked(ptr.cast()) },
+        }
+    }
+
+    unsafe fn borrow<'a>(ptr: *mut kernel::ffi::c_void) -> Self::Borrowed<'a> {
+        // SAFETY: By function safety requirements, `ptr` is valid for use as a
+        // reference for `'a`.
+        unsafe { &*ptr.cast() }
+    }
+
+    unsafe fn borrow_mut<'a>(ptr: *mut kernel::ffi::c_void) -> Self::BorrowedMut<'a> {
+        // SAFETY: By function safety requirements, `ptr` is valid for use as a
+        // unique reference for `'a`.
+        let inner = unsafe { &mut *ptr.cast() };
+
+        // SAFETY: We never move out of inner, and we do not hand out mutable
+        // references when `T: !Unpin`.
+        unsafe { Pin::new_unchecked(inner) }
+    }
+}
+
 /// A trait for objects that can be wrapped in either one of the reference types [`Owned`] and
 /// [`ARef`].
 ///

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 05/10] rust: aref: update formatting of use statements
From: Andreas Hindborg @ 2026-02-24 11:18 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

Update formatting if use statements in preparation for next commit.

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/sync/aref.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index 76deab0cb225e..8c23662a7e6a1 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -17,7 +17,12 @@
 //! [`Arc`]: crate::sync::Arc
 //! [`Arc<T>`]: crate::sync::Arc
 
-use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
+use core::{
+    marker::PhantomData,
+    mem::ManuallyDrop,
+    ops::Deref,
+    ptr::NonNull, //
+};
 
 /// Types that are internally reference counted.
 ///

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 06/10] rust: Add `OwnableRefCounted`
From: Andreas Hindborg @ 2026-02-24 11:18 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg, Oliver Mangold
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

From: Oliver Mangold <oliver.mangold@pm.me>

Types implementing one of these traits can safely convert between an
`ARef<T>` and an `Owned<T>`.

This is useful for types which generally are accessed through an `ARef`
but have methods which can only safely be called when the reference is
unique, like e.g. `block::mq::Request::end_ok()`.

Signed-off-by: Oliver Mangold <oliver.mangold@pm.me>
[ Andreas: Fix formatting, update documentation, fix error handling in
  examples. ]
Co-developed-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/owned.rs     | 136 +++++++++++++++++++++++++++++++++++++++++++++--
 rust/kernel/sync/aref.rs |  15 +++++-
 rust/kernel/types.rs     |   1 +
 3 files changed, 146 insertions(+), 6 deletions(-)

diff --git a/rust/kernel/owned.rs b/rust/kernel/owned.rs
index 41451aa320cff..c81c2ea88124b 100644
--- a/rust/kernel/owned.rs
+++ b/rust/kernel/owned.rs
@@ -14,18 +14,24 @@
     pin::Pin,
     ptr::NonNull, //
 };
+use kernel::{
+    sync::aref::ARef,
+    types::RefCounted, //
+};
 
 /// Types that specify their own way of performing allocation and destruction. Typically, this trait
 /// is implemented on types from the C side.
 ///
-/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type. This
-/// is useful when it is desirable to tie the lifetime of the reference to an owned object, rather
-/// than pass around a bare reference. [`Ownable`] types can define custom drop logic that is
-/// executed when the owned reference [`Owned<Self>`] pointing to the object is dropped.
+/// Implementing this trait allows types to be referenced via the [`Owned<Self>`] pointer type.
+///  - This is useful when it is desirable to tie the lifetime of an object reference to an owned
+///    object, rather than pass around a bare reference.
+///  - [`Ownable`] types can define custom drop logic that is executed when the owned reference
+///    of type [`Owned<_>`] pointing to the object is dropped.
 ///
 /// Note: The underlying object is not required to provide internal reference counting, because it
 /// represents a unique, owned reference. If reference counting (on the Rust side) is required,
-/// [`RefCounted`](crate::types::RefCounted) should be implemented.
+/// [`RefCounted`] should be implemented. [`OwnableRefCounted`] should be implemented if conversion
+/// between unique and shared (reference counted) ownership is needed.
 ///
 /// # Examples
 ///
@@ -179,3 +185,123 @@ fn drop(&mut self) {
         unsafe { T::release(self.ptr.as_mut()) };
     }
 }
+
+/// A trait for objects that can be wrapped in either one of the reference types [`Owned`] and
+/// [`ARef`].
+///
+/// # Examples
+///
+/// A minimal example implementation of [`OwnableRefCounted`], [`Ownable`] and its usage with
+/// [`ARef`] and [`Owned`] looks like this:
+///
+/// ```
+/// # #![expect(clippy::disallowed_names)]
+/// # use core::cell::Cell;
+/// # use core::ptr::NonNull;
+/// # use kernel::alloc::{flags, kbox::KBox, AllocError};
+/// # use kernel::sync::aref::{ARef, RefCounted};
+/// # use kernel::types::{Owned, Ownable, OwnableRefCounted};
+///
+/// // An internally refcounted struct for demonstration purposes.
+/// //
+/// // # Invariants
+/// //
+/// // - `refcount` is always non-zero for a valid object.
+/// // - `refcount` is >1 if there is more than one Rust reference to it.
+/// //
+/// struct Foo {
+///     refcount: Cell<usize>,
+/// }
+///
+/// impl Foo {
+///     fn new() -> Result<Owned<Self>> {
+///         // We are just using a `KBox` here to handle the actual allocation, as our `Foo` is
+///         // not actually a C-allocated object.
+///         let result = KBox::new(
+///             Foo {
+///                 refcount: Cell::new(1),
+///             },
+///             flags::GFP_KERNEL,
+///         )?;
+///         let result = KBox::into_nonnull(result);
+///         // SAFETY:
+///         //  - We just allocated the `Self`, thus it is valid and we own it.
+///         //  - We can transfer this ownership to the `from_raw` method.
+///         Ok(unsafe { Owned::from_raw(result) })
+///     }
+/// }
+///
+/// // SAFETY: We increment and decrement each time the respective function is called and only free
+/// // the `Foo` when the refcount reaches zero.
+/// unsafe impl RefCounted for Foo {
+///     fn inc_ref(&self) {
+///         self.refcount.replace(self.refcount.get() + 1);
+///     }
+///
+///     unsafe fn dec_ref(this: NonNull<Self>) {
+///         // SAFETY: By requirement on calling this function, the refcount is non-zero,
+///         // implying the underlying object is valid.
+///         let refcount = unsafe { &this.as_ref().refcount };
+///         let new_refcount = refcount.get() - 1;
+///         if new_refcount == 0 {
+///             // The `Foo` will be dropped when `KBox` goes out of scope.
+///             // SAFETY: The [`KBox<Foo>`] is still alive as the old refcount is 1. We can pass
+///             // ownership to the [`KBox`] as by requirement on calling this function,
+///             // the `Self` will no longer be used by the caller.
+///             unsafe { KBox::from_raw(this.as_ptr()) };
+///         } else {
+///             refcount.replace(new_refcount);
+///         }
+///     }
+/// }
+///
+/// impl OwnableRefCounted for Foo {
+///     fn try_from_shared(this: ARef<Self>) -> Result<Owned<Self>, ARef<Self>> {
+///         if this.refcount.get() == 1 {
+///             // SAFETY: The `Foo` is still alive and has no other Rust references as the refcount
+///             // is 1.
+///             Ok(unsafe { Owned::from_raw(ARef::into_raw(this)) })
+///         } else {
+///             Err(this)
+///         }
+///     }
+/// }
+///
+/// impl Ownable for Foo {
+///     unsafe fn release(&mut self) {
+///         // SAFETY: Using `dec_ref()` from [`RefCounted`] to release is okay, as the refcount is
+///         // always 1 for an [`Owned<Foo>`].
+///         unsafe{ Foo::dec_ref(NonNull::new_unchecked(self)) };
+///     }
+/// }
+///
+/// let foo = Foo::new()?;
+/// let mut foo = ARef::from(foo);
+/// {
+///     let bar = foo.clone();
+///     assert!(Owned::try_from(bar).is_err());
+/// }
+/// assert!(Owned::try_from(foo).is_ok());
+/// # Ok::<(), Error>(())
+/// ```
+pub trait OwnableRefCounted: RefCounted + Ownable + Sized {
+    /// Checks if the [`ARef`] is unique and converts it to an [`Owned`] if that is the case.
+    /// Otherwise it returns again an [`ARef`] to the same underlying object.
+    fn try_from_shared(this: ARef<Self>) -> Result<Owned<Self>, ARef<Self>>;
+
+    /// Converts the [`Owned`] into an [`ARef`].
+    fn into_shared(this: Owned<Self>) -> ARef<Self> {
+        // SAFETY: Safe by the requirements on implementing the trait.
+        unsafe { ARef::from_raw(Owned::into_raw(this)) }
+    }
+}
+
+impl<T: OwnableRefCounted> TryFrom<ARef<T>> for Owned<T> {
+    type Error = ARef<T>;
+    /// Tries to convert the [`ARef`] to an [`Owned`] by calling
+    /// [`try_from_shared()`](OwnableRefCounted::try_from_shared). In case the [`ARef`] is not
+    /// unique, it returns again an [`ARef`] to the same underlying object.
+    fn try_from(b: ARef<T>) -> Result<Owned<T>, Self::Error> {
+        T::try_from_shared(b)
+    }
+}
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
index 8c23662a7e6a1..a849ebae4313b 100644
--- a/rust/kernel/sync/aref.rs
+++ b/rust/kernel/sync/aref.rs
@@ -23,6 +23,10 @@
     ops::Deref,
     ptr::NonNull, //
 };
+use kernel::types::{
+    OwnableRefCounted,
+    Owned, //
+};
 
 /// Types that are internally reference counted.
 ///
@@ -35,7 +39,10 @@
 /// Note: Implementing this trait allows types to be wrapped in an [`ARef<Self>`]. It requires an
 /// internal reference count and provides only shared references. If unique references are required
 /// [`Ownable`](crate::types::Ownable) should be implemented which allows types to be wrapped in an
-/// [`Owned<Self>`](crate::types::Owned).
+/// [`Owned<Self>`](crate::types::Owned). Implementing the trait
+/// [`OwnableRefCounted`] allows to convert between unique and
+/// shared references (i.e. [`Owned<Self>`](crate::types::Owned) and
+/// [`ARef<Self>`](crate::types::Owned)).
 ///
 /// # Safety
 ///
@@ -185,6 +192,12 @@ fn from(b: &T) -> Self {
     }
 }
 
+impl<T: OwnableRefCounted> From<Owned<T>> for ARef<T> {
+    fn from(b: Owned<T>) -> Self {
+        T::into_shared(b)
+    }
+}
+
 impl<T: RefCounted> Drop for ARef<T> {
     fn drop(&mut self) {
         // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 9b96aa2ebdb7e..f43c091eeb8b7 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -14,6 +14,7 @@
 pub use crate::{
     owned::{
         Ownable,
+        OwnableRefCounted,
         Owned, //
     },
     sync::aref::{

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 10/10] rust: page: add `from_raw()`
From: Andreas Hindborg @ 2026-02-24 11:18 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg, Andreas Hindborg
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

Add a method to `Page` that allows construction of an instance from `struct
page` pointer.

Signed-off-by: Andreas Hindborg <a.hindborg@samsung.com>
---
 rust/kernel/page.rs | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index e21f02ae47b72..96f1ec125f043 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -192,6 +192,17 @@ pub fn nid(&self) -> i32 {
         unsafe { bindings::page_to_nid(self.as_ptr()) }
     }
 
+    /// Create a `&Page` from a raw `struct page` pointer.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must be convertible to a shared reference with a lifetime of `'a`.
+    pub unsafe fn from_raw<'a>(ptr: *const bindings::page) -> &'a Self {
+        // SAFETY: By function safety requirements, `ptr` is not null and is convertible to a shared
+        // reference.
+        unsafe { &*ptr.cast() }
+    }
+
     /// Runs a piece of code with this page mapped to an address.
     ///
     /// The page is unmapped when this call returns.

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 08/10] rust: page: convert to `Ownable`
From: Andreas Hindborg @ 2026-02-24 11:18 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg, Asahi Lina, Asahi Lina
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

From: Asahi Lina <lina+kernel@asahilina.net>

This allows Page references to be returned as borrowed references,
without necessarily owning the struct page.

Signed-off-by: Asahi Lina <lina@asahilina.net>
[ Andreas: Fix formatting and add a safety comment. ]
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/page.rs | 38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

diff --git a/rust/kernel/page.rs b/rust/kernel/page.rs
index bf3bed7e2d3fe..e21f02ae47b72 100644
--- a/rust/kernel/page.rs
+++ b/rust/kernel/page.rs
@@ -10,6 +10,11 @@
     bindings,
     error::code::*,
     error::Result,
+    types::{
+        Opaque,
+        Ownable,
+        Owned, //
+    },
     uaccess::UserSliceReader, //
 };
 use core::{
@@ -83,7 +88,7 @@ pub const fn page_align(addr: usize) -> usize {
 ///
 /// [`VBox`]: kernel::alloc::VBox
 /// [`Vmalloc`]: kernel::alloc::allocator::Vmalloc
-pub struct BorrowedPage<'a>(ManuallyDrop<Page>, PhantomData<&'a Page>);
+pub struct BorrowedPage<'a>(ManuallyDrop<NonNull<Page>>, PhantomData<&'a Page>);
 
 impl<'a> BorrowedPage<'a> {
     /// Constructs a [`BorrowedPage`] from a raw pointer to a `struct page`.
@@ -93,7 +98,9 @@ impl<'a> BorrowedPage<'a> {
     /// - `ptr` must point to a valid `bindings::page`.
     /// - `ptr` must remain valid for the entire lifetime `'a`.
     pub unsafe fn from_raw(ptr: NonNull<bindings::page>) -> Self {
-        let page = Page { page: ptr };
+        let page: NonNull<Page> =
+            // SAFETY: By function safety requirements `ptr` is non null.
+            unsafe { NonNull::new_unchecked(ptr.as_ptr().cast()) };
 
         // INVARIANT: The safety requirements guarantee that `ptr` is valid for the entire lifetime
         // `'a`.
@@ -105,7 +112,8 @@ impl<'a> Deref for BorrowedPage<'a> {
     type Target = Page;
 
     fn deref(&self) -> &Self::Target {
-        &self.0
+        // SAFETY: By type invariant `self.0` is convertible to a reference for `'a`.
+        unsafe { self.0.as_ref() }
     }
 }
 
@@ -126,8 +134,9 @@ pub trait AsPageIter {
 /// # Invariants
 ///
 /// The pointer is valid, and has ownership over the page.
+#[repr(transparent)]
 pub struct Page {
-    page: NonNull<bindings::page>,
+    page: Opaque<bindings::page>,
 }
 
 // SAFETY: Pages have no logic that relies on them staying on a given thread, so moving them across
@@ -161,19 +170,20 @@ impl Page {
     /// # Ok::<(), kernel::alloc::AllocError>(())
     /// ```
     #[inline]
-    pub fn alloc_page(flags: Flags) -> Result<Self, AllocError> {
+    pub fn alloc_page(flags: Flags) -> Result<Owned<Self>, AllocError> {
         // SAFETY: Depending on the value of `gfp_flags`, this call may sleep. Other than that, it
         // is always safe to call this method.
         let page = unsafe { bindings::alloc_pages(flags.as_raw(), 0) };
         let page = NonNull::new(page).ok_or(AllocError)?;
-        // INVARIANT: We just successfully allocated a page, so we now have ownership of the newly
-        // allocated page. We transfer that ownership to the new `Page` object.
-        Ok(Self { page })
+        // SAFETY: We just successfully allocated a page, so we now have ownership of the newly
+        // allocated page. We transfer that ownership to the new `Owned<Page>` object.
+        // Since `Page` is transparent, we can cast the pointer directly.
+        Ok(unsafe { Owned::from_raw(page.cast()) })
     }
 
     /// Returns a raw pointer to the page.
     pub fn as_ptr(&self) -> *mut bindings::page {
-        self.page.as_ptr()
+        Opaque::cast_into(&self.page)
     }
 
     /// Get the node id containing this page.
@@ -348,10 +358,12 @@ pub unsafe fn copy_from_user_slice_raw(
     }
 }
 
-impl Drop for Page {
+impl Ownable for Page {
     #[inline]
-    fn drop(&mut self) {
-        // SAFETY: By the type invariants, we have ownership of the page and can free it.
-        unsafe { bindings::__free_pages(self.page.as_ptr(), 0) };
+    unsafe fn release(&mut self) {
+        let ptr: *mut Self = self;
+        // SAFETY: By the function safety requirements, we have ownership of the page and can free
+        // it. Since Page is transparent, we can cast the raw pointer directly.
+        unsafe { bindings::__free_pages(ptr.cast(), 0) };
     }
 }

-- 
2.51.2



^ permalink raw reply related

* [PATCH v16 01/10] rust: alloc: add `KBox::into_nonnull`
From: Andreas Hindborg @ 2026-02-24 11:17 UTC (permalink / raw)
  To: Miguel Ojeda, Gary Guo, Björn Roy Baron, Benno Lossin,
	Alice Ryhl, Trevor Gross, Danilo Krummrich, Greg Kroah-Hartman,
	Dave Ertman, Ira Weiny, Leon Romanovsky, Paul Moore, Serge Hallyn,
	Rafael J. Wysocki, David Airlie, Simona Vetter, Alexander Viro,
	Christian Brauner, Jan Kara, Igor Korotin, Daniel Almeida,
	Lorenzo Stoakes, Liam R. Howlett, Viresh Kumar, Nishanth Menon,
	Stephen Boyd, Bjorn Helgaas, Krzysztof Wilczyński,
	Boqun Feng, Vlastimil Babka, Uladzislau Rezki, Boqun Feng
  Cc: linux-kernel, rust-for-linux, linux-block, linux-security-module,
	dri-devel, linux-fsdevel, linux-mm, linux-pm, linux-pci,
	Andreas Hindborg
In-Reply-To: <20260224-unique-ref-v16-0-c21afcb118d3@kernel.org>

Add a method to consume a `Box<T, A>` and return a `NonNull<T>`. This
is a convenience wrapper around `Self::into_raw` for callers that need
a `NonNull` pointer rather than a raw pointer.

Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
 rust/kernel/alloc/kbox.rs | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index 622b3529edfcb..e6efdd572aeea 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -213,6 +213,14 @@ pub fn leak<'a>(b: Self) -> &'a mut T {
         // which points to an initialized instance of `T`.
         unsafe { &mut *Box::into_raw(b) }
     }
+
+    /// Consumes the `Box<T,A>` and returns a `NonNull<T>`.
+    ///
+    /// Like [`Self::into_raw`], but returns a `NonNull`.
+    pub fn into_nonnull(b: Self) -> NonNull<T> {
+        // SAFETY: `KBox::into_raw` returns a valid pointer.
+        unsafe { NonNull::new_unchecked(Self::into_raw(b)) }
+    }
 }
 
 impl<T, A> Box<MaybeUninit<T>, A>

-- 
2.51.2



^ permalink raw reply related

* Re: [syzbot] [kernel?] INFO: task hung in restrict_one_thread_callback
From: Günther Noack @ 2026-02-24 14:43 UTC (permalink / raw)
  To: syzbot; +Cc: linux-security-module
In-Reply-To: <00A9E53EDC82309F+7b1dfc69-95f8-4ffc-a67c-967de0e2dfee@uniontech.com>

#syz set subsystems: lsm, kernel

^ permalink raw reply

* Re: [PATCH] lsm: move inode IS_PRIVATE checks to individual LSMs
From: Stephen Smalley @ 2026-02-24 14:44 UTC (permalink / raw)
  To: Paul Moore
  Cc: Casey Schaufler, danieldurning.work, linux-security-module,
	selinux, linux-integrity, jmorris, serge, john.johansen, zohar,
	roberto.sassu, dmitry.kasatkin, mic, takedakn, penguin-kernel
In-Reply-To: <CAHC9VhSp+X8YNocS7sDz+UyhdJh2yY8CRoi6dwV1eOGdCu9f9w@mail.gmail.com>

On Mon, Feb 23, 2026 at 5:21 PM Paul Moore <paul@paul-moore.com> wrote:
> I'm not going to argue with that, and perhaps that is a good next
> step: send a quick RFC patch to the VFS folks, with the LSM list CC'd,
> that drops setting the S_PRIVATE flag to see if they complain too
> loudly.  Based on other threads, Christian is aware that we are
> starting to look at better/proper handling of pidfds/pidfs so he may
> be open to dropping S_PRIVATE since it doesn't really have much impact
> outside of the LSM, but who knows; the VFS folks have been growing a
> bit more anti-LSM as of late.

Adding S_PRIVATE to pidfs inodes was originally motivated by this bug report:
https://lore.kernel.org/linux-fsdevel/20240222190334.GA412503@dev-arch.thelio-3990X/
when pidfs was first introduced as its own distinct filesystem type.
Otherwise, Fedora (and likely any other system enforcing SELinux)
stopped working.
So we can't unconditionally remove S_PRIVATE from pidfs inodes without breaking
existing userspace/policy. If we want to introduce controls over pidfs
inodes and do so in a
backward-compatible manner, we have to either move the S_PRIVATE
handling into the
individual LSMs or introduce a new hook in pidfs_init_inode() to
determine whether or not to
set S_PRIVATE. Such a hook might also handle labeling the pidfs inode
although we'd have to
see if we have enough information there to do so fully. Note that such
an approach will still likely
end up leaving pidfs inodes created before initial policy load with
the S_PRIVATE flag and hence
uncontrolled; not sure if that is a problem in practice.

>
> diff --git a/fs/pidfs.c b/fs/pidfs.c
> index 318253344b5c..4cec73b4cbcf 100644
> --- a/fs/pidfs.c
> +++ b/fs/pidfs.c
> @@ -921,7 +921,7 @@ static int pidfs_init_inode(struct inode *inode, void *data)
>        const struct pid *pid = data;
>
>        inode->i_private = data;
> -       inode->i_flags |= S_PRIVATE | S_ANON_INODE;
> +       inode->i_flags |= S_ANON_INODE;
>        /* We allow to set xattrs. */
>        inode->i_flags &= ~S_IMMUTABLE;
>        inode->i_mode |= S_IRWXU;
>
> --
> paul-moore.com

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox