* Re: [syzbot] [kernel?] INFO: task hung in restrict_one_thread_callback
From: Ding Yihan @ 2026-02-21 7:28 UTC (permalink / raw)
To: syzbot, Mickaël Salaün
Cc: linux-security-module, Günther Noack
In-Reply-To: <69995a88.050a0220.340abe.0d25.GAE@google.com>
Hi all,
Thanks to syzbot for the testing and confirmation.
Since I am relatively new to the inner workings of this specific subsystem,
I would like to take a few days to thoroughly study the root cause
(the task_work and mutex interaction) and prepare a detailed and proper commit message.
I will send out the formal patch (v1) to the mailing list later.
Best regards,
Yihan Ding
在 2026/2/21 15:11, syzbot 写道:
> Hello,
>
> syzbot has tested the proposed patch and the reproducer did not trigger any issue:
>
> Reported-by: syzbot+7ea2f5e9dfd468201817@syzkaller.appspotmail.com
> Tested-by: syzbot+7ea2f5e9dfd468201817@syzkaller.appspotmail.com
>
> Tested on:
>
> commit: d4906ae1 Add linux-next specific files for 20260220
> git tree: linux-next
> console output: https://syzkaller.appspot.com/x/log.txt?x=13ea89e6580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=51f859f3211496bc
> dashboard link: https://syzkaller.appspot.com/bug?extid=7ea2f5e9dfd468201817
> compiler: Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
> patch: https://syzkaller.appspot.com/x/patch.diff?x=15f0595a580000
>
> Note: testing is done by a robot and is best-effort only.
>
^ permalink raw reply
* Re: [GIT PULL] AppArmor updates for 7.0-rc1
From: pr-tracker-bot @ 2026-02-21 1:20 UTC (permalink / raw)
To: John Johansen; +Cc: Linus Torvalds, LKLM, open list:SECURITY SUBSYSTEM
In-Reply-To: <53c39cf4-d9e4-4ccf-ae16-dc5b143c9681@canonical.com>
The pull request you sent on Wed, 18 Feb 2026 16:19:34 -0800:
> git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor tags/apparmor-pr-2026-02-18
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/219d7660c57ec7457a6020f3d025cfe1139ffc64
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* Re: [PATCH 05/13] selinux: Use simple_start_creating() / simple_done_creating()
From: Paul Moore @ 2026-02-20 22:47 UTC (permalink / raw)
To: NeilBrown
Cc: Christian Brauner, Alexander Viro, David Howells, Jan Kara,
Chuck Lever, Jeff Layton, Miklos Szeredi, Amir Goldstein,
John Johansen, James Morris, Serge E. Hallyn, Stephen Smalley,
linux-kernel, netfs, linux-fsdevel, linux-nfs, linux-unionfs,
apparmor, linux-security-module, selinux
In-Reply-To: <20260204050726.177283-6-neilb@ownmail.net>
On Wed, Feb 4, 2026 at 12:08 AM NeilBrown <neilb@ownmail.net> wrote:
>
> From: NeilBrown <neil@brown.name>
>
> Instead of explicitly locking the parent and performing a lookup in
> selinux, use simple_start_creating(), and then use
> simple_done_creating() to unlock.
>
> This extends the region that the directory is locked for, and also
> performs a lookup.
> The lock extension is of no real consequence.
> The lookup uses simple_lookup() and so always succeeds. Thus when
> d_make_persistent() is called the dentry will already be hashed.
> d_make_persistent() handles this case.
>
> Signed-off-by: NeilBrown <neil@brown.name>
> ---
> security/selinux/selinuxfs.c | 15 +++++++--------
> 1 file changed, 7 insertions(+), 8 deletions(-)
Unless I'm missing something, there is no reason why I couldn't take
just this patch into the SELinux tree once the merge window closes,
yes?
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH 2/2] fanotify: call fanotify_events_supported() before path_permission() and security_path_notify()
From: Paul Moore @ 2026-02-20 22:16 UTC (permalink / raw)
To: Ondrej Mosnacek
Cc: Jan Kara, Amir Goldstein, Matthew Bobrowski, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260216150625.793013-3-omosnace@redhat.com>
On Mon, Feb 16, 2026 at 10:14 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
>
> The latter trigger LSM (e.g. SELinux) checks, which will log a denial
> when permission is denied, so it's better to do them after validity
> checks to avoid logging a denial when the operation would fail anyway.
>
> Fixes: 0b3b094ac9a7 ("fanotify: Disallow permission events for proc filesystem")
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> ---
> fs/notify/fanotify/fanotify_user.c | 25 ++++++++++---------------
> 1 file changed, 10 insertions(+), 15 deletions(-)
Reviewed-by: Paul Moore <paul@paul-moore.com>
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH 1/2] fanotify: avoid/silence premature LSM capability checks
From: Paul Moore @ 2026-02-20 22:15 UTC (permalink / raw)
To: Ondrej Mosnacek
Cc: Jan Kara, Amir Goldstein, Matthew Bobrowski, linux-fsdevel,
linux-security-module, selinux, linux-kernel
In-Reply-To: <20260216150625.793013-2-omosnace@redhat.com>
On Mon, Feb 16, 2026 at 10:13 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
>
> Make sure calling capable()/ns_capable() actually leads to access denied
> when false is returned, because these functions emit an audit record
> when a Linux Security Module denies the capability, which makes it
> difficult to avoid allowing/silencing unnecessary permissions in
> security policies (namely with SELinux).
>
> Where the return value just used to set a flag, use the non-auditing
> ns_capable_noaudit() instead.
>
> Fixes: 7cea2a3c505e ("fanotify: support limited functionality for unprivileged users")
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> ---
> fs/notify/fanotify/fanotify_user.c | 25 +++++++++++++------------
> 1 file changed, 13 insertions(+), 12 deletions(-)
Reviewed-by: Paul Moore <paul@paul-moore.com>
--
paul-moore.com
^ permalink raw reply
* Re: [PATCH] lsm: move inode IS_PRIVATE checks to individual LSMs
From: Casey Schaufler @ 2026-02-20 21:13 UTC (permalink / raw)
To: danieldurning.work, linux-security-module, selinux,
linux-integrity
Cc: stephen.smalley.work, paul, jmorris, serge, john.johansen, zohar,
roberto.sassu, dmitry.kasatkin, mic, takedakn, penguin-kernel,
Casey Schaufler
In-Reply-To: <20260220195405.30612-1-danieldurning.work@gmail.com>
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.
>
> 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.
I would strongly suggest that this is a pidfs issue, not an LSM
infrastructure issue.
>
> Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
> ---
> security/apparmor/lsm.c | 32 ++++++++
> security/commoncap.c | 11 ++-
> security/integrity/evm/evm_main.c | 33 +++++++++
> security/integrity/ima/ima_appraise.c | 12 +++
> security/integrity/ima/ima_main.c | 6 ++
> security/landlock/fs.c | 23 ++++++
> security/security.c | 101 ++------------------------
> security/selinux/hooks.c | 77 ++++++++++++++++++++
> security/smack/smack_lsm.c | 56 ++++++++++++++
> security/tomoyo/tomoyo.c | 35 +++++++++
> 10 files changed, 290 insertions(+), 96 deletions(-)
>
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index a87cd60ed206..5b3ced11bdbc 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -323,18 +323,27 @@ static int common_perm_create(const char *op, const struct path *dir,
>
> static int apparmor_path_unlink(const struct path *dir, struct dentry *dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE);
> }
>
> static int apparmor_path_mkdir(const struct path *dir, struct dentry *dentry,
> umode_t mode)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
> S_IFDIR);
> }
>
> static int apparmor_path_rmdir(const struct path *dir, struct dentry *dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE);
> }
>
> @@ -346,6 +355,9 @@ static int apparmor_path_mknod(const struct path *dir, struct dentry *dentry,
>
> static int apparmor_path_truncate(const struct path *path)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_SETATTR);
> }
>
> @@ -357,6 +369,9 @@ static int apparmor_file_truncate(struct file *file)
> static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
> const char *old_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE,
> S_IFLNK);
> }
> @@ -367,6 +382,9 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_
> struct aa_label *label;
> int error = 0;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
> + return 0;
> +
> if (!path_mediated_fs(old_dentry))
> return 0;
>
> @@ -386,6 +404,11 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
> struct aa_label *label;
> int error = 0;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
> + (d_is_positive(new_dentry) &&
> + IS_PRIVATE(d_backing_inode(new_dentry)))))
> + return 0;
> +
> if (!path_mediated_fs(old_dentry))
> return 0;
> if ((flags & RENAME_EXCHANGE) && !path_mediated_fs(new_dentry))
> @@ -444,16 +467,25 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
>
> static int apparmor_path_chmod(const struct path *path, umode_t mode)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return common_perm_cond(OP_CHMOD, path, AA_MAY_CHMOD);
> }
>
> static int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN);
> }
>
> static int apparmor_inode_getattr(const struct path *path)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return common_perm_cond(OP_GETATTR, path, AA_MAY_GETATTR);
> }
>
> diff --git a/security/commoncap.c b/security/commoncap.c
> index 8a23dfab7fac..1b61d43529c2 100644
> --- a/security/commoncap.c
> +++ b/security/commoncap.c
> @@ -88,7 +88,7 @@ static inline int cap_capable_helper(const struct cred *cred,
> if (ns->level <= cred_ns->level)
> return -EPERM;
>
> - /*
> + /*
> * The owner of the user namespace in the parent of the
> * user namespace has all caps.
> */
> @@ -432,6 +432,9 @@ int cap_inode_getsecurity(struct mnt_idmap *idmap,
> struct dentry *dentry;
> struct user_namespace *fs_ns;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return -EOPNOTSUPP;
> +
> if (strcmp(name, "capability") != 0)
> return -EOPNOTSUPP;
>
> @@ -1027,6 +1030,9 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
> {
> struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /* Ignore non-security xattrs */
> if (strncmp(name, XATTR_SECURITY_PREFIX,
> XATTR_SECURITY_PREFIX_LEN) != 0)
> @@ -1068,6 +1074,9 @@ int cap_inode_removexattr(struct mnt_idmap *idmap,
> {
> struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /* Ignore non-security xattrs */
> if (strncmp(name, XATTR_SECURITY_PREFIX,
> XATTR_SECURITY_PREFIX_LEN) != 0)
> diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
> index 73d500a375cb..0095712b8d75 100644
> --- a/security/integrity/evm/evm_main.c
> +++ b/security/integrity/evm/evm_main.c
> @@ -590,6 +590,9 @@ static int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> {
> const struct evm_ima_xattr_data *xattr_data = xattr_value;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /* Policy permits modification of the protected xattrs even though
> * there's no HMAC key loaded
> */
> @@ -675,6 +678,9 @@ static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> {
> enum integrity_status evm_status;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /* Policy permits modification of the protected xattrs even though
> * there's no HMAC key loaded
> */
> @@ -725,6 +731,9 @@ static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> const char *acl_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
> }
>
> @@ -807,6 +816,9 @@ static void evm_inode_post_setxattr(struct dentry *dentry,
> size_t xattr_value_len,
> int flags)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> if (!evm_revalidate_status(xattr_name))
> return;
>
> @@ -836,6 +848,9 @@ static void evm_inode_post_setxattr(struct dentry *dentry,
> static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> struct posix_acl *kacl)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
> }
>
> @@ -852,6 +867,9 @@ static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> static void evm_inode_post_removexattr(struct dentry *dentry,
> const char *xattr_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> if (!evm_revalidate_status(xattr_name))
> return;
>
> @@ -879,6 +897,9 @@ static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
> struct dentry *dentry,
> const char *acl_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> evm_inode_post_removexattr(dentry, acl_name);
> }
>
> @@ -911,6 +932,9 @@ static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> unsigned int ia_valid = attr->ia_valid;
> enum integrity_status evm_status;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /* Policy permits modification of the protected attrs even though
> * there's no HMAC key loaded
> */
> @@ -960,6 +984,9 @@ static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> static void evm_inode_post_setattr(struct mnt_idmap *idmap,
> struct dentry *dentry, int ia_valid)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> if (!evm_revalidate_status(NULL))
> return;
>
> @@ -1019,6 +1046,9 @@ int evm_inode_init_security(struct inode *inode, struct inode *dir,
> bool evm_protected_xattrs = false;
> int rc;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> if (!(evm_initialized & EVM_INIT_HMAC) || !xattrs)
> return 0;
>
> @@ -1094,6 +1124,9 @@ static void evm_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
> struct inode *inode = d_backing_inode(dentry);
> struct evm_iint_cache *iint = evm_iint_inode(inode);
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return;
> +
> if (!S_ISREG(inode->i_mode))
> return;
>
> diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
> index 5149ff4fd50d..d705c908132f 100644
> --- a/security/integrity/ima/ima_appraise.c
> +++ b/security/integrity/ima/ima_appraise.c
> @@ -665,6 +665,9 @@ static void ima_inode_post_setattr(struct mnt_idmap *idmap,
> struct ima_iint_cache *iint;
> int action;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
> || !(inode->i_opflags & IOP_XATTR))
> return;
> @@ -790,6 +793,9 @@ static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> int result;
> int err;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> result = ima_protect_xattr(dentry, xattr_name, xattr_value,
> xattr_value_len);
> if (result == 1) {
> @@ -817,6 +823,9 @@ static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
> static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> const char *acl_name, struct posix_acl *kacl)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> if (evm_revalidate_status(acl_name))
> ima_reset_appraise_flags(d_backing_inode(dentry), -1);
>
> @@ -842,6 +851,9 @@ static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
> static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
> const char *acl_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
> }
>
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 5770cf691912..5ddac6c15c7f 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -794,6 +794,9 @@ static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
> struct ima_iint_cache *iint;
> int must_appraise;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return;
> +
> if (!ima_policy_flag || !S_ISREG(inode->i_mode))
> return;
>
> @@ -826,6 +829,9 @@ static void ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
> struct inode *inode = dentry->d_inode;
> int must_appraise;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return;
> +
> if (!ima_policy_flag || !S_ISREG(inode->i_mode))
> return;
>
> diff --git a/security/landlock/fs.c b/security/landlock/fs.c
> index fe794875ad46..5fe15313a3f5 100644
> --- a/security/landlock/fs.c
> +++ b/security/landlock/fs.c
> @@ -1528,6 +1528,9 @@ static int hook_path_link(struct dentry *const old_dentry,
> const struct path *const new_dir,
> struct dentry *const new_dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
> + return 0;
> +
> return current_check_refer_path(old_dentry, new_dir, new_dentry, false,
> false);
> }
> @@ -1538,6 +1541,11 @@ static int hook_path_rename(const struct path *const old_dir,
> struct dentry *const new_dentry,
> const unsigned int flags)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
> + (d_is_positive(new_dentry) &&
> + IS_PRIVATE(d_backing_inode(new_dentry)))))
> + return 0;
> +
> /* old_dir refers to old_dentry->d_parent and new_dir->mnt */
> return current_check_refer_path(old_dentry, new_dir, new_dentry, true,
> !!(flags & RENAME_EXCHANGE));
> @@ -1546,6 +1554,9 @@ static int hook_path_rename(const struct path *const old_dir,
> static int hook_path_mkdir(const struct path *const dir,
> struct dentry *const dentry, const umode_t mode)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return current_check_access_path(dir, LANDLOCK_ACCESS_FS_MAKE_DIR);
> }
>
> @@ -1560,23 +1571,35 @@ static int hook_path_symlink(const struct path *const dir,
> struct dentry *const dentry,
> const char *const old_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return current_check_access_path(dir, LANDLOCK_ACCESS_FS_MAKE_SYM);
> }
>
> static int hook_path_unlink(const struct path *const dir,
> struct dentry *const dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_FILE);
> }
>
> static int hook_path_rmdir(const struct path *const dir,
> struct dentry *const dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> + return 0;
> +
> return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_DIR);
> }
>
> static int hook_path_truncate(const struct path *const path)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
> }
>
> diff --git a/security/security.c b/security/security.c
> index 31a688650601..658dbb10ea40 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1310,9 +1310,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
> struct xattr *new_xattrs = NULL;
> int ret = -EOPNOTSUPP, xattr_count = 0;
>
> - if (unlikely(IS_PRIVATE(inode)))
> - return 0;
> -
> if (!blob_sizes.lbs_xattr_count)
> return 0;
>
> @@ -1386,8 +1383,6 @@ int security_inode_init_security_anon(struct inode *inode,
> int security_path_mknod(const struct path *dir, struct dentry *dentry,
> umode_t mode, unsigned int dev)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> - return 0;
> return call_int_hook(path_mknod, dir, dentry, mode, dev);
> }
> EXPORT_SYMBOL(security_path_mknod);
> @@ -1401,8 +1396,6 @@ EXPORT_SYMBOL(security_path_mknod);
> */
> void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return;
> call_void_hook(path_post_mknod, idmap, dentry);
> }
>
> @@ -1419,8 +1412,6 @@ void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
> int security_path_mkdir(const struct path *dir, struct dentry *dentry,
> umode_t mode)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> - return 0;
> return call_int_hook(path_mkdir, dir, dentry, mode);
> }
> EXPORT_SYMBOL(security_path_mkdir);
> @@ -1436,8 +1427,6 @@ EXPORT_SYMBOL(security_path_mkdir);
> */
> int security_path_rmdir(const struct path *dir, struct dentry *dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> - return 0;
> return call_int_hook(path_rmdir, dir, dentry);
> }
>
> @@ -1452,8 +1441,6 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry)
> */
> int security_path_unlink(const struct path *dir, struct dentry *dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> - return 0;
> return call_int_hook(path_unlink, dir, dentry);
> }
> EXPORT_SYMBOL(security_path_unlink);
> @@ -1471,8 +1458,6 @@ EXPORT_SYMBOL(security_path_unlink);
> int security_path_symlink(const struct path *dir, struct dentry *dentry,
> const char *old_name)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
> - return 0;
> return call_int_hook(path_symlink, dir, dentry, old_name);
> }
>
> @@ -1489,8 +1474,6 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry,
> int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
> struct dentry *new_dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
> - return 0;
> return call_int_hook(path_link, old_dentry, new_dir, new_dentry);
> }
>
> @@ -1510,11 +1493,6 @@ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry,
> const struct path *new_dir, struct dentry *new_dentry,
> unsigned int flags)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
> - (d_is_positive(new_dentry) &&
> - IS_PRIVATE(d_backing_inode(new_dentry)))))
> - return 0;
> -
> return call_int_hook(path_rename, old_dir, old_dentry, new_dir,
> new_dentry, flags);
> }
> @@ -1532,8 +1510,6 @@ EXPORT_SYMBOL(security_path_rename);
> */
> int security_path_truncate(const struct path *path)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> - return 0;
> return call_int_hook(path_truncate, path);
> }
>
> @@ -1550,8 +1526,6 @@ int security_path_truncate(const struct path *path)
> */
> int security_path_chmod(const struct path *path, umode_t mode)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> - return 0;
> return call_int_hook(path_chmod, path, mode);
> }
>
> @@ -1567,8 +1541,6 @@ int security_path_chmod(const struct path *path, umode_t mode)
> */
> int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> - return 0;
> return call_int_hook(path_chown, path, uid, gid);
> }
>
> @@ -1599,8 +1571,6 @@ int security_path_chroot(const struct path *path)
> int security_inode_create(struct inode *dir, struct dentry *dentry,
> umode_t mode)
> {
> - if (unlikely(IS_PRIVATE(dir)))
> - return 0;
> return call_int_hook(inode_create, dir, dentry, mode);
> }
> EXPORT_SYMBOL_GPL(security_inode_create);
> @@ -1615,8 +1585,6 @@ EXPORT_SYMBOL_GPL(security_inode_create);
> void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
> struct inode *inode)
> {
> - if (unlikely(IS_PRIVATE(inode)))
> - return;
> call_void_hook(inode_post_create_tmpfile, idmap, inode);
> }
>
> @@ -1633,8 +1601,6 @@ void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
> int security_inode_link(struct dentry *old_dentry, struct inode *dir,
> struct dentry *new_dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
> - return 0;
> return call_int_hook(inode_link, old_dentry, dir, new_dentry);
> }
>
> @@ -1649,8 +1615,6 @@ int security_inode_link(struct dentry *old_dentry, struct inode *dir,
> */
> int security_inode_unlink(struct inode *dir, struct dentry *dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_unlink, dir, dentry);
> }
>
> @@ -1667,8 +1631,6 @@ int security_inode_unlink(struct inode *dir, struct dentry *dentry)
> int security_inode_symlink(struct inode *dir, struct dentry *dentry,
> const char *old_name)
> {
> - if (unlikely(IS_PRIVATE(dir)))
> - return 0;
> return call_int_hook(inode_symlink, dir, dentry, old_name);
> }
>
> @@ -1685,8 +1647,6 @@ int security_inode_symlink(struct inode *dir, struct dentry *dentry,
> */
> int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
> {
> - if (unlikely(IS_PRIVATE(dir)))
> - return 0;
> return call_int_hook(inode_mkdir, dir, dentry, mode);
> }
> EXPORT_SYMBOL_GPL(security_inode_mkdir);
> @@ -1702,8 +1662,6 @@ EXPORT_SYMBOL_GPL(security_inode_mkdir);
> */
> int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_rmdir, dir, dentry);
> }
>
> @@ -1724,8 +1682,6 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
> int security_inode_mknod(struct inode *dir, struct dentry *dentry,
> umode_t mode, dev_t dev)
> {
> - if (unlikely(IS_PRIVATE(dir)))
> - return 0;
> return call_int_hook(inode_mknod, dir, dentry, mode, dev);
> }
>
> @@ -1745,11 +1701,6 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
> struct inode *new_dir, struct dentry *new_dentry,
> unsigned int flags)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
> - (d_is_positive(new_dentry) &&
> - IS_PRIVATE(d_backing_inode(new_dentry)))))
> - return 0;
> -
> if (flags & RENAME_EXCHANGE) {
> int err = call_int_hook(inode_rename, new_dir, new_dentry,
> old_dir, old_dentry);
> @@ -1771,8 +1722,6 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
> */
> int security_inode_readlink(struct dentry *dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_readlink, dentry);
> }
>
> @@ -1790,8 +1739,6 @@ int security_inode_readlink(struct dentry *dentry)
> int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
> bool rcu)
> {
> - if (unlikely(IS_PRIVATE(inode)))
> - return 0;
> return call_int_hook(inode_follow_link, dentry, inode, rcu);
> }
>
> @@ -1811,8 +1758,6 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
> */
> int security_inode_permission(struct inode *inode, int mask)
> {
> - if (unlikely(IS_PRIVATE(inode)))
> - return 0;
> return call_int_hook(inode_permission, inode, mask);
> }
>
> @@ -1832,8 +1777,6 @@ int security_inode_permission(struct inode *inode, int mask)
> int security_inode_setattr(struct mnt_idmap *idmap,
> struct dentry *dentry, struct iattr *attr)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_setattr, idmap, dentry, attr);
> }
> EXPORT_SYMBOL_GPL(security_inode_setattr);
> @@ -1849,8 +1792,6 @@ EXPORT_SYMBOL_GPL(security_inode_setattr);
> void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> int ia_valid)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return;
> call_void_hook(inode_post_setattr, idmap, dentry, ia_valid);
> }
>
> @@ -1864,8 +1805,6 @@ void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> */
> int security_inode_getattr(const struct path *path)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> - return 0;
> return call_int_hook(inode_getattr, path);
> }
>
> @@ -1901,11 +1840,11 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
> {
> int rc;
>
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> -
> /* enforce the capability checks at the lsm layer, if needed */
> if (!call_int_hook(inode_xattr_skipcap, name)) {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> rc = cap_inode_setxattr(dentry, name, value, size, flags);
> if (rc)
> return rc;
> @@ -1931,8 +1870,6 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
> struct dentry *dentry, const char *acl_name,
> struct posix_acl *kacl)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_set_acl, idmap, dentry, acl_name, kacl);
> }
>
> @@ -1948,8 +1885,6 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
> void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> struct posix_acl *kacl)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return;
> call_void_hook(inode_post_set_acl, dentry, acl_name, kacl);
> }
>
> @@ -1967,8 +1902,6 @@ void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
> int security_inode_get_acl(struct mnt_idmap *idmap,
> struct dentry *dentry, const char *acl_name)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_get_acl, idmap, dentry, acl_name);
> }
>
> @@ -1986,8 +1919,6 @@ int security_inode_get_acl(struct mnt_idmap *idmap,
> int security_inode_remove_acl(struct mnt_idmap *idmap,
> struct dentry *dentry, const char *acl_name)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_remove_acl, idmap, dentry, acl_name);
> }
>
> @@ -2003,8 +1934,6 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
> void security_inode_post_remove_acl(struct mnt_idmap *idmap,
> struct dentry *dentry, const char *acl_name)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return;
> call_void_hook(inode_post_remove_acl, idmap, dentry, acl_name);
> }
>
> @@ -2021,8 +1950,6 @@ void security_inode_post_remove_acl(struct mnt_idmap *idmap,
> void security_inode_post_setxattr(struct dentry *dentry, const char *name,
> const void *value, size_t size, int flags)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return;
> call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
> }
>
> @@ -2038,8 +1965,6 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
> */
> int security_inode_getxattr(struct dentry *dentry, const char *name)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_getxattr, dentry, name);
> }
>
> @@ -2054,8 +1979,6 @@ int security_inode_getxattr(struct dentry *dentry, const char *name)
> */
> int security_inode_listxattr(struct dentry *dentry)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> return call_int_hook(inode_listxattr, dentry);
> }
>
> @@ -2087,11 +2010,11 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
> {
> int rc;
>
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return 0;
> -
> /* enforce the capability checks at the lsm layer, if needed */
> if (!call_int_hook(inode_xattr_skipcap, name)) {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> rc = cap_inode_removexattr(idmap, dentry, name);
> if (rc)
> return rc;
> @@ -2109,8 +2032,6 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
> */
> void security_inode_post_removexattr(struct dentry *dentry, const char *name)
> {
> - if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> - return;
> call_void_hook(inode_post_removexattr, dentry, name);
> }
>
> @@ -2197,9 +2118,6 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
> struct inode *inode, const char *name,
> void **buffer, bool alloc)
> {
> - if (unlikely(IS_PRIVATE(inode)))
> - return LSM_RET_DEFAULT(inode_getsecurity);
> -
> return call_int_hook(inode_getsecurity, idmap, inode, name, buffer,
> alloc);
> }
> @@ -2222,9 +2140,6 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
> int security_inode_setsecurity(struct inode *inode, const char *name,
> const void *value, size_t size, int flags)
> {
> - if (unlikely(IS_PRIVATE(inode)))
> - return LSM_RET_DEFAULT(inode_setsecurity);
> -
> return call_int_hook(inode_setsecurity, inode, name, value, size,
> flags);
> }
> @@ -2245,8 +2160,6 @@ int security_inode_setsecurity(struct inode *inode, const char *name,
> int security_inode_listsecurity(struct inode *inode,
> char *buffer, size_t buffer_size)
> {
> - if (unlikely(IS_PRIVATE(inode)))
> - return 0;
> return call_int_hook(inode_listsecurity, inode, buffer, buffer_size);
> }
> EXPORT_SYMBOL(security_inode_listsecurity);
> @@ -3596,8 +3509,6 @@ int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
> */
> void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> {
> - if (unlikely(inode && IS_PRIVATE(inode)))
> - return;
> call_void_hook(d_instantiate, dentry, inode);
> }
> EXPORT_SYMBOL(security_d_instantiate);
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index feda34b18d83..e17d776fb159 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2948,6 +2948,9 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
> int rc;
> char *context;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> sbsec = selinux_superblock(dir->i_sb);
>
> newsid = crsec->create_sid;
> @@ -3049,42 +3052,68 @@ static int selinux_inode_init_security_anon(struct inode *inode,
>
> static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
> {
> + if (unlikely(IS_PRIVATE(dir)))
> + return 0;
> +
> return may_create(dir, dentry, SECCLASS_FILE);
> }
>
> static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
> + return 0;
> +
> return may_link(dir, old_dentry, MAY_LINK);
> }
>
> static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return may_link(dir, dentry, MAY_UNLINK);
> }
>
> static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
> {
> + if (unlikely(IS_PRIVATE(dir)))
> + return 0;
> +
> return may_create(dir, dentry, SECCLASS_LNK_FILE);
> }
>
> static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
> {
> + if (unlikely(IS_PRIVATE(dir)))
> + return 0;
> +
> return may_create(dir, dentry, SECCLASS_DIR);
> }
>
> static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return may_link(dir, dentry, MAY_RMDIR);
> }
>
> static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
> {
> + if (unlikely(IS_PRIVATE(dir)))
> + return 0;
> +
> return may_create(dir, dentry, inode_mode_to_security_class(mode));
> }
>
> static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
> struct inode *new_inode, struct dentry *new_dentry)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
> + (d_is_positive(new_dentry) &&
> + IS_PRIVATE(d_backing_inode(new_dentry)))))
> + return 0;
> +
> return may_rename(old_inode, old_dentry, new_inode, new_dentry);
> }
>
> @@ -3092,6 +3121,9 @@ static int selinux_inode_readlink(struct dentry *dentry)
> {
> const struct cred *cred = current_cred();
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return dentry_has_perm(cred, dentry, FILE__READ);
> }
>
> @@ -3102,6 +3134,9 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
> struct inode_security_struct *isec;
> u32 sid = current_sid();
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> ad.type = LSM_AUDIT_DATA_DENTRY;
> ad.u.dentry = dentry;
> isec = inode_security_rcu(inode, rcu);
> @@ -3230,6 +3265,9 @@ static int selinux_inode_permission(struct inode *inode, int requested)
> int rc, rc2;
> u32 audited, denied;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> mask = requested & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
>
> /* No permission to check. Existence test. */
> @@ -3283,6 +3321,9 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> unsigned int ia_valid = iattr->ia_valid;
> u32 av = FILE__WRITE;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
> if (ia_valid & ATTR_FORCE) {
> ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
> @@ -3308,6 +3349,9 @@ static int selinux_inode_getattr(const struct path *path)
> {
> struct task_security_struct *tsec;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> tsec = selinux_task(current);
>
> if (task_avdcache_permnoaudit(tsec, current_sid()))
> @@ -3356,6 +3400,9 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
> u32 newsid, sid = current_sid();
> int rc = 0;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /* if not a selinux xattr, only check the ordinary setattr perm */
> if (strcmp(name, XATTR_NAME_SELINUX))
> return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
> @@ -3435,18 +3482,27 @@ static int selinux_inode_set_acl(struct mnt_idmap *idmap,
> struct dentry *dentry, const char *acl_name,
> struct posix_acl *kacl)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
> }
>
> static int selinux_inode_get_acl(struct mnt_idmap *idmap,
> struct dentry *dentry, const char *acl_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return dentry_has_perm(current_cred(), dentry, FILE__GETATTR);
> }
>
> static int selinux_inode_remove_acl(struct mnt_idmap *idmap,
> struct dentry *dentry, const char *acl_name)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
> }
>
> @@ -3459,6 +3515,9 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
> u32 newsid;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> if (strcmp(name, XATTR_NAME_SELINUX)) {
> /* Not an attribute we recognize, so nothing to do. */
> return;
> @@ -3494,6 +3553,9 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
> {
> const struct cred *cred = current_cred();
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return dentry_has_perm(cred, dentry, FILE__GETATTR);
> }
>
> @@ -3501,6 +3563,9 @@ static int selinux_inode_listxattr(struct dentry *dentry)
> {
> const struct cred *cred = current_cred();
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> return dentry_has_perm(cred, dentry, FILE__GETATTR);
> }
>
> @@ -3593,6 +3658,9 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
> char *context = NULL;
> struct inode_security_struct *isec;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return -EOPNOTSUPP;
> +
> /*
> * If we're not initialized yet, then we can't validate contexts, so
> * just let vfs_getxattr fall back to using the on-disk xattr.
> @@ -3637,6 +3705,9 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
> u32 newsid;
> int rc;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return -EOPNOTSUPP;
> +
> if (strcmp(name, XATTR_SELINUX_SUFFIX))
> return -EOPNOTSUPP;
>
> @@ -3664,6 +3735,9 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
> {
> const int len = sizeof(XATTR_NAME_SELINUX);
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> if (!selinux_initialized())
> return 0;
>
> @@ -6546,6 +6620,9 @@ static void selinux_ipc_getlsmprop(struct kern_ipc_perm *ipcp,
>
> static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
> {
> + if (unlikely(inode && IS_PRIVATE(inode)))
> + return;
> +
> if (inode)
> inode_doinit_with_dentry(inode, dentry);
> }
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index a0bd4919a9d9..8f432348dfbd 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -1020,6 +1020,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
> bool trans_cred;
> bool trans_rule;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> /*
> * UNIX domain sockets use lower level socket data. Let
> * UDS inode have fixed * label to keep smack_inode_permission() calm
> @@ -1093,6 +1096,9 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
>
> @@ -1124,6 +1130,9 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
>
> @@ -1157,6 +1166,9 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
>
> @@ -1199,6 +1211,11 @@ static int smack_inode_rename(struct inode *old_inode,
> struct smack_known *isp;
> struct smk_audit_info ad;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
> + (d_is_positive(new_dentry) &&
> + IS_PRIVATE(d_backing_inode(new_dentry)))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
>
> @@ -1231,6 +1248,9 @@ static int smack_inode_permission(struct inode *inode, int mask)
> int no_block = mask & MAY_NOT_BLOCK;
> int rc;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
> /*
> * No permission to check. Existence test. Yup, it's there.
> @@ -1267,6 +1287,9 @@ static int smack_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /*
> * Need to allow for clearing the setuid bit.
> */
> @@ -1292,6 +1315,9 @@ static int smack_inode_getattr(const struct path *path)
> struct inode *inode = d_backing_inode(path->dentry);
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
> smk_ad_setfield_u_fs_path(&ad, *path);
> rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad);
> @@ -1351,6 +1377,9 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
> int rc = 0;
> umode_t const i_mode = d_backing_inode(dentry)->i_mode;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> /*
> * Check label validity here so import won't fail in post_setxattr
> */
> @@ -1421,6 +1450,9 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
> struct smack_known *skp;
> struct inode_smack *isp = smack_inode(d_backing_inode(dentry));
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return;
> +
> if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
> isp->smk_flags |= SMK_INODE_TRANSMUTE;
> return;
> @@ -1455,6 +1487,9 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
>
> @@ -1541,6 +1576,9 @@ static int smack_inode_set_acl(struct mnt_idmap *idmap,
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
>
> @@ -1563,6 +1601,9 @@ static int smack_inode_get_acl(struct mnt_idmap *idmap,
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
>
> @@ -1585,6 +1626,9 @@ static int smack_inode_remove_acl(struct mnt_idmap *idmap,
> struct smk_audit_info ad;
> int rc;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
> + return 0;
> +
> smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
> smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
>
> @@ -1616,6 +1660,9 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
> size_t label_len;
> char *label = NULL;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return -EOPNOTSUPP;
> +
> if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
> isp = smk_of_inode(inode);
> } else if (strcmp(name, XATTR_SMACK_TRANSMUTE) == 0) {
> @@ -1672,6 +1719,9 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
> {
> int len = sizeof(XATTR_NAME_SMACK);
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return 0;
> +
> if (buffer != NULL && len <= buffer_size)
> memcpy(buffer, XATTR_NAME_SMACK, len);
>
> @@ -2918,6 +2968,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
> struct socket *sock;
> int rc = 0;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return -EOPNOTSUPP;
> +
> if (value == NULL || size > SMK_LONGLABEL || size == 0)
> return -EINVAL;
>
> @@ -3517,6 +3570,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
> if (inode == NULL)
> return;
>
> + if (unlikely(IS_PRIVATE(inode)))
> + return;
> +
> isp = smack_inode(inode);
>
> /*
> diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
> index c66e02ed8ee3..98eb8cd67f78 100644
> --- a/security/tomoyo/tomoyo.c
> +++ b/security/tomoyo/tomoyo.c
> @@ -120,6 +120,9 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
> */
> static int tomoyo_inode_getattr(const struct path *path)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, path, NULL);
> }
>
> @@ -132,6 +135,9 @@ static int tomoyo_inode_getattr(const struct path *path)
> */
> static int tomoyo_path_truncate(const struct path *path)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL);
> }
>
> @@ -159,6 +165,9 @@ static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry)
> {
> struct path path = { .mnt = parent->mnt, .dentry = dentry };
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
> + return 0;
> +
> return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL);
> }
>
> @@ -176,6 +185,9 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry,
> {
> struct path path = { .mnt = parent->mnt, .dentry = dentry };
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
> + return 0;
> +
> return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
> mode & S_IALLUGO);
> }
> @@ -192,6 +204,9 @@ static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry)
> {
> struct path path = { .mnt = parent->mnt, .dentry = dentry };
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
> + return 0;
> +
> return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL);
> }
>
> @@ -209,6 +224,9 @@ static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry,
> {
> struct path path = { .mnt = parent->mnt, .dentry = dentry };
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
> + return 0;
> +
> return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name);
> }
>
> @@ -229,6 +247,9 @@ static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry,
> int type = TOMOYO_TYPE_CREATE;
> const unsigned int perm = mode & S_IALLUGO;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
> + return 0;
> +
> switch (mode & S_IFMT) {
> case S_IFCHR:
> type = TOMOYO_TYPE_MKCHAR;
> @@ -267,6 +288,9 @@ static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_di
> struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry };
> struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry };
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
> + return 0;
> +
> return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2);
> }
>
> @@ -290,6 +314,11 @@ static int tomoyo_path_rename(const struct path *old_parent,
> struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry };
> struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry };
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
> + (d_is_positive(new_dentry) &&
> + IS_PRIVATE(d_backing_inode(new_dentry)))))
> + return 0;
> +
> if (flags & RENAME_EXCHANGE) {
> const int err = tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path2,
> &path1);
> @@ -360,6 +389,9 @@ static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
> */
> static int tomoyo_path_chmod(const struct path *path, umode_t mode)
> {
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, path,
> mode & S_IALLUGO);
> }
> @@ -377,6 +409,9 @@ static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
> {
> int error = 0;
>
> + if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
> + return 0;
> +
> if (uid_valid(uid))
> error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path,
> from_kuid(&init_user_ns, uid));
^ permalink raw reply
* Re: [RFC PATCH] fs/pidfs: Add permission check to pidfd_info()
From: Daniel Durning @ 2026-02-20 20:45 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, linux-security-module, selinux, viro, jack, paul,
stephen.smalley.work, omosnace, Oleg Nesterov
In-Reply-To: <20260217-abgedankt-eilte-2386c98b3ef7@brauner>
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.
^ permalink raw reply
* [PATCH] lsm: move inode IS_PRIVATE checks to individual LSMs
From: danieldurning.work @ 2026-02-20 19:54 UTC (permalink / raw)
To: linux-security-module, selinux, linux-integrity
Cc: stephen.smalley.work, paul, jmorris, serge, john.johansen, zohar,
roberto.sassu, dmitry.kasatkin, mic, casey, takedakn,
penguin-kernel
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.
This reorganization enables the LSMs to eventually implement
checks or labeling for some specific S_PRIVATE inodes like pidfds.
Signed-off-by: Daniel Durning <danieldurning.work@gmail.com>
---
security/apparmor/lsm.c | 32 ++++++++
security/commoncap.c | 11 ++-
security/integrity/evm/evm_main.c | 33 +++++++++
security/integrity/ima/ima_appraise.c | 12 +++
security/integrity/ima/ima_main.c | 6 ++
security/landlock/fs.c | 23 ++++++
security/security.c | 101 ++------------------------
security/selinux/hooks.c | 77 ++++++++++++++++++++
security/smack/smack_lsm.c | 56 ++++++++++++++
security/tomoyo/tomoyo.c | 35 +++++++++
10 files changed, 290 insertions(+), 96 deletions(-)
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index a87cd60ed206..5b3ced11bdbc 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -323,18 +323,27 @@ static int common_perm_create(const char *op, const struct path *dir,
static int apparmor_path_unlink(const struct path *dir, struct dentry *dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE);
}
static int apparmor_path_mkdir(const struct path *dir, struct dentry *dentry,
umode_t mode)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
S_IFDIR);
}
static int apparmor_path_rmdir(const struct path *dir, struct dentry *dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE);
}
@@ -346,6 +355,9 @@ static int apparmor_path_mknod(const struct path *dir, struct dentry *dentry,
static int apparmor_path_truncate(const struct path *path)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_SETATTR);
}
@@ -357,6 +369,9 @@ static int apparmor_file_truncate(struct file *file)
static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
const char *old_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE,
S_IFLNK);
}
@@ -367,6 +382,9 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_
struct aa_label *label;
int error = 0;
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
+ return 0;
+
if (!path_mediated_fs(old_dentry))
return 0;
@@ -386,6 +404,11 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
struct aa_label *label;
int error = 0;
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
+ (d_is_positive(new_dentry) &&
+ IS_PRIVATE(d_backing_inode(new_dentry)))))
+ return 0;
+
if (!path_mediated_fs(old_dentry))
return 0;
if ((flags & RENAME_EXCHANGE) && !path_mediated_fs(new_dentry))
@@ -444,16 +467,25 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
static int apparmor_path_chmod(const struct path *path, umode_t mode)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return common_perm_cond(OP_CHMOD, path, AA_MAY_CHMOD);
}
static int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN);
}
static int apparmor_inode_getattr(const struct path *path)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return common_perm_cond(OP_GETATTR, path, AA_MAY_GETATTR);
}
diff --git a/security/commoncap.c b/security/commoncap.c
index 8a23dfab7fac..1b61d43529c2 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -88,7 +88,7 @@ static inline int cap_capable_helper(const struct cred *cred,
if (ns->level <= cred_ns->level)
return -EPERM;
- /*
+ /*
* The owner of the user namespace in the parent of the
* user namespace has all caps.
*/
@@ -432,6 +432,9 @@ int cap_inode_getsecurity(struct mnt_idmap *idmap,
struct dentry *dentry;
struct user_namespace *fs_ns;
+ if (unlikely(IS_PRIVATE(inode)))
+ return -EOPNOTSUPP;
+
if (strcmp(name, "capability") != 0)
return -EOPNOTSUPP;
@@ -1027,6 +1030,9 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
{
struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/* Ignore non-security xattrs */
if (strncmp(name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN) != 0)
@@ -1068,6 +1074,9 @@ int cap_inode_removexattr(struct mnt_idmap *idmap,
{
struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/* Ignore non-security xattrs */
if (strncmp(name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN) != 0)
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 73d500a375cb..0095712b8d75 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -590,6 +590,9 @@ static int evm_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
{
const struct evm_ima_xattr_data *xattr_data = xattr_value;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/* Policy permits modification of the protected xattrs even though
* there's no HMAC key loaded
*/
@@ -675,6 +678,9 @@ static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
{
enum integrity_status evm_status;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/* Policy permits modification of the protected xattrs even though
* there's no HMAC key loaded
*/
@@ -725,6 +731,9 @@ static int evm_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
static int evm_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
const char *acl_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return evm_inode_set_acl(idmap, dentry, acl_name, NULL);
}
@@ -807,6 +816,9 @@ static void evm_inode_post_setxattr(struct dentry *dentry,
size_t xattr_value_len,
int flags)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
if (!evm_revalidate_status(xattr_name))
return;
@@ -836,6 +848,9 @@ static void evm_inode_post_setxattr(struct dentry *dentry,
static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
return evm_inode_post_setxattr(dentry, acl_name, NULL, 0, 0);
}
@@ -852,6 +867,9 @@ static void evm_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
static void evm_inode_post_removexattr(struct dentry *dentry,
const char *xattr_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
if (!evm_revalidate_status(xattr_name))
return;
@@ -879,6 +897,9 @@ static inline void evm_inode_post_remove_acl(struct mnt_idmap *idmap,
struct dentry *dentry,
const char *acl_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
evm_inode_post_removexattr(dentry, acl_name);
}
@@ -911,6 +932,9 @@ static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
unsigned int ia_valid = attr->ia_valid;
enum integrity_status evm_status;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/* Policy permits modification of the protected attrs even though
* there's no HMAC key loaded
*/
@@ -960,6 +984,9 @@ static int evm_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
static void evm_inode_post_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, int ia_valid)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
if (!evm_revalidate_status(NULL))
return;
@@ -1019,6 +1046,9 @@ int evm_inode_init_security(struct inode *inode, struct inode *dir,
bool evm_protected_xattrs = false;
int rc;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
if (!(evm_initialized & EVM_INIT_HMAC) || !xattrs)
return 0;
@@ -1094,6 +1124,9 @@ static void evm_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
struct inode *inode = d_backing_inode(dentry);
struct evm_iint_cache *iint = evm_iint_inode(inode);
+ if (unlikely(IS_PRIVATE(inode)))
+ return;
+
if (!S_ISREG(inode->i_mode))
return;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 5149ff4fd50d..d705c908132f 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -665,6 +665,9 @@ static void ima_inode_post_setattr(struct mnt_idmap *idmap,
struct ima_iint_cache *iint;
int action;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
|| !(inode->i_opflags & IOP_XATTR))
return;
@@ -790,6 +793,9 @@ static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
int result;
int err;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len);
if (result == 1) {
@@ -817,6 +823,9 @@ static int ima_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
static int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
const char *acl_name, struct posix_acl *kacl)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
if (evm_revalidate_status(acl_name))
ima_reset_appraise_flags(d_backing_inode(dentry), -1);
@@ -842,6 +851,9 @@ static int ima_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
static int ima_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
const char *acl_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return ima_inode_set_acl(idmap, dentry, acl_name, NULL);
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 5770cf691912..5ddac6c15c7f 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -794,6 +794,9 @@ static void ima_post_create_tmpfile(struct mnt_idmap *idmap,
struct ima_iint_cache *iint;
int must_appraise;
+ if (unlikely(IS_PRIVATE(inode)))
+ return;
+
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return;
@@ -826,6 +829,9 @@ static void ima_post_path_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
struct inode *inode = dentry->d_inode;
int must_appraise;
+ if (unlikely(IS_PRIVATE(inode)))
+ return;
+
if (!ima_policy_flag || !S_ISREG(inode->i_mode))
return;
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index fe794875ad46..5fe15313a3f5 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -1528,6 +1528,9 @@ static int hook_path_link(struct dentry *const old_dentry,
const struct path *const new_dir,
struct dentry *const new_dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
+ return 0;
+
return current_check_refer_path(old_dentry, new_dir, new_dentry, false,
false);
}
@@ -1538,6 +1541,11 @@ static int hook_path_rename(const struct path *const old_dir,
struct dentry *const new_dentry,
const unsigned int flags)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
+ (d_is_positive(new_dentry) &&
+ IS_PRIVATE(d_backing_inode(new_dentry)))))
+ return 0;
+
/* old_dir refers to old_dentry->d_parent and new_dir->mnt */
return current_check_refer_path(old_dentry, new_dir, new_dentry, true,
!!(flags & RENAME_EXCHANGE));
@@ -1546,6 +1554,9 @@ static int hook_path_rename(const struct path *const old_dir,
static int hook_path_mkdir(const struct path *const dir,
struct dentry *const dentry, const umode_t mode)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return current_check_access_path(dir, LANDLOCK_ACCESS_FS_MAKE_DIR);
}
@@ -1560,23 +1571,35 @@ static int hook_path_symlink(const struct path *const dir,
struct dentry *const dentry,
const char *const old_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return current_check_access_path(dir, LANDLOCK_ACCESS_FS_MAKE_SYM);
}
static int hook_path_unlink(const struct path *const dir,
struct dentry *const dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_FILE);
}
static int hook_path_rmdir(const struct path *const dir,
struct dentry *const dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
+ return 0;
+
return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_DIR);
}
static int hook_path_truncate(const struct path *const path)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
}
diff --git a/security/security.c b/security/security.c
index 31a688650601..658dbb10ea40 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1310,9 +1310,6 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
struct xattr *new_xattrs = NULL;
int ret = -EOPNOTSUPP, xattr_count = 0;
- if (unlikely(IS_PRIVATE(inode)))
- return 0;
-
if (!blob_sizes.lbs_xattr_count)
return 0;
@@ -1386,8 +1383,6 @@ int security_inode_init_security_anon(struct inode *inode,
int security_path_mknod(const struct path *dir, struct dentry *dentry,
umode_t mode, unsigned int dev)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
- return 0;
return call_int_hook(path_mknod, dir, dentry, mode, dev);
}
EXPORT_SYMBOL(security_path_mknod);
@@ -1401,8 +1396,6 @@ EXPORT_SYMBOL(security_path_mknod);
*/
void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return;
call_void_hook(path_post_mknod, idmap, dentry);
}
@@ -1419,8 +1412,6 @@ void security_path_post_mknod(struct mnt_idmap *idmap, struct dentry *dentry)
int security_path_mkdir(const struct path *dir, struct dentry *dentry,
umode_t mode)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
- return 0;
return call_int_hook(path_mkdir, dir, dentry, mode);
}
EXPORT_SYMBOL(security_path_mkdir);
@@ -1436,8 +1427,6 @@ EXPORT_SYMBOL(security_path_mkdir);
*/
int security_path_rmdir(const struct path *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
- return 0;
return call_int_hook(path_rmdir, dir, dentry);
}
@@ -1452,8 +1441,6 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry)
*/
int security_path_unlink(const struct path *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
- return 0;
return call_int_hook(path_unlink, dir, dentry);
}
EXPORT_SYMBOL(security_path_unlink);
@@ -1471,8 +1458,6 @@ EXPORT_SYMBOL(security_path_unlink);
int security_path_symlink(const struct path *dir, struct dentry *dentry,
const char *old_name)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
- return 0;
return call_int_hook(path_symlink, dir, dentry, old_name);
}
@@ -1489,8 +1474,6 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry,
int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
struct dentry *new_dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
- return 0;
return call_int_hook(path_link, old_dentry, new_dir, new_dentry);
}
@@ -1510,11 +1493,6 @@ int security_path_rename(const struct path *old_dir, struct dentry *old_dentry,
const struct path *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
- (d_is_positive(new_dentry) &&
- IS_PRIVATE(d_backing_inode(new_dentry)))))
- return 0;
-
return call_int_hook(path_rename, old_dir, old_dentry, new_dir,
new_dentry, flags);
}
@@ -1532,8 +1510,6 @@ EXPORT_SYMBOL(security_path_rename);
*/
int security_path_truncate(const struct path *path)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
- return 0;
return call_int_hook(path_truncate, path);
}
@@ -1550,8 +1526,6 @@ int security_path_truncate(const struct path *path)
*/
int security_path_chmod(const struct path *path, umode_t mode)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
- return 0;
return call_int_hook(path_chmod, path, mode);
}
@@ -1567,8 +1541,6 @@ int security_path_chmod(const struct path *path, umode_t mode)
*/
int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
- return 0;
return call_int_hook(path_chown, path, uid, gid);
}
@@ -1599,8 +1571,6 @@ int security_path_chroot(const struct path *path)
int security_inode_create(struct inode *dir, struct dentry *dentry,
umode_t mode)
{
- if (unlikely(IS_PRIVATE(dir)))
- return 0;
return call_int_hook(inode_create, dir, dentry, mode);
}
EXPORT_SYMBOL_GPL(security_inode_create);
@@ -1615,8 +1585,6 @@ EXPORT_SYMBOL_GPL(security_inode_create);
void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
struct inode *inode)
{
- if (unlikely(IS_PRIVATE(inode)))
- return;
call_void_hook(inode_post_create_tmpfile, idmap, inode);
}
@@ -1633,8 +1601,6 @@ void security_inode_post_create_tmpfile(struct mnt_idmap *idmap,
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
- return 0;
return call_int_hook(inode_link, old_dentry, dir, new_dentry);
}
@@ -1649,8 +1615,6 @@ int security_inode_link(struct dentry *old_dentry, struct inode *dir,
*/
int security_inode_unlink(struct inode *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_unlink, dir, dentry);
}
@@ -1667,8 +1631,6 @@ int security_inode_unlink(struct inode *dir, struct dentry *dentry)
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
const char *old_name)
{
- if (unlikely(IS_PRIVATE(dir)))
- return 0;
return call_int_hook(inode_symlink, dir, dentry, old_name);
}
@@ -1685,8 +1647,6 @@ int security_inode_symlink(struct inode *dir, struct dentry *dentry,
*/
int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- if (unlikely(IS_PRIVATE(dir)))
- return 0;
return call_int_hook(inode_mkdir, dir, dentry, mode);
}
EXPORT_SYMBOL_GPL(security_inode_mkdir);
@@ -1702,8 +1662,6 @@ EXPORT_SYMBOL_GPL(security_inode_mkdir);
*/
int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_rmdir, dir, dentry);
}
@@ -1724,8 +1682,6 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
int security_inode_mknod(struct inode *dir, struct dentry *dentry,
umode_t mode, dev_t dev)
{
- if (unlikely(IS_PRIVATE(dir)))
- return 0;
return call_int_hook(inode_mknod, dir, dentry, mode, dev);
}
@@ -1745,11 +1701,6 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
- (d_is_positive(new_dentry) &&
- IS_PRIVATE(d_backing_inode(new_dentry)))))
- return 0;
-
if (flags & RENAME_EXCHANGE) {
int err = call_int_hook(inode_rename, new_dir, new_dentry,
old_dir, old_dentry);
@@ -1771,8 +1722,6 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
*/
int security_inode_readlink(struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_readlink, dentry);
}
@@ -1790,8 +1739,6 @@ int security_inode_readlink(struct dentry *dentry)
int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu)
{
- if (unlikely(IS_PRIVATE(inode)))
- return 0;
return call_int_hook(inode_follow_link, dentry, inode, rcu);
}
@@ -1811,8 +1758,6 @@ int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
*/
int security_inode_permission(struct inode *inode, int mask)
{
- if (unlikely(IS_PRIVATE(inode)))
- return 0;
return call_int_hook(inode_permission, inode, mask);
}
@@ -1832,8 +1777,6 @@ int security_inode_permission(struct inode *inode, int mask)
int security_inode_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_setattr, idmap, dentry, attr);
}
EXPORT_SYMBOL_GPL(security_inode_setattr);
@@ -1849,8 +1792,6 @@ EXPORT_SYMBOL_GPL(security_inode_setattr);
void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
int ia_valid)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return;
call_void_hook(inode_post_setattr, idmap, dentry, ia_valid);
}
@@ -1864,8 +1805,6 @@ void security_inode_post_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
*/
int security_inode_getattr(const struct path *path)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
- return 0;
return call_int_hook(inode_getattr, path);
}
@@ -1901,11 +1840,11 @@ int security_inode_setxattr(struct mnt_idmap *idmap,
{
int rc;
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
-
/* enforce the capability checks at the lsm layer, if needed */
if (!call_int_hook(inode_xattr_skipcap, name)) {
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
rc = cap_inode_setxattr(dentry, name, value, size, flags);
if (rc)
return rc;
@@ -1931,8 +1870,6 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_set_acl, idmap, dentry, acl_name, kacl);
}
@@ -1948,8 +1885,6 @@ int security_inode_set_acl(struct mnt_idmap *idmap,
void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return;
call_void_hook(inode_post_set_acl, dentry, acl_name, kacl);
}
@@ -1967,8 +1902,6 @@ void security_inode_post_set_acl(struct dentry *dentry, const char *acl_name,
int security_inode_get_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_get_acl, idmap, dentry, acl_name);
}
@@ -1986,8 +1919,6 @@ int security_inode_get_acl(struct mnt_idmap *idmap,
int security_inode_remove_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_remove_acl, idmap, dentry, acl_name);
}
@@ -2003,8 +1934,6 @@ int security_inode_remove_acl(struct mnt_idmap *idmap,
void security_inode_post_remove_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return;
call_void_hook(inode_post_remove_acl, idmap, dentry, acl_name);
}
@@ -2021,8 +1950,6 @@ void security_inode_post_remove_acl(struct mnt_idmap *idmap,
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return;
call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
}
@@ -2038,8 +1965,6 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name,
*/
int security_inode_getxattr(struct dentry *dentry, const char *name)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_getxattr, dentry, name);
}
@@ -2054,8 +1979,6 @@ int security_inode_getxattr(struct dentry *dentry, const char *name)
*/
int security_inode_listxattr(struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
return call_int_hook(inode_listxattr, dentry);
}
@@ -2087,11 +2010,11 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
{
int rc;
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return 0;
-
/* enforce the capability checks at the lsm layer, if needed */
if (!call_int_hook(inode_xattr_skipcap, name)) {
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
rc = cap_inode_removexattr(idmap, dentry, name);
if (rc)
return rc;
@@ -2109,8 +2032,6 @@ int security_inode_removexattr(struct mnt_idmap *idmap,
*/
void security_inode_post_removexattr(struct dentry *dentry, const char *name)
{
- if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
- return;
call_void_hook(inode_post_removexattr, dentry, name);
}
@@ -2197,9 +2118,6 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
struct inode *inode, const char *name,
void **buffer, bool alloc)
{
- if (unlikely(IS_PRIVATE(inode)))
- return LSM_RET_DEFAULT(inode_getsecurity);
-
return call_int_hook(inode_getsecurity, idmap, inode, name, buffer,
alloc);
}
@@ -2222,9 +2140,6 @@ int security_inode_getsecurity(struct mnt_idmap *idmap,
int security_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
- if (unlikely(IS_PRIVATE(inode)))
- return LSM_RET_DEFAULT(inode_setsecurity);
-
return call_int_hook(inode_setsecurity, inode, name, value, size,
flags);
}
@@ -2245,8 +2160,6 @@ int security_inode_setsecurity(struct inode *inode, const char *name,
int security_inode_listsecurity(struct inode *inode,
char *buffer, size_t buffer_size)
{
- if (unlikely(IS_PRIVATE(inode)))
- return 0;
return call_int_hook(inode_listsecurity, inode, buffer, buffer_size);
}
EXPORT_SYMBOL(security_inode_listsecurity);
@@ -3596,8 +3509,6 @@ int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
*/
void security_d_instantiate(struct dentry *dentry, struct inode *inode)
{
- if (unlikely(inode && IS_PRIVATE(inode)))
- return;
call_void_hook(d_instantiate, dentry, inode);
}
EXPORT_SYMBOL(security_d_instantiate);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index feda34b18d83..e17d776fb159 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -2948,6 +2948,9 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
int rc;
char *context;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
sbsec = selinux_superblock(dir->i_sb);
newsid = crsec->create_sid;
@@ -3049,42 +3052,68 @@ static int selinux_inode_init_security_anon(struct inode *inode,
static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
+ if (unlikely(IS_PRIVATE(dir)))
+ return 0;
+
return may_create(dir, dentry, SECCLASS_FILE);
}
static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
+ return 0;
+
return may_link(dir, old_dentry, MAY_LINK);
}
static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return may_link(dir, dentry, MAY_UNLINK);
}
static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
{
+ if (unlikely(IS_PRIVATE(dir)))
+ return 0;
+
return may_create(dir, dentry, SECCLASS_LNK_FILE);
}
static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
{
+ if (unlikely(IS_PRIVATE(dir)))
+ return 0;
+
return may_create(dir, dentry, SECCLASS_DIR);
}
static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return may_link(dir, dentry, MAY_RMDIR);
}
static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
+ if (unlikely(IS_PRIVATE(dir)))
+ return 0;
+
return may_create(dir, dentry, inode_mode_to_security_class(mode));
}
static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
struct inode *new_inode, struct dentry *new_dentry)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
+ (d_is_positive(new_dentry) &&
+ IS_PRIVATE(d_backing_inode(new_dentry)))))
+ return 0;
+
return may_rename(old_inode, old_dentry, new_inode, new_dentry);
}
@@ -3092,6 +3121,9 @@ static int selinux_inode_readlink(struct dentry *dentry)
{
const struct cred *cred = current_cred();
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return dentry_has_perm(cred, dentry, FILE__READ);
}
@@ -3102,6 +3134,9 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
struct inode_security_struct *isec;
u32 sid = current_sid();
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
isec = inode_security_rcu(inode, rcu);
@@ -3230,6 +3265,9 @@ static int selinux_inode_permission(struct inode *inode, int requested)
int rc, rc2;
u32 audited, denied;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
mask = requested & (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
/* No permission to check. Existence test. */
@@ -3283,6 +3321,9 @@ static int selinux_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
unsigned int ia_valid = iattr->ia_valid;
u32 av = FILE__WRITE;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
if (ia_valid & ATTR_FORCE) {
ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
@@ -3308,6 +3349,9 @@ static int selinux_inode_getattr(const struct path *path)
{
struct task_security_struct *tsec;
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
tsec = selinux_task(current);
if (task_avdcache_permnoaudit(tsec, current_sid()))
@@ -3356,6 +3400,9 @@ static int selinux_inode_setxattr(struct mnt_idmap *idmap,
u32 newsid, sid = current_sid();
int rc = 0;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/* if not a selinux xattr, only check the ordinary setattr perm */
if (strcmp(name, XATTR_NAME_SELINUX))
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
@@ -3435,18 +3482,27 @@ static int selinux_inode_set_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name,
struct posix_acl *kacl)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
}
static int selinux_inode_get_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return dentry_has_perm(current_cred(), dentry, FILE__GETATTR);
}
static int selinux_inode_remove_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
}
@@ -3459,6 +3515,9 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
u32 newsid;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
if (strcmp(name, XATTR_NAME_SELINUX)) {
/* Not an attribute we recognize, so nothing to do. */
return;
@@ -3494,6 +3553,9 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
{
const struct cred *cred = current_cred();
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return dentry_has_perm(cred, dentry, FILE__GETATTR);
}
@@ -3501,6 +3563,9 @@ static int selinux_inode_listxattr(struct dentry *dentry)
{
const struct cred *cred = current_cred();
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
return dentry_has_perm(cred, dentry, FILE__GETATTR);
}
@@ -3593,6 +3658,9 @@ static int selinux_inode_getsecurity(struct mnt_idmap *idmap,
char *context = NULL;
struct inode_security_struct *isec;
+ if (unlikely(IS_PRIVATE(inode)))
+ return -EOPNOTSUPP;
+
/*
* If we're not initialized yet, then we can't validate contexts, so
* just let vfs_getxattr fall back to using the on-disk xattr.
@@ -3637,6 +3705,9 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
u32 newsid;
int rc;
+ if (unlikely(IS_PRIVATE(inode)))
+ return -EOPNOTSUPP;
+
if (strcmp(name, XATTR_SELINUX_SUFFIX))
return -EOPNOTSUPP;
@@ -3664,6 +3735,9 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
{
const int len = sizeof(XATTR_NAME_SELINUX);
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
if (!selinux_initialized())
return 0;
@@ -6546,6 +6620,9 @@ static void selinux_ipc_getlsmprop(struct kern_ipc_perm *ipcp,
static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
{
+ if (unlikely(inode && IS_PRIVATE(inode)))
+ return;
+
if (inode)
inode_doinit_with_dentry(inode, dentry);
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a0bd4919a9d9..8f432348dfbd 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1020,6 +1020,9 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
bool trans_cred;
bool trans_rule;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
/*
* UNIX domain sockets use lower level socket data. Let
* UDS inode have fixed * label to keep smack_inode_permission() calm
@@ -1093,6 +1096,9 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
@@ -1124,6 +1130,9 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
@@ -1157,6 +1166,9 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
@@ -1199,6 +1211,11 @@ static int smack_inode_rename(struct inode *old_inode,
struct smack_known *isp;
struct smk_audit_info ad;
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
+ (d_is_positive(new_dentry) &&
+ IS_PRIVATE(d_backing_inode(new_dentry)))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
@@ -1231,6 +1248,9 @@ static int smack_inode_permission(struct inode *inode, int mask)
int no_block = mask & MAY_NOT_BLOCK;
int rc;
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
/*
* No permission to check. Existence test. Yup, it's there.
@@ -1267,6 +1287,9 @@ static int smack_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/*
* Need to allow for clearing the setuid bit.
*/
@@ -1292,6 +1315,9 @@ static int smack_inode_getattr(const struct path *path)
struct inode *inode = d_backing_inode(path->dentry);
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, *path);
rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad);
@@ -1351,6 +1377,9 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
int rc = 0;
umode_t const i_mode = d_backing_inode(dentry)->i_mode;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
/*
* Check label validity here so import won't fail in post_setxattr
*/
@@ -1421,6 +1450,9 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
struct smack_known *skp;
struct inode_smack *isp = smack_inode(d_backing_inode(dentry));
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return;
+
if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
isp->smk_flags |= SMK_INODE_TRANSMUTE;
return;
@@ -1455,6 +1487,9 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
@@ -1541,6 +1576,9 @@ static int smack_inode_set_acl(struct mnt_idmap *idmap,
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
@@ -1563,6 +1601,9 @@ static int smack_inode_get_acl(struct mnt_idmap *idmap,
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
@@ -1585,6 +1626,9 @@ static int smack_inode_remove_acl(struct mnt_idmap *idmap,
struct smk_audit_info ad;
int rc;
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
@@ -1616,6 +1660,9 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
size_t label_len;
char *label = NULL;
+ if (unlikely(IS_PRIVATE(inode)))
+ return -EOPNOTSUPP;
+
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
isp = smk_of_inode(inode);
} else if (strcmp(name, XATTR_SMACK_TRANSMUTE) == 0) {
@@ -1672,6 +1719,9 @@ static int smack_inode_listsecurity(struct inode *inode, char *buffer,
{
int len = sizeof(XATTR_NAME_SMACK);
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
if (buffer != NULL && len <= buffer_size)
memcpy(buffer, XATTR_NAME_SMACK, len);
@@ -2918,6 +2968,9 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
struct socket *sock;
int rc = 0;
+ if (unlikely(IS_PRIVATE(inode)))
+ return -EOPNOTSUPP;
+
if (value == NULL || size > SMK_LONGLABEL || size == 0)
return -EINVAL;
@@ -3517,6 +3570,9 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
if (inode == NULL)
return;
+ if (unlikely(IS_PRIVATE(inode)))
+ return;
+
isp = smack_inode(inode);
/*
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index c66e02ed8ee3..98eb8cd67f78 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -120,6 +120,9 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
*/
static int tomoyo_inode_getattr(const struct path *path)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, path, NULL);
}
@@ -132,6 +135,9 @@ static int tomoyo_inode_getattr(const struct path *path)
*/
static int tomoyo_path_truncate(const struct path *path)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path, NULL);
}
@@ -159,6 +165,9 @@ static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry)
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+ if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
+ return 0;
+
return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL);
}
@@ -176,6 +185,9 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry,
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+ if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
+ return 0;
+
return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
mode & S_IALLUGO);
}
@@ -192,6 +204,9 @@ static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry)
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+ if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
+ return 0;
+
return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL);
}
@@ -209,6 +224,9 @@ static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry,
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+ if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
+ return 0;
+
return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name);
}
@@ -229,6 +247,9 @@ static int tomoyo_path_mknod(const struct path *parent, struct dentry *dentry,
int type = TOMOYO_TYPE_CREATE;
const unsigned int perm = mode & S_IALLUGO;
+ if (unlikely(IS_PRIVATE(d_backing_inode(parent->dentry))))
+ return 0;
+
switch (mode & S_IFMT) {
case S_IFCHR:
type = TOMOYO_TYPE_MKCHAR;
@@ -267,6 +288,9 @@ static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_di
struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry };
struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry };
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
+ return 0;
+
return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2);
}
@@ -290,6 +314,11 @@ static int tomoyo_path_rename(const struct path *old_parent,
struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry };
struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry };
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
+ (d_is_positive(new_dentry) &&
+ IS_PRIVATE(d_backing_inode(new_dentry)))))
+ return 0;
+
if (flags & RENAME_EXCHANGE) {
const int err = tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path2,
&path1);
@@ -360,6 +389,9 @@ static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
*/
static int tomoyo_path_chmod(const struct path *path, umode_t mode)
{
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, path,
mode & S_IALLUGO);
}
@@ -377,6 +409,9 @@ static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
{
int error = 0;
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
+ return 0;
+
if (uid_valid(uid))
error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path,
from_kuid(&init_user_ns, uid));
--
2.52.0
^ permalink raw reply related
* Re: [PATCH] samples/landlock: Bump ABI version to 8
From: Mickaël Salaün @ 2026-02-20 19:30 UTC (permalink / raw)
To: Günther Noack; +Cc: linux-security-module
In-Reply-To: <20260220160627.53913-1-gnoack3000@gmail.com>
Thanks, applied!
On Fri, Feb 20, 2026 at 05:06:27PM +0100, Günther Noack wrote:
> The sample tool should print a warning if it is not running on a
> kernel that provides the newest Landlock ABI version.
>
> Link: https://lore.kernel.org/all/20260218.ufao5Vaefa2u@digikod.net/
> Suggested-by: Mickaël Salaün <mic@digikod.net>
> Signed-off-by: Günther Noack <gnoack3000@gmail.com>
> ---
> samples/landlock/sandboxer.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
> index e7af02f98208..9f21088c0855 100644
> --- a/samples/landlock/sandboxer.c
> +++ b/samples/landlock/sandboxer.c
> @@ -299,7 +299,7 @@ static bool check_ruleset_scope(const char *const env_var,
>
> /* clang-format on */
>
> -#define LANDLOCK_ABI_LAST 7
> +#define LANDLOCK_ABI_LAST 8
>
> #define XSTR(s) #s
> #define STR(s) XSTR(s)
> @@ -436,7 +436,8 @@ int main(const int argc, char *const argv[], char *const *const envp)
> /* Removes LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON for ABI < 7 */
> supported_restrict_flags &=
> ~LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
> -
> + __attribute__((fallthrough));
> + case 7:
> /* Must be printed for any ABI < LANDLOCK_ABI_LAST. */
> fprintf(stderr,
> "Hint: You should update the running kernel "
> --
> 2.52.0
>
>
^ permalink raw reply
* [PATCH v2 2/2] keys/trusted_keys: move TPM-specific fields into trusted_tpm_options
From: Srish Srinivasan @ 2026-02-20 18:34 UTC (permalink / raw)
To: linux-integrity, keyrings
Cc: James.Bottomley, jarkko, zohar, stefanb, nayna, linux-kernel,
linux-security-module, ssrish
In-Reply-To: <20260220183426.80446-1-ssrish@linux.ibm.com>
The trusted_key_options struct contains TPM-specific fields (keyhandle,
keyauth, blobauth_len, blobauth, pcrinfo_len, pcrinfo, pcrlock, hash,
policydigest_len, policydigest, and policyhandle). This leads to the
accumulation of backend-specific fields in the generic options structure.
Define trusted_tpm_options structure and move the TPM-specific fields
there. Store a pointer to trusted_tpm_options in trusted_key_options's
private.
No functional change intended.
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
include/keys/trusted-type.h | 11 ---
include/keys/trusted_tpm.h | 14 ++++
security/keys/trusted-keys/trusted_tpm1.c | 95 ++++++++++++++---------
security/keys/trusted-keys/trusted_tpm2.c | 51 ++++++------
4 files changed, 102 insertions(+), 69 deletions(-)
diff --git a/include/keys/trusted-type.h b/include/keys/trusted-type.h
index 03527162613f..b80f250305b8 100644
--- a/include/keys/trusted-type.h
+++ b/include/keys/trusted-type.h
@@ -39,17 +39,6 @@ struct trusted_key_payload {
struct trusted_key_options {
uint16_t keytype;
- uint32_t keyhandle;
- unsigned char keyauth[TPM_DIGEST_SIZE];
- uint32_t blobauth_len;
- unsigned char blobauth[TPM_DIGEST_SIZE];
- uint32_t pcrinfo_len;
- unsigned char pcrinfo[MAX_PCRINFO_SIZE];
- int pcrlock;
- uint32_t hash;
- uint32_t policydigest_len;
- unsigned char policydigest[MAX_DIGEST_SIZE];
- uint32_t policyhandle;
void *private;
};
diff --git a/include/keys/trusted_tpm.h b/include/keys/trusted_tpm.h
index 0fadc6a4f166..355ebd36cbfd 100644
--- a/include/keys/trusted_tpm.h
+++ b/include/keys/trusted_tpm.h
@@ -7,6 +7,20 @@
extern struct trusted_key_ops trusted_key_tpm_ops;
+struct trusted_tpm_options {
+ uint32_t keyhandle;
+ unsigned char keyauth[TPM_DIGEST_SIZE];
+ uint32_t blobauth_len;
+ unsigned char blobauth[TPM_DIGEST_SIZE];
+ uint32_t pcrinfo_len;
+ unsigned char pcrinfo[MAX_PCRINFO_SIZE];
+ int pcrlock;
+ uint32_t hash;
+ uint32_t policydigest_len;
+ unsigned char policydigest[MAX_DIGEST_SIZE];
+ uint32_t policyhandle;
+};
+
int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index 216caef97ffc..741b1d47d9f8 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -48,12 +48,14 @@ enum {
static inline void dump_options(struct trusted_key_options *o)
{
+ struct trusted_tpm_options *private = o->private;
+
pr_debug("sealing key type %d\n", o->keytype);
- pr_debug("sealing key handle %0X\n", o->keyhandle);
- pr_debug("pcrlock %d\n", o->pcrlock);
- pr_debug("pcrinfo %d\n", o->pcrinfo_len);
+ pr_debug("sealing key handle %0X\n", private->keyhandle);
+ pr_debug("pcrlock %d\n", private->pcrlock);
+ pr_debug("pcrinfo %d\n", private->pcrinfo_len);
print_hex_dump(KERN_DEBUG, "pcrinfo ", DUMP_PREFIX_NONE,
- 16, 1, o->pcrinfo, o->pcrinfo_len, 0);
+ 16, 1, private->pcrinfo, private->pcrinfo_len, 0);
}
static inline void dump_sess(struct osapsess *s)
@@ -609,6 +611,7 @@ static int tpm_unseal(struct tpm_buf *tb,
static int key_seal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
+ struct trusted_tpm_options *private = o->private;
struct tpm_buf tb;
int ret;
@@ -619,9 +622,10 @@ static int key_seal(struct trusted_key_payload *p,
/* include migratable flag at end of sealed key */
p->key[p->key_len] = p->migratable;
- ret = tpm_seal(&tb, o->keytype, o->keyhandle, o->keyauth,
+ ret = tpm_seal(&tb, o->keytype, private->keyhandle, private->keyauth,
p->key, p->key_len + 1, p->blob, &p->blob_len,
- o->blobauth, o->pcrinfo, o->pcrinfo_len);
+ private->blobauth, private->pcrinfo,
+ private->pcrinfo_len);
if (ret < 0)
pr_info("srkseal failed (%d)\n", ret);
@@ -635,6 +639,7 @@ static int key_seal(struct trusted_key_payload *p,
static int key_unseal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
+ struct trusted_tpm_options *private = o->private;
struct tpm_buf tb;
int ret;
@@ -642,8 +647,8 @@ static int key_unseal(struct trusted_key_payload *p,
if (ret)
return ret;
- ret = tpm_unseal(&tb, o->keyhandle, o->keyauth, p->blob, p->blob_len,
- o->blobauth, p->key, &p->key_len);
+ ret = tpm_unseal(&tb, private->keyhandle, private->keyauth, p->blob,
+ p->blob_len, private->blobauth, p->key, &p->key_len);
if (ret < 0)
pr_info("srkunseal failed (%d)\n", ret);
else
@@ -680,6 +685,7 @@ static const match_table_t key_tokens = {
static int getoptions(char *c, struct trusted_key_payload *pay,
struct trusted_key_options *opt)
{
+ struct trusted_tpm_options *private = opt->private;
substring_t args[MAX_OPT_ARGS];
char *p = c;
int token;
@@ -695,7 +701,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
if (tpm2 < 0)
return tpm2;
- opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
+ private->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
if (!c)
return 0;
@@ -709,11 +715,11 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
switch (token) {
case Opt_pcrinfo:
- opt->pcrinfo_len = strlen(args[0].from) / 2;
- if (opt->pcrinfo_len > MAX_PCRINFO_SIZE)
+ private->pcrinfo_len = strlen(args[0].from) / 2;
+ if (private->pcrinfo_len > MAX_PCRINFO_SIZE)
return -EINVAL;
- res = hex2bin(opt->pcrinfo, args[0].from,
- opt->pcrinfo_len);
+ res = hex2bin(private->pcrinfo, args[0].from,
+ private->pcrinfo_len);
if (res < 0)
return -EINVAL;
break;
@@ -722,12 +728,12 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
if (res < 0)
return -EINVAL;
opt->keytype = SEAL_keytype;
- opt->keyhandle = handle;
+ private->keyhandle = handle;
break;
case Opt_keyauth:
if (strlen(args[0].from) != 2 * SHA1_DIGEST_SIZE)
return -EINVAL;
- res = hex2bin(opt->keyauth, args[0].from,
+ res = hex2bin(private->keyauth, args[0].from,
SHA1_DIGEST_SIZE);
if (res < 0)
return -EINVAL;
@@ -738,21 +744,23 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
* hex strings. TPM 2.0 authorizations are simple
* passwords (although it can take a hash as well)
*/
- opt->blobauth_len = strlen(args[0].from);
+ private->blobauth_len = strlen(args[0].from);
- if (opt->blobauth_len == 2 * TPM_DIGEST_SIZE) {
- res = hex2bin(opt->blobauth, args[0].from,
+ if (private->blobauth_len == 2 * TPM_DIGEST_SIZE) {
+ res = hex2bin(private->blobauth, args[0].from,
TPM_DIGEST_SIZE);
if (res < 0)
return -EINVAL;
- opt->blobauth_len = TPM_DIGEST_SIZE;
+ private->blobauth_len = TPM_DIGEST_SIZE;
break;
}
- if (tpm2 && opt->blobauth_len <= sizeof(opt->blobauth)) {
- memcpy(opt->blobauth, args[0].from,
- opt->blobauth_len);
+ if (tpm2 &&
+ private->blobauth_len <=
+ sizeof(private->blobauth)) {
+ memcpy(private->blobauth, args[0].from,
+ private->blobauth_len);
break;
}
@@ -770,14 +778,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
res = kstrtoul(args[0].from, 10, &lock);
if (res < 0)
return -EINVAL;
- opt->pcrlock = lock;
+ private->pcrlock = lock;
break;
case Opt_hash:
if (test_bit(Opt_policydigest, &token_mask))
return -EINVAL;
for (i = 0; i < HASH_ALGO__LAST; i++) {
if (!strcmp(args[0].from, hash_algo_name[i])) {
- opt->hash = i;
+ private->hash = i;
break;
}
}
@@ -789,14 +797,14 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
}
break;
case Opt_policydigest:
- digest_len = hash_digest_size[opt->hash];
+ digest_len = hash_digest_size[private->hash];
if (!tpm2 || strlen(args[0].from) != (2 * digest_len))
return -EINVAL;
- res = hex2bin(opt->policydigest, args[0].from,
+ res = hex2bin(private->policydigest, args[0].from,
digest_len);
if (res < 0)
return -EINVAL;
- opt->policydigest_len = digest_len;
+ private->policydigest_len = digest_len;
break;
case Opt_policyhandle:
if (!tpm2)
@@ -804,7 +812,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
res = kstrtoul(args[0].from, 16, &handle);
if (res < 0)
return -EINVAL;
- opt->policyhandle = handle;
+ private->policyhandle = handle;
break;
default:
return -EINVAL;
@@ -815,6 +823,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
static struct trusted_key_options *trusted_options_alloc(void)
{
+ struct trusted_tpm_options *private;
struct trusted_key_options *options;
int tpm2;
@@ -827,14 +836,23 @@ static struct trusted_key_options *trusted_options_alloc(void)
/* set any non-zero defaults */
options->keytype = SRK_keytype;
- if (!tpm2)
- options->keyhandle = SRKHANDLE;
+ private = kzalloc(sizeof(*private), GFP_KERNEL);
+ if (!private) {
+ kfree_sensitive(options);
+ options = NULL;
+ } else {
+ if (!tpm2)
+ private->keyhandle = SRKHANDLE;
+
+ options->private = private;
+ }
}
return options;
}
static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
{
+ struct trusted_tpm_options *private = NULL;
struct trusted_key_options *options = NULL;
int ret = 0;
int tpm2;
@@ -852,7 +870,8 @@ static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
goto out;
dump_options(options);
- if (!options->keyhandle && !tpm2) {
+ private = options->private;
+ if (!private->keyhandle && !tpm2) {
ret = -EINVAL;
goto out;
}
@@ -866,20 +885,22 @@ static int trusted_tpm_seal(struct trusted_key_payload *p, char *datablob)
goto out;
}
- if (options->pcrlock) {
- ret = pcrlock(options->pcrlock);
+ if (private->pcrlock) {
+ ret = pcrlock(private->pcrlock);
if (ret < 0) {
pr_info("pcrlock failed (%d)\n", ret);
goto out;
}
}
out:
+ kfree_sensitive(options->private);
kfree_sensitive(options);
return ret;
}
static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
{
+ struct trusted_tpm_options *private = NULL;
struct trusted_key_options *options = NULL;
int ret = 0;
int tpm2;
@@ -897,7 +918,8 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
goto out;
dump_options(options);
- if (!options->keyhandle && !tpm2) {
+ private = options->private;
+ if (!private->keyhandle && !tpm2) {
ret = -EINVAL;
goto out;
}
@@ -909,14 +931,15 @@ static int trusted_tpm_unseal(struct trusted_key_payload *p, char *datablob)
if (ret < 0)
pr_info("key_unseal failed (%d)\n", ret);
- if (options->pcrlock) {
- ret = pcrlock(options->pcrlock);
+ if (private->pcrlock) {
+ ret = pcrlock(private->pcrlock);
if (ret < 0) {
pr_info("pcrlock failed (%d)\n", ret);
goto out;
}
}
out:
+ kfree_sensitive(options->private);
kfree_sensitive(options);
return ret;
}
diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c
index 6340823f8b53..94e01249b921 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -24,6 +24,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
struct trusted_key_options *options,
u8 *src, u32 len)
{
+ struct trusted_tpm_options *private = options->private;
const int SCRATCH_SIZE = PAGE_SIZE;
u8 *scratch = kmalloc(SCRATCH_SIZE, GFP_KERNEL);
u8 *work = scratch, *work1;
@@ -46,7 +47,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
work = asn1_encode_oid(work, end_work, tpm2key_oid,
asn1_oid_len(tpm2key_oid));
- if (options->blobauth_len == 0) {
+ if (private->blobauth_len == 0) {
unsigned char bool[3], *w = bool;
/* tag 0 is emptyAuth */
w = asn1_encode_boolean(w, w + sizeof(bool), true);
@@ -69,7 +70,7 @@ static int tpm2_key_encode(struct trusted_key_payload *payload,
goto err;
}
- work = asn1_encode_integer(work, end_work, options->keyhandle);
+ work = asn1_encode_integer(work, end_work, private->keyhandle);
work = asn1_encode_octet_string(work, end_work, pub, pub_len);
work = asn1_encode_octet_string(work, end_work, priv, priv_len);
@@ -102,6 +103,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
struct trusted_key_options *options,
u8 **buf)
{
+ struct trusted_tpm_options *private = options->private;
int ret;
struct tpm2_key_context ctx;
u8 *blob;
@@ -121,7 +123,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload,
return -ENOMEM;
*buf = blob;
- options->keyhandle = ctx.parent;
+ private->keyhandle = ctx.parent;
memcpy(blob, ctx.priv, ctx.priv_len);
blob += ctx.priv_len;
@@ -233,6 +235,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
+ struct trusted_tpm_options *private = options->private;
off_t offset = TPM_HEADER_SIZE;
struct tpm_buf buf, sized;
int blob_len = 0;
@@ -240,11 +243,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
u32 flags;
int rc;
- hash = tpm2_find_hash_alg(options->hash);
+ hash = tpm2_find_hash_alg(private->hash);
if (hash < 0)
return hash;
- if (!options->keyhandle)
+ if (!private->keyhandle)
return -EINVAL;
rc = tpm_try_get_ops(chip);
@@ -268,18 +271,19 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
goto out_put;
}
- rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
+ rc = tpm_buf_append_name(chip, &buf, private->keyhandle, NULL);
if (rc)
goto out;
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_DECRYPT,
- options->keyauth, TPM_DIGEST_SIZE);
+ private->keyauth, TPM_DIGEST_SIZE);
/* sensitive */
- tpm_buf_append_u16(&sized, options->blobauth_len);
+ tpm_buf_append_u16(&sized, private->blobauth_len);
- if (options->blobauth_len)
- tpm_buf_append(&sized, options->blobauth, options->blobauth_len);
+ if (private->blobauth_len)
+ tpm_buf_append(&sized, private->blobauth,
+ private->blobauth_len);
tpm_buf_append_u16(&sized, payload->key_len);
tpm_buf_append(&sized, payload->key, payload->key_len);
@@ -292,14 +296,15 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
/* key properties */
flags = 0;
- flags |= options->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
+ flags |= private->policydigest_len ? 0 : TPM2_OA_USER_WITH_AUTH;
flags |= payload->migratable ? 0 : (TPM2_OA_FIXED_TPM | TPM2_OA_FIXED_PARENT);
tpm_buf_append_u32(&sized, flags);
/* policy */
- tpm_buf_append_u16(&sized, options->policydigest_len);
- if (options->policydigest_len)
- tpm_buf_append(&sized, options->policydigest, options->policydigest_len);
+ tpm_buf_append_u16(&sized, private->policydigest_len);
+ if (private->policydigest_len)
+ tpm_buf_append(&sized, private->policydigest,
+ private->policydigest_len);
/* public parameters */
tpm_buf_append_u16(&sized, TPM_ALG_NULL);
@@ -373,6 +378,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
u32 *blob_handle)
{
u8 *blob_ref __free(kfree) = NULL;
+ struct trusted_tpm_options *private = options->private;
struct tpm_buf buf;
unsigned int private_len;
unsigned int public_len;
@@ -392,7 +398,7 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
}
/* new format carries keyhandle but old format doesn't */
- if (!options->keyhandle)
+ if (!private->keyhandle)
return -EINVAL;
/* must be big enough for at least the two be16 size counts */
@@ -433,11 +439,11 @@ static int tpm2_load_cmd(struct tpm_chip *chip,
return rc;
}
- rc = tpm_buf_append_name(chip, &buf, options->keyhandle, NULL);
+ rc = tpm_buf_append_name(chip, &buf, private->keyhandle, NULL);
if (rc)
goto out;
- tpm_buf_append_hmac_session(chip, &buf, 0, options->keyauth,
+ tpm_buf_append_hmac_session(chip, &buf, 0, private->keyauth,
TPM_DIGEST_SIZE);
tpm_buf_append(&buf, blob, blob_len);
@@ -481,6 +487,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
struct trusted_key_options *options,
u32 blob_handle)
{
+ struct trusted_tpm_options *private = options->private;
struct tpm_header *head;
struct tpm_buf buf;
u16 data_len;
@@ -502,10 +509,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
if (rc)
goto out;
- if (!options->policyhandle) {
+ if (!private->policyhandle) {
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT,
- options->blobauth,
- options->blobauth_len);
+ private->blobauth,
+ private->blobauth_len);
} else {
/*
* FIXME: The policy session was generated outside the
@@ -518,9 +525,9 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
* could repeat our actions with the exfiltrated
* password.
*/
- tpm2_buf_append_auth(&buf, options->policyhandle,
+ tpm2_buf_append_auth(&buf, private->policyhandle,
NULL /* nonce */, 0, 0,
- options->blobauth, options->blobauth_len);
+ private->blobauth, private->blobauth_len);
if (tpm2_chip_auth(chip)) {
tpm_buf_append_hmac_session(chip, &buf, TPM2_SA_ENCRYPT, NULL, 0);
} else {
--
2.43.0
^ permalink raw reply related
* [PATCH v2 1/2] keys/trusted_keys: clean up debug message logging in the tpm backend
From: Srish Srinivasan @ 2026-02-20 18:34 UTC (permalink / raw)
To: linux-integrity, keyrings
Cc: James.Bottomley, jarkko, zohar, stefanb, nayna, linux-kernel,
linux-security-module, ssrish
In-Reply-To: <20260220183426.80446-1-ssrish@linux.ibm.com>
The TPM trusted-keys backend uses a local TPM_DEBUG guard and pr_info()
for logging debug information.
Replace pr_info() with pr_debug(), and use KERN_DEBUG for print_hex_dump().
Remove TPM_DEBUG.
No functional change intended.
Signed-off-by: Srish Srinivasan <ssrish@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
security/keys/trusted-keys/trusted_tpm1.c | 40 +++++++----------------
1 file changed, 12 insertions(+), 28 deletions(-)
diff --git a/security/keys/trusted-keys/trusted_tpm1.c b/security/keys/trusted-keys/trusted_tpm1.c
index c865c97aa1b4..216caef97ffc 100644
--- a/security/keys/trusted-keys/trusted_tpm1.c
+++ b/security/keys/trusted-keys/trusted_tpm1.c
@@ -46,28 +46,25 @@ enum {
SRK_keytype = 4
};
-#define TPM_DEBUG 0
-
-#if TPM_DEBUG
static inline void dump_options(struct trusted_key_options *o)
{
- pr_info("sealing key type %d\n", o->keytype);
- pr_info("sealing key handle %0X\n", o->keyhandle);
- pr_info("pcrlock %d\n", o->pcrlock);
- pr_info("pcrinfo %d\n", o->pcrinfo_len);
- print_hex_dump(KERN_INFO, "pcrinfo ", DUMP_PREFIX_NONE,
+ pr_debug("sealing key type %d\n", o->keytype);
+ pr_debug("sealing key handle %0X\n", o->keyhandle);
+ pr_debug("pcrlock %d\n", o->pcrlock);
+ pr_debug("pcrinfo %d\n", o->pcrinfo_len);
+ print_hex_dump(KERN_DEBUG, "pcrinfo ", DUMP_PREFIX_NONE,
16, 1, o->pcrinfo, o->pcrinfo_len, 0);
}
static inline void dump_sess(struct osapsess *s)
{
- print_hex_dump(KERN_INFO, "trusted-key: handle ", DUMP_PREFIX_NONE,
+ print_hex_dump(KERN_DEBUG, "trusted-key: handle ", DUMP_PREFIX_NONE,
16, 1, &s->handle, 4, 0);
- pr_info("secret:\n");
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
+ pr_debug("secret:\n");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,
16, 1, &s->secret, SHA1_DIGEST_SIZE, 0);
- pr_info("trusted-key: enonce:\n");
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE,
+ pr_debug("trusted-key: enonce:\n");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,
16, 1, &s->enonce, SHA1_DIGEST_SIZE, 0);
}
@@ -75,23 +72,10 @@ static inline void dump_tpm_buf(unsigned char *buf)
{
int len;
- pr_info("\ntpm buffer\n");
+ pr_debug("\ntpm buffer\n");
len = LOAD32(buf, TPM_SIZE_OFFSET);
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
-}
-#else
-static inline void dump_options(struct trusted_key_options *o)
-{
-}
-
-static inline void dump_sess(struct osapsess *s)
-{
-}
-
-static inline void dump_tpm_buf(unsigned char *buf)
-{
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 16, 1, buf, len, 0);
}
-#endif
static int TSS_rawhmac(unsigned char *digest, const unsigned char *key,
unsigned int keylen, ...)
--
2.43.0
^ permalink raw reply related
* [PATCH v2 0/2] move TPM-specific fields into trusted_tpm_options
From: Srish Srinivasan @ 2026-02-20 18:34 UTC (permalink / raw)
To: linux-integrity, keyrings
Cc: James.Bottomley, jarkko, zohar, stefanb, nayna, linux-kernel,
linux-security-module, ssrish
The backend-agnostic trusted_key_options structure carries TPM-specific
fields. With the recent addition of a backend-private pointer, these fields
can be moved out of the generic options structure.
This patch series intends to reloacte all TPM-spcific fields into a newly
defined trusted_tpm_options structure. A pointer to the trusted_tpm_options
struct is stored in trusted_key_option's private.
Along with the migration of TPM-specific fields, this patch series includes
a preparatory clean-up patch: replacing pr_info() with pr_debug() and using
KERN_DEBUG for print_hex_dump() for logging debug information.
Testing covered both TPM 1.2 and TPM 2.0 backends (virtual environment),
including trusted key creation, revocation, unlinking, invalidation, and
loading keys from encrypted blobs. I would welcome any additional testing
from upstream to further strengthen the validation.
Changelog:
v2:
* Exclude the bug-fix patch as it has already been applied to 6.19-rc7
* Rename instances of trusted_tpm_options from tpm_opts to private
* Use pr_debug and KERN_DEBUG for logging debug messages (preparatory
clean up patch)
* Address comments from Jarkko
Srish Srinivasan (2):
keys/trusted_keys: clean up debug message logging in the tpm backend
keys/trusted_keys: move TPM-specific fields into trusted_tpm_options
include/keys/trusted-type.h | 11 --
include/keys/trusted_tpm.h | 14 +++
security/keys/trusted-keys/trusted_tpm1.c | 129 ++++++++++++----------
security/keys/trusted-keys/trusted_tpm2.c | 51 +++++----
4 files changed, 111 insertions(+), 94 deletions(-)
--
2.43.0
^ permalink raw reply
* Re: [PATCH v9 01/11] KEYS: trusted: Use get_random-fallback for TPM
From: Chris Fenner @ 2026-02-20 18:30 UTC (permalink / raw)
To: Mimi Zohar
Cc: Jarkko Sakkinen, linux-integrity, Jonathan McDowell, Eric Biggers,
James Bottomley, David Howells, Paul Moore, James Morris,
Serge E. Hallyn, open list:KEYS-TRUSTED,
open list:SECURITY SUBSYSTEM, open list, Roberto Sassu
In-Reply-To: <06a08cbbe47111a1795e5dcd42fb8cc4be643a72.camel@linux.ibm.com>
My conclusion about TCG_TPM2_HMAC after [1] and [2] was that
TPM2_TCG_HMAC doesn't (or didn't at the time) actually solve the
threat model it claims to (active interposer adversaries), while
dramatically increasing the cost of many kernel TPM activities beyond
the amount that would have been required to just solve for
passive/bus-sniffer interposer adversaries. The added symmetric crypto
required to secure a TPM transaction is almost not noticeable; the big
performance problem is the re-bootstrapping of the session with ECDH
for every command.
My primary concern at that time was, essentially, that TCG_TPM2_HMAC
punts on checking that the key that was used to secure the session was
actually resident in a real TPM and not just an interposer adversary.
I wrote up my understanding at
https://www.dlp.rip/decorative-cryptography, for anyone who wants a
long-form opinionated take :).
Unless I'm wrong, or TCG_TPM2_HMAC has changed dramatically since
August, I don't think "TPM2_TCG_HMAC makes this too costly" is a
compelling reason to make a security decision. (There could be other
reasons to make choices about whether to use the TPM as a source of
randomness in the kernel! This just isn't one IMHO.)
The version of TCG_TPM2_HMAC that I'd like to see someday would be one
that fully admits that its threat model is only passive interposers,
and sets up one session upon startup and ContextSaves/ContextLoads it
back into the TPM as needed in order to secure parameter encryption
for e.g., GetRandom() and Unseal() calls.
[1]: https://lore.kernel.org/linux-integrity/CAMigqh2nwuRRxaLyOJ+QaTJ+XGmkQj=rMj5K9GP1bCcXp2OsBQ@mail.gmail.com/
[2]: https://lore.kernel.org/linux-integrity/20250825203223.629515-1-jarkko@kernel.org/
Thanks
Chris
On Fri, Feb 20, 2026 at 10:04 AM Mimi Zohar <zohar@linux.ibm.com> wrote:
>
> [Cc: Chris Fenner, Jonathan McDowell, Roberto]
>
> On Sun, 2026-01-25 at 21:25 +0200, Jarkko Sakkinen wrote:
> > 1. tpm2_get_random() is costly when TCG_TPM2_HMAC is enabled and thus its
> > use should be pooled rather than directly used. This both reduces
> > latency and improves its predictability.
>
> If the concern is the latency of encrypting the bus session, please remember
> that:
>
> - Not all environments expose the TPM bus to sniffing.
> - The current TPM trusted keys design is based on TPM RNG, but already allows it
> to be replaced with the kernel RNG via the "trusted_rng=kernel" boot command
> line option.
> - The proposed patch removes that possibility for no reason.
>
> Mimi & Elaine
>
>
^ permalink raw reply
* Re: [PATCH v9 01/11] KEYS: trusted: Use get_random-fallback for TPM
From: Mimi Zohar @ 2026-02-20 18:04 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-integrity, Chris Fenner, Jonathan McDowell
Cc: Eric Biggers, James Bottomley, David Howells, Paul Moore,
James Morris, Serge E. Hallyn, open list:KEYS-TRUSTED,
open list:SECURITY SUBSYSTEM, open list, Roberto Sassu
In-Reply-To: <20260125192526.782202-2-jarkko@kernel.org>
[Cc: Chris Fenner, Jonathan McDowell, Roberto]
On Sun, 2026-01-25 at 21:25 +0200, Jarkko Sakkinen wrote:
> 1. tpm2_get_random() is costly when TCG_TPM2_HMAC is enabled and thus its
> use should be pooled rather than directly used. This both reduces
> latency and improves its predictability.
If the concern is the latency of encrypting the bus session, please remember
that:
- Not all environments expose the TPM bus to sniffing.
- The current TPM trusted keys design is based on TPM RNG, but already allows it
to be replaced with the kernel RNG via the "trusted_rng=kernel" boot command
line option.
- The proposed patch removes that possibility for no reason.
Mimi & Elaine
^ permalink raw reply
* Re: [PATCH v15 9/9] rust: page: add `from_raw()`
From: Tamir Duberstein @ 2026-02-20 17:50 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Andreas Hindborg, Benno Lossin, Miguel Ojeda, Gary Guo,
Björn Roy Baron, 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, linux-kernel,
rust-for-linux, linux-block, linux-security-module, dri-devel,
linux-fsdevel, linux-mm, linux-pm, linux-pci
In-Reply-To: <CANiq72myc+tCEHm0WtZspZHWwsSzvesxsmUvk31=GCdUN_zVNA@mail.gmail.com>
On Fri, Feb 20, 2026 at 12:34 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Fri, Feb 20, 2026 at 10:52 AM Andreas Hindborg <a.hindborg@kernel.org> wrote:
> >
> > + /// Create a `&Page` from a raw `struct page` pointer
>
> Please end sentences with a period.
>
> > + // SAFETY: By function safety requirements, ptr is not null and is
>
> Please use Markdown in comments: `ptr`.
>
> > + /// `ptr` must be valid for use as a reference for the duration of `'a`.
>
> Since we will likely try to starting introducing at least a subset of
> the Safety Standard soon, we should try to use standard terms.
>
> So I think this "valid for use as a reference" is not an established
> one, no? Isn't "convertible to a shared reference" the official term?
>
> https://doc.rust-lang.org/std/ptr/index.html#pointer-to-reference-conversion
>
> In fact, I see `as_ref_unchecked()` and `as_mut_unchecked()` just got
> stabilized for 1.95.0, so we should probably starting using those were
> applicable as we bump the minimum, but we should probably use already
> a similar wording as the standard library for the safety section and
> the comment:
>
> "`ptr` must be [convertible to a reference](...)."
>
> where the term is a link to that section. Cc'ing Benno.
>
> I have created a (future) issue for that:
>
> https://github.com/Rust-for-Linux/linux/issues/1225
>
> Cc'ing Tamir since this is close to the cast work, so it may interest
> him as well.
Thanks Miguel -- FWIW there's no current cast work on my plate, I
believe everything was merged except for provenance which was a bit
too hard to work with given MSRV.
^ permalink raw reply
* Re: [PATCH v15 9/9] rust: page: add `from_raw()`
From: Miguel Ojeda @ 2026-02-20 17:33 UTC (permalink / raw)
To: Andreas Hindborg, Tamir Duberstein, Benno Lossin
Cc: Miguel Ojeda, Gary Guo, Björn Roy Baron, 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, linux-kernel, rust-for-linux, linux-block,
linux-security-module, dri-devel, linux-fsdevel, linux-mm,
linux-pm, linux-pci
In-Reply-To: <20260220-unique-ref-v15-9-893ed86b06cc@kernel.org>
On Fri, Feb 20, 2026 at 10:52 AM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
> + /// Create a `&Page` from a raw `struct page` pointer
Please end sentences with a period.
> + // SAFETY: By function safety requirements, ptr is not null and is
Please use Markdown in comments: `ptr`.
> + /// `ptr` must be valid for use as a reference for the duration of `'a`.
Since we will likely try to starting introducing at least a subset of
the Safety Standard soon, we should try to use standard terms.
So I think this "valid for use as a reference" is not an established
one, no? Isn't "convertible to a shared reference" the official term?
https://doc.rust-lang.org/std/ptr/index.html#pointer-to-reference-conversion
In fact, I see `as_ref_unchecked()` and `as_mut_unchecked()` just got
stabilized for 1.95.0, so we should probably starting using those were
applicable as we bump the minimum, but we should probably use already
a similar wording as the standard library for the safety section and
the comment:
"`ptr` must be [convertible to a reference](...)."
where the term is a link to that section. Cc'ing Benno.
I have created a (future) issue for that:
https://github.com/Rust-for-Linux/linux/issues/1225
Cc'ing Tamir since this is close to the cast work, so it may interest
him as well.
Cheers,
Miguel
^ permalink raw reply
* Re: [PATCH v5 4/9] landlock/selftests: Test LANDLOCK_ACCESS_FS_RESOLVE_UNIX
From: Günther Noack @ 2026-02-20 17:04 UTC (permalink / raw)
To: Mickaël Salaün
Cc: John Johansen, Justin Suess, Tingmao Wang, linux-security-module,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi
In-Reply-To: <20260220.5f431119d04a@gnoack.org>
On Fri, Feb 20, 2026 at 05:27:52PM +0100, Günther Noack wrote:
> On Wed, Feb 18, 2026 at 08:11:26PM +0100, Mickaël Salaün wrote:
> > On Sun, Feb 15, 2026 at 11:51:52AM +0100, Günther Noack wrote:
> > > --- a/tools/testing/selftests/landlock/fs_test.c
> > > +++ b/tools/testing/selftests/landlock/fs_test.c
>
> > > + strncpy(addr.sun_path, path, sizeof(addr.sun_path));
> >
> > fs_test.c: In function ‘set_up_named_unix_server’:
> > fs_test.c:4125:9: error: ‘strncpy’ specified bound 108 equals destination size [-Werror=stringop-truncation]
> > 4125 | strncpy(addr.sun_path, path, sizeof(addr.sun_path));
> > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >
> > We should also ASSERT the result to make sure path's length is not too big.
>
> Fair enough, will do, because it's less confusing.
>
> (FWIW though, I think Linux can technically deal with a sun_path that
> does not end in a NUL byte. See the long comment in unix_mkname_bsd().
> But that's a Linux peculiarity.)
FYI, before the question comes up why I didn't use strscpy: We don't
have that library in these userspace tests, so it is now:
struct sockaddr_un addr = {
.sun_family = AF_UNIX,
};
ASSERT_LT(strlen(path), sizeof(addr.sun_path));
strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
–Günther
^ permalink raw reply
* Re: [PATCH v5 4/9] landlock/selftests: Test LANDLOCK_ACCESS_FS_RESOLVE_UNIX
From: Günther Noack @ 2026-02-20 16:27 UTC (permalink / raw)
To: Mickaël Salaün
Cc: John Johansen, Justin Suess, Tingmao Wang, linux-security-module,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi
In-Reply-To: <20260218.aser1cu7Aewi@digikod.net>
On Wed, Feb 18, 2026 at 08:11:26PM +0100, Mickaël Salaün wrote:
> On Sun, Feb 15, 2026 at 11:51:52AM +0100, Günther Noack wrote:
> > --- a/tools/testing/selftests/landlock/fs_test.c
> > +++ b/tools/testing/selftests/landlock/fs_test.c
> > + strncpy(addr.sun_path, path, sizeof(addr.sun_path));
>
> fs_test.c: In function ‘set_up_named_unix_server’:
> fs_test.c:4125:9: error: ‘strncpy’ specified bound 108 equals destination size [-Werror=stringop-truncation]
> 4125 | strncpy(addr.sun_path, path, sizeof(addr.sun_path));
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> We should also ASSERT the result to make sure path's length is not too big.
Fair enough, will do, because it's less confusing.
(FWIW though, I think Linux can technically deal with a sun_path that
does not end in a NUL byte. See the long comment in unix_mkname_bsd().
But that's a Linux peculiarity.)
–Günther
^ permalink raw reply
* Re: [PATCH v5 3/9] samples/landlock: Add support for named UNIX domain socket restrictions
From: Günther Noack @ 2026-02-20 16:08 UTC (permalink / raw)
To: Mickaël Salaün
Cc: John Johansen, Justin Suess, linux-security-module, Tingmao Wang,
Samasth Norway Ananda, Matthieu Buffet, Mikhail Ivanov,
konstantin.meskhidze, Demi Marie Obenour, Alyssa Ross, Jann Horn,
Tahera Fahimi
In-Reply-To: <20260218.ufao5Vaefa2u@digikod.net>
On Wed, Feb 18, 2026 at 10:37:31AM +0100, Mickaël Salaün wrote:
> On Sun, Feb 15, 2026 at 11:51:51AM +0100, Günther Noack wrote:
> > @@ -444,6 +446,13 @@ int main(const int argc, char *const argv[], char *const *const envp)
> > "provided by ABI version %d (instead of %d).\n",
> > LANDLOCK_ABI_LAST, abi);
> > __attribute__((fallthrough));
> > + case 7:
> > + __attribute__((fallthrough));
>
> The current code should print the hint when ABI <= 7. Please send a
> dedicated patch to fix the TSYNC-related changes.
Good catch, thanks! I sent a follow-up.
https://lore.kernel.org/all/20260220160627.53913-1-gnoack3000@gmail.com/
–Günther
^ permalink raw reply
* [PATCH] samples/landlock: Bump ABI version to 8
From: Günther Noack @ 2026-02-20 16:06 UTC (permalink / raw)
To: Mickaël Salaün; +Cc: linux-security-module, Günther Noack
The sample tool should print a warning if it is not running on a
kernel that provides the newest Landlock ABI version.
Link: https://lore.kernel.org/all/20260218.ufao5Vaefa2u@digikod.net/
Suggested-by: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
---
samples/landlock/sandboxer.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index e7af02f98208..9f21088c0855 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -299,7 +299,7 @@ static bool check_ruleset_scope(const char *const env_var,
/* clang-format on */
-#define LANDLOCK_ABI_LAST 7
+#define LANDLOCK_ABI_LAST 8
#define XSTR(s) #s
#define STR(s) XSTR(s)
@@ -436,7 +436,8 @@ int main(const int argc, char *const argv[], char *const *const envp)
/* Removes LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON for ABI < 7 */
supported_restrict_flags &=
~LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
-
+ __attribute__((fallthrough));
+ case 7:
/* Must be printed for any ABI < LANDLOCK_ABI_LAST. */
fprintf(stderr,
"Hint: You should update the running kernel "
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v6] lsm: Add LSM hook security_unix_find
From: Günther Noack @ 2026-02-20 15:49 UTC (permalink / raw)
To: Justin Suess
Cc: brauner, demiobenour, fahimitahera, hi, horms, ivanov.mikhail1,
jannh, jmorris, john.johansen, konstantin.meskhidze,
linux-security-module, m, matthieu, mic, netdev, paul,
samasth.norway.ananda, serge, viro
In-Reply-To: <20260219200459.1474232-1-utilityemal77@gmail.com>
Hello!
On Thu, Feb 19, 2026 at 03:04:59PM -0500, Justin Suess wrote:
> diff --git a/security/security.c b/security/security.c
> index 67af9228c4e9..c73196b8db4b 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -4731,6 +4731,26 @@ int security_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
>
> #endif /* CONFIG_SECURITY_NETWORK */
>
> +#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_SECURITY_PATH)
> +/**
> + * security_unix_find() - Check if a named AF_UNIX socket can connect
> + * @path: path of the socket being connected to
> + * @other: peer sock
> + * @flags: flags associated with the socket
> + *
> + * This hook is called to check permissions before connecting to a named
> + * AF_UNIX socket.
Nit: Could we please insert a sentence about locking here?
Something like:
The caller holds no locks on @other.
(Originally brought up by Mickaël in
https://lore.kernel.org/all/20260217.lievaS8eeng8@digikod.net/)
Thanks,
–Günther
^ permalink raw reply
* Re: [PATCH v5 2/9] landlock: Control pathname UNIX domain socket resolution by path
From: Günther Noack @ 2026-02-20 14:33 UTC (permalink / raw)
To: Mickaël Salaün
Cc: John Johansen, Tingmao Wang, Justin Suess, Jann Horn,
linux-security-module, Samasth Norway Ananda, Matthieu Buffet,
Mikhail Ivanov, konstantin.meskhidze, Demi Marie Obenour,
Alyssa Ross, Tahera Fahimi, netdev
In-Reply-To: <20260217.lievaS8eeng8@digikod.net>
+netdev, we could use some advice on the locking approach in af_unix (see below)
On Wed, Feb 18, 2026 at 10:37:14AM +0100, Mickaël Salaün wrote:
> On Sun, Feb 15, 2026 at 11:51:50AM +0100, Günther Noack wrote:
> > diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
> > index f88fa1f68b77..3a8fc3af0d64 100644
> > --- a/include/uapi/linux/landlock.h
> > +++ b/include/uapi/linux/landlock.h
> > @@ -248,6 +248,15 @@ struct landlock_net_port_attr {
> > *
> > * This access right is available since the fifth version of the Landlock
> > * ABI.
> > + * - %LANDLOCK_ACCESS_FS_RESOLVE_UNIX: Look up pathname UNIX domain sockets
> > + * (:manpage:`unix(7)`). On UNIX domain sockets, this restricts both calls to
> > + * :manpage:`connect(2)` as well as calls to :manpage:`sendmsg(2)` with an
> > + * explicit recipient address.
> > + *
> > + * This access right only applies to connections to UNIX server sockets which
> > + * were created outside of the newly created Landlock domain (e.g. from within
> > + * a parent domain or from an unrestricted process). Newly created UNIX
> > + * servers within the same Landlock domain continue to be accessible.
>
> It might help to add a reference to the explicit scope mechanism.
>
> Please squash patch 9/9 into this one and also add a reference here to
> the rationale described in security/landlock.rst
Sounds good, will do.
> > +static void unmask_scoped_access(const struct landlock_ruleset *const client,
> > + const struct landlock_ruleset *const server,
> > + struct layer_access_masks *const masks,
> > + const access_mask_t access)
>
> This helper should be moved to task.c and factored out with
> domain_is_scoped(). This should be a dedicated patch.
(already discussed in another follow-up mail)
> > +static int hook_unix_find(const struct path *const path, struct sock *other,
> > + int flags)
> > +{
> > + const struct landlock_ruleset *dom_other;
> > + const struct landlock_cred_security *subject;
> > + struct layer_access_masks layer_masks;
> > + struct landlock_request request = {};
> > + static const struct access_masks fs_resolve_unix = {
> > + .fs = LANDLOCK_ACCESS_FS_RESOLVE_UNIX,
> > + };
> > +
> > + /* Lookup for the purpose of saving coredumps is OK. */
> > + if (unlikely(flags & SOCK_COREDUMP))
> > + return 0;
> > +
> > + /* Access to the same (or a lower) domain is always allowed. */
> > + subject = landlock_get_applicable_subject(current_cred(),
> > + fs_resolve_unix, NULL);
> > +
> > + if (!subject)
> > + return 0;
> > +
> > + if (!landlock_init_layer_masks(subject->domain, fs_resolve_unix.fs,
> > + &layer_masks, LANDLOCK_KEY_INODE))
> > + return 0;
> > +
> > + /* Checks the layers in which we are connecting within the same domain. */
> > + dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
>
> We need to call unix_state_lock(other) before reading it, and check for
> SOCK_DEAD, and check sk_socket before dereferencing it. Indeed,
> the socket can be make orphan (see unix_dgram_sendmsg and
> unix_stream_connect). I *think* a socket cannot be "resurrected" or
> recycled once dead, so we may assume there is no race condition wrt
> dom_other, but please double check. This lockless call should be made
> clear in the LSM hook. It's OK to not lock the socket before
> security_unix_find() (1) because no LSM might implement and (2) they
> might not need to lock the socket (e.g. if the caller is not sandboxed).
>
> The updated code should look something like this:
>
> unix_state_unlock(other);
> if (unlikely(sock_flag(other, SOCK_DEAD) || !other->sk_socket)) {
> unix_state_unlock(other);
> return 0;
> }
>
> dom_other = landlock_cred(other->sk_socket->file->f_cred)->domain;
> unix_state_unlock(other);
Thank you for spotting the locking concern!
@anyone from netdev, could you please advise on the correct locking
approach here?
* Do we need ot check SOCK_DEAD?
You are saying that we need to do that, but it's not clear to me
why.
If you look at the places where unix_find_other() is called in
af_unix.c, then you'll find that all of them check for SOCK_DEAD and
then restart from unix_find_other() if they do actually discover
that the socket is dead. I think that this is catching this race
condition scenario:
* a server socket exists and is alive
* A client connects: af_unix.c's unix_stream_connect() calls
unix_find_other() and finds the server socket...
* (Concurrently): The server closes the socket and enters
unix_release_sock(). This function:
1. disassociates the server sock from the named socket inode
number in the hash table (=> future unix_find_other() calls
will fail).
2. calls sock_orphan(), which sets SOCK_DEAD.
* ...(client connection resuming): unix_stream_connect() continues,
grabs the unix_state_lock(), which apparently protects everything
here, checks that the socket is not dead - and discovers that it
IS suddenly dead. This was not supposed to happen. The code
recovers from that by retrying everything starting with the
unix_find_other() call. From unix_release_sock(), we know that
the inode is not associated with the sock any more -- so the
unix_find_socket_by_inode() call should be failing on the next
attempt.
(This works with unix_dgram_connect() and unix_dgram_sendmsg() as
well.)
The comments next to the SOCK_DEAD checks are also suggesting this.
* What lock to use
I am having trouble reasoning about what lock is used for what in
this code.
Is it possible that the lock protecting ->sk_socket is the
->sk_callback_lock, not the unix_state_lock()? The only callers to
sk_set_socket are either sock_orphan/sock_graft (both grabbing
sk_callback_lock), or they are creating new struct sock objects that
they own exclusively, and don't need locks yet.
Admittedly, in af_unix.c, sock_orphan() and sock_graft() only get
called in contexts where the unix_state_lock() is held, so it would
probably work as well to lock that, but it is maybe a more
fine-grained approach to use sk_callback_lock?
So... how about a scheme where we only check for ->sk_socket not being
NULL:
read_lock_bh(&other->sk_callback_lock);
struct sock *other_sk = other->sk_socket;
if (!other_sk) {
read_unlock_bh(&other->sk_callback_lock);
return 0;
}
/* XXX double check whether we need a lock here too */
struct file *file = other_sk->file;
if (!other_file) {
read_unlock_bh(&other->sk_callback_lock);
return 0;
}
read_unlock_bh(&other->sk_callback_lock);
If this fails, that would in my understanding also be because the
socket has died after the path lookup. We'd then return 0 (success),
because we know that the surrounding SOCK_DEAD logic will repeat
everything starting from the path lookup operation (this time likely
failing with ECONNREFUSED, but maybe also with a success, if another
server process was quick enough).
Does this sound reasonable?
–Günther
^ permalink raw reply
* Re: [PATCH v15 3/9] rust: Add missing SAFETY documentation for `ARef` example
From: Alice Ryhl @ 2026-02-20 10:49 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, Oliver Mangold
In-Reply-To: <20260220-unique-ref-v15-3-893ed86b06cc@kernel.org>
On Fri, Feb 20, 2026 at 10:52 AM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
> 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 | 10 ++++++----
> 1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
> index 61caddfd89619..efe16a7fdfa5d 100644
> --- a/rust/kernel/sync/aref.rs
> +++ b/rust/kernel/sync/aref.rs
> @@ -129,12 +129,14 @@ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
> /// # Examples
> ///
> /// ```
> - /// use core::ptr::NonNull;
> - /// use kernel::sync::aref::{ARef, RefCounted};
> + /// # use core::ptr::NonNull;
> + /// # use kernel::sync::aref::{ARef, RefCounted};
> ///
Either keep the imports visible or delete this empty line. And either
way, it doesn't really fit in this commit.
> /// 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
* Re: [PATCH v15 9/9] rust: page: add `from_raw()`
From: Alice Ryhl @ 2026-02-20 10:49 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
In-Reply-To: <20260220-unique-ref-v15-9-893ed86b06cc@kernel.org>
On Fri, Feb 20, 2026 at 10:52 AM Andreas Hindborg <a.hindborg@kernel.org> wrote:
>
> 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 4591b7b01c3d2..803f3e3d76b22 100644
> --- a/rust/kernel/page.rs
> +++ b/rust/kernel/page.rs
> @@ -191,6 +191,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 valid for use as a reference for the duration 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
> + // valid for use as a reference.
> + unsafe { &*Opaque::cast_from(ptr).cast::<Self>() }
If you're going to do a pointer cast, then keep it simple and just do
&*ptr.cast().
Alice
^ permalink raw reply
* Re: [PATCH] task: delete task_euid()
From: Alice Ryhl @ 2026-02-20 10:43 UTC (permalink / raw)
To: Paul Moore, Serge Hallyn, Jonathan Corbet, Greg Kroah-Hartman,
Shuah Khan, Alex Shi, Yanteng Si, Dongliang Mu
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Trevor Gross, Danilo Krummrich,
linux-security-module, linux-doc, linux-kernel, rust-for-linux,
Jann Horn
In-Reply-To: <20260219-remove-task-euid-v1-1-904060826e07@google.com>
On Thu, Feb 19, 2026 at 12:14:39PM +0000, Alice Ryhl wrote:
> include/linux/cred.h | 1 -
I guess the title of this should probably be
cred: delete task_euid()
rather than use the 'task:' prefix.
Alice
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox