Linux Integrity Measurement development
 help / color / mirror / Atom feed
* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: ross.philipson @ 2026-02-18 18:02 UTC (permalink / raw)
  To: Ard Biesheuvel, Daniel P. Smith, linux-kernel, x86,
	linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu,
	dave.hansen
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H . Peter Anvin,
	mjg59, James.Bottomley, peterhuewe, Jarkko Sakkinen, jgg, luto,
	nivedita, Herbert Xu, davem, corbet, ebiederm, dwmw2, baolu.lu,
	kanth.ghatraju, andrew.cooper3, trenchboot-devel
In-Reply-To: <242a0462-7fc5-4902-b71d-22cf8360239e@app.fastmail.com>

On 2/18/26 9:30 AM, 'Ard Biesheuvel' via trenchboot-devel wrote:
> On Thu, 12 Feb 2026, at 21:39, Ard Biesheuvel wrote:
>> On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
>>> On 2/9/26 09:04, Ard Biesheuvel wrote:
>> ...
>>>> I've had a stab at implementing all of this in a manner that is more idiomatic for EFI boot:
>>>>
>>>> - GRUB does minimal TXT related preparation upfront, and exposes the remaining functionality via a protocol that is attached to the loaded image by GRUB
>>>> - The SL stub is moved to the core kernel, with some startup code added to pivot to long mode
>>>> - the EFI stub executes and decompresses the kernel as usual
>>>> - if the protocol is present, the EFI stub calls it to pass the bootparams pointer, the base and size of the MLE and the header offset back to the GRUB code
>>>> - after calling ExitBootServices(), it calls another protocol method to trigger the secure launch.
>>>>
>> ...
>>>
>>> I think this is a great approach for UEFI, though we need to reconcile
>>> this with non-UEFI situations such as booting under coreboot.
>>
>> There are two approaches that I think are feasible for coreboot in this model:
>>
>> - just unpack the ELF and boot that - there is already prior art for
>> that with Xen. We can stick the MLE header offset in an ELF note where
>> any loader can find it.
>>
>> - stick with the current approach as much as possible, i.e., disable
>> physical KASLR so that the decompressed kernel will end up right where
>> the decompressor was loaded, which allows much of the secure launch
>> preparation to be done as before. Only the final bits (including the
>> call into the ACM itself) need to be deferred, and we can propose a
>> generic mechanism for that via boot_params.
>>
>> I'm working on a prototype of the latter, but GRUB is an odd beast and
>> my x86 fu is weak.
>>
> 
> I've managed to get a working implementation of the legacy entrypoint, by repurposing the dl_handler() entrypoint you added for EFI [which no longer needs it in my version] as a callback for the legacy boot flow. This /should/ work for i386-coreboot too, but I have no way of testing it (I only tried 'slaunch --legacy-linux' using the x86_64-efi build).

Using that GRUB argument should cause GRUB to choose the legacy boot path. That is where we were going with things.

> 
> I've pushed the changes to the branches I mentioned previously in this thread.

I will pull your latest, thank you Ard

> 
> 
> 
>   
> 


^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: Andy Lutomirski @ 2026-02-18 20:03 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Daniel P. Smith, Ross Philipson, linux-kernel, x86,
	linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu,
	dave.hansen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H . Peter Anvin, mjg59, James.Bottomley, peterhuewe,
	Jarkko Sakkinen, jgg, nivedita, Herbert Xu, davem, corbet,
	ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
	trenchboot-devel
In-Reply-To: <49d169bf-0ad2-49be-b7d7-fceb9e7f831a@app.fastmail.com>

On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
> > On 2/9/26 09:04, Ard Biesheuvel wrote:
> ...
> >> Surprisingly, even when doing a secure launch, the EFI runtime services still work happily, which means (AIUI) that code that was excluded from the D-RTM TCB is still being executed at ring 0? Doesn't this defeat D-RTM entirely in the case some exploit is hidden in the EFI runtime code? Should we measure the contents of EfiRuntimeServicesCode regions too?
> >
> > Yes, in fact in the early days I specifically stated that we should
> > provide for the ability to measure the RS blocks. Particularly if you
> > are not in an environment where you can isolate the calls to RS from the
> > TCB. While the RS can pose runtime corruption risks, the larger concern
> > is integrating the D-RTM validation of the Intel System Resources
> > Defense (ISRD), aka SMI isolation/SMM Supervisor, provided by the Intel
> > System Security Report (ISSR). Within the ISSR is a list of memory
> > regions which the SMM Policy Shim (SPS) restricts a SMI handler's access
> > when running. This allows a kernel to restrict what access a SMI handler
> > are able to reach, thus allowing them to be removed from the TCB when
> > the appropriate guards are put in place.
> >
> > If you are interested in understanding these further, Satoshi Tanda has
> > probably the best technical explanation without Intel market speak.
> >
> > ISRD: https://tandasat.github.io/blog/2024/02/29/ISRD.html
> > ISSR: https://tandasat.github.io/blog/2024/03/18/ISSR.html
> >
>
> Thanks, I'll take a look at those.
>
> But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.

So I have a possible way to disable EFI runtime service without losing
the ability to write EFI vars.  We come up with a simple file format
to store deferred EFI var updates and we come up with a place to put
it so that we find it early-ish in boot the next time around.  (This
could be done via integration with systemd-boot or shim some other
boot loader or it could actually be part of the kernel.)  And then,
instead of writing variables directly, we write them to the deferred
list and then update them on reboot (before TXT launch, etc).  [0]
This would be a distincly nontrivial project and would not work for
all configurations.

As a maybe less painful option, we could disable EFI runtime services
but have a root-writable thing in sysfs that (a) turns them back on
but (b) first extends a PCR to say that they're turned back on.

(Or someone could try running runtime services at CPL3...)

[0] I have thought for years that Intel and AMD should do this on
their end, too.  Keep the sensitive part of SMI flash entirely locked
after boot and, instead of using magic SMM stuff to validate that
write attempts have the appropriate permissions and signatures, queue
them up as deferred upates and validate the signatures on the next
boot before locking flash.

^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: Andy Lutomirski @ 2026-02-18 20:34 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ard Biesheuvel, Daniel P. Smith, Ross Philipson, linux-kernel,
	x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
	iommu, dave.hansen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	mjg59, James.Bottomley, peterhuewe, Jarkko Sakkinen, jgg,
	nivedita, Herbert Xu, davem, corbet, ebiederm, dwmw2, baolu.lu,
	kanth.ghatraju, andrew.cooper3, trenchboot-devel
In-Reply-To: <1BBD7449-8420-43FD-930B-A4E1BA38FFC6@zytor.com>

On Wed, Feb 18, 2026 at 12:29 PM H. Peter Anvin <hpa@zytor.com> wrote:
>
> On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
> >On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
> >>
> >> On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
> >> > On 2/9/26 09:04, Ard Biesheuvel wrote:
> >> ...
> >> >> Surprisingly, even when doing a secure launch, the EFI runtime services still work happily, which means (AIUI) that code that was excluded from the D-RTM TCB is still being executed at ring 0? Doesn't this defeat D-RTM entirely in the case some exploit is hidden in the EFI runtime code? Should we measure the contents of EfiRuntimeServicesCode regions too?
> >> >
> >> > Yes, in fact in the early days I specifically stated that we should
> >> > provide for the ability to measure the RS blocks. Particularly if you
> >> > are not in an environment where you can isolate the calls to RS from the
> >> > TCB. While the RS can pose runtime corruption risks, the larger concern
> >> > is integrating the D-RTM validation of the Intel System Resources
> >> > Defense (ISRD), aka SMI isolation/SMM Supervisor, provided by the Intel
> >> > System Security Report (ISSR). Within the ISSR is a list of memory
> >> > regions which the SMM Policy Shim (SPS) restricts a SMI handler's access
> >> > when running. This allows a kernel to restrict what access a SMI handler
> >> > are able to reach, thus allowing them to be removed from the TCB when
> >> > the appropriate guards are put in place.
> >> >
> >> > If you are interested in understanding these further, Satoshi Tanda has
> >> > probably the best technical explanation without Intel market speak.
> >> >
> >> > ISRD: https://tandasat.github.io/blog/2024/02/29/ISRD.html
> >> > ISSR: https://tandasat.github.io/blog/2024/03/18/ISSR.html
> >> >
> >>
> >> Thanks, I'll take a look at those.
> >>
> >> But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
> >
> >So I have a possible way to disable EFI runtime service without losing
> >the ability to write EFI vars.  We come up with a simple file format
> >to store deferred EFI var updates and we come up with a place to put
> >it so that we find it early-ish in boot the next time around.  (This
> >could be done via integration with systemd-boot or shim some other
> >boot loader or it could actually be part of the kernel.)  And then,
> >instead of writing variables directly, we write them to the deferred
> >list and then update them on reboot (before TXT launch, etc).  [0]
> >This would be a distincly nontrivial project and would not work for
> >all configurations.
> >
> >As a maybe less painful option, we could disable EFI runtime services
> >but have a root-writable thing in sysfs that (a) turns them back on
> >but (b) first extends a PCR to say that they're turned back on.
> >
> >(Or someone could try running runtime services at CPL3...)
> >
> >[0] I have thought for years that Intel and AMD should do this on
> >their end, too.  Keep the sensitive part of SMI flash entirely locked
> >after boot and, instead of using magic SMM stuff to validate that
> >write attempts have the appropriate permissions and signatures, queue
> >them up as deferred upates and validate the signatures on the next
> >boot before locking flash.
> >
>
> *If* a physical EFI partition exists there is a lot to be said for this approach.
>
> The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)

Hmm, I guess my approach is a 100% complete nonstarter for installing
Linux from a CD, and it's really not awesome for installing Linux from
a USB stick.

^ permalink raw reply

* Re: [PATCH v2] ima: fallback to using i_version to detect file change
From: Mimi Zohar @ 2026-02-18 20:34 UTC (permalink / raw)
  To: Frederick Lawler
  Cc: linux-integrity, Jeff Layton, Roberto Sassu, Roberto Sassu
In-Reply-To: <aY-ApsCkJQ05-FIk@CMGLRV3>

On Fri, 2026-02-13 at 13:51 -0600, Frederick Lawler wrote:
> On Fri, Feb 13, 2026 at 12:49:47PM -0500, Mimi Zohar wrote:
> > Commit db1d1e8b9867 ("IMA: use vfs_getattr_nosec to get the i_version")
> > replaced detecting file change based on i_version with
> > STATX_CHANGE_COOKIE.
> > 
> > On filesystems without STATX_CHANGE_COOKIE enabled, revert back to
> > detecting file change based on i_version.
> > 
> > On filesystems which do not support either, assume the file changed.
> > 
> 
> Tested-by: Frederick Lawler <fred@cloudflare.com>

Thanks, Fred.  It's temporarily queued in the next-integrity-testing branch.
> 

^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: H. Peter Anvin @ 2026-02-18 20:29 UTC (permalink / raw)
  To: Andy Lutomirski, Ard Biesheuvel
  Cc: Daniel P. Smith, Ross Philipson, linux-kernel, x86,
	linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu,
	dave.hansen, Thomas Gleixner, Ingo Molnar, Borislav Petkov, mjg59,
	James.Bottomley, peterhuewe, Jarkko Sakkinen, jgg, nivedita,
	Herbert Xu, davem, corbet, ebiederm, dwmw2, baolu.lu,
	kanth.ghatraju, andrew.cooper3, trenchboot-devel
In-Reply-To: <CALCETrUE8c-dxRWhtHKz_PojwZuWMXJSzOsFQf2vt5LS3ATwpA@mail.gmail.com>

On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
>On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>>
>> On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
>> > On 2/9/26 09:04, Ard Biesheuvel wrote:
>> ...
>> >> Surprisingly, even when doing a secure launch, the EFI runtime services still work happily, which means (AIUI) that code that was excluded from the D-RTM TCB is still being executed at ring 0? Doesn't this defeat D-RTM entirely in the case some exploit is hidden in the EFI runtime code? Should we measure the contents of EfiRuntimeServicesCode regions too?
>> >
>> > Yes, in fact in the early days I specifically stated that we should
>> > provide for the ability to measure the RS blocks. Particularly if you
>> > are not in an environment where you can isolate the calls to RS from the
>> > TCB. While the RS can pose runtime corruption risks, the larger concern
>> > is integrating the D-RTM validation of the Intel System Resources
>> > Defense (ISRD), aka SMI isolation/SMM Supervisor, provided by the Intel
>> > System Security Report (ISSR). Within the ISSR is a list of memory
>> > regions which the SMM Policy Shim (SPS) restricts a SMI handler's access
>> > when running. This allows a kernel to restrict what access a SMI handler
>> > are able to reach, thus allowing them to be removed from the TCB when
>> > the appropriate guards are put in place.
>> >
>> > If you are interested in understanding these further, Satoshi Tanda has
>> > probably the best technical explanation without Intel market speak.
>> >
>> > ISRD: https://tandasat.github.io/blog/2024/02/29/ISRD.html
>> > ISSR: https://tandasat.github.io/blog/2024/03/18/ISSR.html
>> >
>>
>> Thanks, I'll take a look at those.
>>
>> But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
>
>So I have a possible way to disable EFI runtime service without losing
>the ability to write EFI vars.  We come up with a simple file format
>to store deferred EFI var updates and we come up with a place to put
>it so that we find it early-ish in boot the next time around.  (This
>could be done via integration with systemd-boot or shim some other
>boot loader or it could actually be part of the kernel.)  And then,
>instead of writing variables directly, we write them to the deferred
>list and then update them on reboot (before TXT launch, etc).  [0]
>This would be a distincly nontrivial project and would not work for
>all configurations.
>
>As a maybe less painful option, we could disable EFI runtime services
>but have a root-writable thing in sysfs that (a) turns them back on
>but (b) first extends a PCR to say that they're turned back on.
>
>(Or someone could try running runtime services at CPL3...)
>
>[0] I have thought for years that Intel and AMD should do this on
>their end, too.  Keep the sensitive part of SMI flash entirely locked
>after boot and, instead of using magic SMM stuff to validate that
>write attempts have the appropriate permissions and signatures, queue
>them up as deferred upates and validate the signatures on the next
>boot before locking flash.
>

*If* a physical EFI partition exists there is a lot to be said for this approach.

The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)

Even *if* there is a back channel to the boot server, it would require the OS to know what it is and how to get to it. Maybe we need to consider standardizing a protocol for uploads to the boot server, but that doesn't solve the boot from readonly media, or legacy boot server setups ... and boot server infrastructure is something that changes slowly at best.

Just *reading out* the EFI variables doesn't have that issue, of course; we can do that in the EFI stub (and pass them onward to kexec kernels etc using the setup_data protocol.)



^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: Simo Sorce @ 2026-02-18 21:04 UTC (permalink / raw)
  To: Andy Lutomirski, H. Peter Anvin
  Cc: Ard Biesheuvel, Daniel P. Smith, Ross Philipson, linux-kernel,
	x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
	iommu, dave.hansen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	mjg59, James.Bottomley, peterhuewe, Jarkko Sakkinen, jgg,
	nivedita, Herbert Xu, davem, corbet, ebiederm, dwmw2, baolu.lu,
	kanth.ghatraju, andrew.cooper3, trenchboot-devel
In-Reply-To: <CALCETrWzG1Mjb-RcwLQ5-tGFZ15WKHjZbqtLvyif+UPuVKJ_5g@mail.gmail.com>

On Wed, 2026-02-18 at 12:34 -0800, Andy Lutomirski wrote:
> On Wed, Feb 18, 2026 at 12:29 PM H. Peter Anvin <hpa@zytor.com> wrote:
> > 
> > On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
> > > On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
> > > > 
> > > > On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
> > > > > On 2/9/26 09:04, Ard Biesheuvel wrote:
> > > > ...
> > > > > > Surprisingly, even when doing a secure launch, the EFI runtime services still work happily, which means (AIUI) that code that was excluded from the D-RTM TCB is still being executed at ring 0? Doesn't this defeat D-RTM entirely in the case some exploit is hidden in the EFI runtime code? Should we measure the contents of EfiRuntimeServicesCode regions too?
> > > > > 
> > > > > Yes, in fact in the early days I specifically stated that we should
> > > > > provide for the ability to measure the RS blocks. Particularly if you
> > > > > are not in an environment where you can isolate the calls to RS from the
> > > > > TCB. While the RS can pose runtime corruption risks, the larger concern
> > > > > is integrating the D-RTM validation of the Intel System Resources
> > > > > Defense (ISRD), aka SMI isolation/SMM Supervisor, provided by the Intel
> > > > > System Security Report (ISSR). Within the ISSR is a list of memory
> > > > > regions which the SMM Policy Shim (SPS) restricts a SMI handler's access
> > > > > when running. This allows a kernel to restrict what access a SMI handler
> > > > > are able to reach, thus allowing them to be removed from the TCB when
> > > > > the appropriate guards are put in place.
> > > > > 
> > > > > If you are interested in understanding these further, Satoshi Tanda has
> > > > > probably the best technical explanation without Intel market speak.
> > > > > 
> > > > > ISRD: https://tandasat.github.io/blog/2024/02/29/ISRD.html
> > > > > ISSR: https://tandasat.github.io/blog/2024/03/18/ISSR.html
> > > > > 
> > > > 
> > > > Thanks, I'll take a look at those.
> > > > 
> > > > But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
> > > 
> > > So I have a possible way to disable EFI runtime service without losing
> > > the ability to write EFI vars.  We come up with a simple file format
> > > to store deferred EFI var updates and we come up with a place to put
> > > it so that we find it early-ish in boot the next time around.  (This
> > > could be done via integration with systemd-boot or shim some other
> > > boot loader or it could actually be part of the kernel.)  And then,
> > > instead of writing variables directly, we write them to the deferred
> > > list and then update them on reboot (before TXT launch, etc).  [0]
> > > This would be a distincly nontrivial project and would not work for
> > > all configurations.
> > > 
> > > As a maybe less painful option, we could disable EFI runtime services
> > > but have a root-writable thing in sysfs that (a) turns them back on
> > > but (b) first extends a PCR to say that they're turned back on.
> > > 
> > > (Or someone could try running runtime services at CPL3...)
> > > 
> > > [0] I have thought for years that Intel and AMD should do this on
> > > their end, too.  Keep the sensitive part of SMI flash entirely locked
> > > after boot and, instead of using magic SMM stuff to validate that
> > > write attempts have the appropriate permissions and signatures, queue
> > > them up as deferred upates and validate the signatures on the next
> > > boot before locking flash.
> > > 
> > 
> > *If* a physical EFI partition exists there is a lot to be said for this approach.
> > 
> > The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)
> 
> Hmm, I guess my approach is a 100% complete nonstarter for installing
> Linux from a CD, and it's really not awesome for installing Linux from
> a USB stick.

Doing any of this on a removable device feels generally like a trap.
You get your USB disk in, try to boot, and it saves vars, but reboot
fails for whatever reason, you plug it in another machine ... and it
tries to "continue" from there? The amount of validation needed and
testing for failure modes across reboots sounds really painful.


-- 
Simo Sorce
Distinguished Engineer
RHEL Crypto Team
Red Hat, Inc


^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: Andy Lutomirski @ 2026-02-18 21:54 UTC (permalink / raw)
  To: Simo Sorce
  Cc: H. Peter Anvin, Ard Biesheuvel, Daniel P. Smith, Ross Philipson,
	linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
	kexec, linux-efi, iommu, dave.hansen, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, mjg59, James.Bottomley, peterhuewe,
	Jarkko Sakkinen, jgg, nivedita, Herbert Xu, davem, corbet,
	ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
	trenchboot-devel
In-Reply-To: <32e62cef7b89d9691bdd4120388ce752fd041230.camel@redhat.com>

On Wed, Feb 18, 2026 at 1:04 PM Simo Sorce <simo@redhat.com> wrote:
>
> On Wed, 2026-02-18 at 12:34 -0800, Andy Lutomirski wrote:
> > On Wed, Feb 18, 2026 at 12:29 PM H. Peter Anvin <hpa@zytor.com> wrote:
> > >
> > > On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
> > > > On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
> > > > >
> > > > > On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
> > > > > > On 2/9/26 09:04, Ard Biesheuvel wrote:
> > > > > ...
> > > > > > > Surprisingly, even when doing a secure launch, the EFI runtime services still work happily, which means (AIUI) that code that was excluded from the D-RTM TCB is still being executed at ring 0? Doesn't this defeat D-RTM entirely in the case some exploit is hidden in the EFI runtime code? Should we measure the contents of EfiRuntimeServicesCode regions too?
> > > > > >
> > > > > > Yes, in fact in the early days I specifically stated that we should
> > > > > > provide for the ability to measure the RS blocks. Particularly if you
> > > > > > are not in an environment where you can isolate the calls to RS from the
> > > > > > TCB. While the RS can pose runtime corruption risks, the larger concern
> > > > > > is integrating the D-RTM validation of the Intel System Resources
> > > > > > Defense (ISRD), aka SMI isolation/SMM Supervisor, provided by the Intel
> > > > > > System Security Report (ISSR). Within the ISSR is a list of memory
> > > > > > regions which the SMM Policy Shim (SPS) restricts a SMI handler's access
> > > > > > when running. This allows a kernel to restrict what access a SMI handler
> > > > > > are able to reach, thus allowing them to be removed from the TCB when
> > > > > > the appropriate guards are put in place.
> > > > > >
> > > > > > If you are interested in understanding these further, Satoshi Tanda has
> > > > > > probably the best technical explanation without Intel market speak.
> > > > > >
> > > > > > ISRD: https://tandasat.github.io/blog/2024/02/29/ISRD.html
> > > > > > ISSR: https://tandasat.github.io/blog/2024/03/18/ISSR.html
> > > > > >
> > > > >
> > > > > Thanks, I'll take a look at those.
> > > > >
> > > > > But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
> > > >
> > > > So I have a possible way to disable EFI runtime service without losing
> > > > the ability to write EFI vars.  We come up with a simple file format
> > > > to store deferred EFI var updates and we come up with a place to put
> > > > it so that we find it early-ish in boot the next time around.  (This
> > > > could be done via integration with systemd-boot or shim some other
> > > > boot loader or it could actually be part of the kernel.)  And then,
> > > > instead of writing variables directly, we write them to the deferred
> > > > list and then update them on reboot (before TXT launch, etc).  [0]
> > > > This would be a distincly nontrivial project and would not work for
> > > > all configurations.
> > > >
> > > > As a maybe less painful option, we could disable EFI runtime services
> > > > but have a root-writable thing in sysfs that (a) turns them back on
> > > > but (b) first extends a PCR to say that they're turned back on.
> > > >
> > > > (Or someone could try running runtime services at CPL3...)
> > > >
> > > > [0] I have thought for years that Intel and AMD should do this on
> > > > their end, too.  Keep the sensitive part of SMI flash entirely locked
> > > > after boot and, instead of using magic SMM stuff to validate that
> > > > write attempts have the appropriate permissions and signatures, queue
> > > > them up as deferred upates and validate the signatures on the next
> > > > boot before locking flash.
> > > >
> > >
> > > *If* a physical EFI partition exists there is a lot to be said for this approach.
> > >
> > > The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)
> >
> > Hmm, I guess my approach is a 100% complete nonstarter for installing
> > Linux from a CD, and it's really not awesome for installing Linux from
> > a USB stick.
>
> Doing any of this on a removable device feels generally like a trap.
> You get your USB disk in, try to boot, and it saves vars, but reboot
> fails for whatever reason, you plug it in another machine ... and it
> tries to "continue" from there? The amount of validation needed and
> testing for failure modes across reboots sounds really painful.

I kind of stand by my other previous suggestion, though:

As a maybe less painful option, we could disable EFI runtime services
but have a root-writable thing in sysfs that (a) turns them back on
but (b) first extends a PCR to say that they're turned back on.

--Andy

^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: Ard Biesheuvel @ 2026-02-19  7:54 UTC (permalink / raw)
  To: Andy Lutomirski, Simo Sorce
  Cc: H . Peter Anvin, Daniel P. Smith, Ross Philipson, linux-kernel,
	x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
	iommu, dave.hansen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	mjg59, James.Bottomley, peterhuewe, Jarkko Sakkinen, jgg,
	nivedita, Herbert Xu, davem, corbet, ebiederm, dwmw2, baolu.lu,
	kanth.ghatraju, andrew.cooper3, trenchboot-devel
In-Reply-To: <CALCETrUMR0RvOFXGzL7=F4c-3veL+1Sm2xf-BprHTK4=UKw8yA@mail.gmail.com>

On Wed, 18 Feb 2026, at 22:54, Andy Lutomirski wrote:
> On Wed, Feb 18, 2026 at 1:04 PM Simo Sorce <simo@redhat.com> wrote:
>>
>> On Wed, 2026-02-18 at 12:34 -0800, Andy Lutomirski wrote:
>> > On Wed, Feb 18, 2026 at 12:29 PM H. Peter Anvin <hpa@zytor.com> wrote:
>> > >
>> > > On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
>> > > > On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>> > > > >
>> > > > > On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
>> > > > > > On 2/9/26 09:04, Ard Biesheuvel wrote:
>> > > > > ...
>> > > > > But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
>> > > >
>> > > > So I have a possible way to disable EFI runtime service without losing
>> > > > the ability to write EFI vars.  We come up with a simple file format
>> > > > to store deferred EFI var updates and we come up with a place to put
>> > > > it so that we find it early-ish in boot the next time around.  (This
>> > > > could be done via integration with systemd-boot or shim some other
>> > > > boot loader or it could actually be part of the kernel.)  And then,
>> > > > instead of writing variables directly, we write them to the deferred
>> > > > list and then update them on reboot (before TXT launch, etc).  [0]
>> > > > This would be a distincly nontrivial project and would not work for
>> > > > all configurations.
>> > > >
>> > > > As a maybe less painful option, we could disable EFI runtime services
>> > > > but have a root-writable thing in sysfs that (a) turns them back on
>> > > > but (b) first extends a PCR to say that they're turned back on.
>> > > >
>> > > > (Or someone could try running runtime services at CPL3...)
>> > > >
>> > > > [0] I have thought for years that Intel and AMD should do this on
>> > > > their end, too.  Keep the sensitive part of SMI flash entirely locked
>> > > > after boot and, instead of using magic SMM stuff to validate that
>> > > > write attempts have the appropriate permissions and signatures, queue
>> > > > them up as deferred upates and validate the signatures on the next
>> > > > boot before locking flash.
>> > > >
>> > >
>> > > *If* a physical EFI partition exists there is a lot to be said for this approach.
>> > >
>> > > The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)
>> >
>> > Hmm, I guess my approach is a 100% complete nonstarter for installing
>> > Linux from a CD, and it's really not awesome for installing Linux from
>> > a USB stick.
>>
>> Doing any of this on a removable device feels generally like a trap.
>> You get your USB disk in, try to boot, and it saves vars, but reboot
>> fails for whatever reason, you plug it in another machine ... and it
>> tries to "continue" from there? The amount of validation needed and
>> testing for failure modes across reboots sounds really painful.
>
> I kind of stand by my other previous suggestion, though:
>
> As a maybe less painful option, we could disable EFI runtime services
> but have a root-writable thing in sysfs that (a) turns them back on
> but (b) first extends a PCR to say that they're turned back on.
>

After setting the EFI boot path to GRUB (or systemd-boot or whatever) at installation time, what other meaningful interactions do we expect with the EFI runtime services?

And given that the secure launch is orchestrated by the bootloader , with which the kernel has a backchannel via its configuration file, it should be rather straight-forward to implement the staging of variable updates there if we really need it. 

Doing any of this at the EFI/spec level might lead to a situation where the OS now has to guess which of the provided APIs to manipulate variables is the least broken.

Of course, for readinf variables, dumping the RT variables into a memory buffer at boot time and exposing it via a EFI config table would be rather straight-forward, but it is also something I feel should be the job of the boot component that takes part in the decision to shield the runtime services from the OS.




^ permalink raw reply

* Re: [PATCH] ima: check return value of crypto_shash_final() in boot aggregate
From: Roberto Sassu @ 2026-02-19  8:56 UTC (permalink / raw)
  To: Daniel Hodges, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin
  Cc: Eric Snowberg, Paul Moore, James Morris, Serge E . Hallyn,
	linux-integrity, linux-security-module, linux-kernel
In-Reply-To: <20260201024015.2862236-1-hodgesd@meta.com>

On Sat, 2026-01-31 at 18:40 -0800, Daniel Hodges wrote:
> The return value of crypto_shash_final() is not checked in
> ima_calc_boot_aggregate_tfm(). If the hash finalization fails, the
> function returns success and a corrupted boot aggregate digest could
> be used for IMA measurements.
> 
> Capture the return value and propagate any error to the caller.
> 
> Fixes: 76bb28f6126f ("ima: use new crypto_shash API instead of old crypto_hash")
> Signed-off-by: Daniel Hodges <hodgesd@meta.com>

Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>

Thanks

Roberto

> ---
>  security/integrity/ima/ima_crypto.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
> index 6f5696d999d0..8ae7821a65c2 100644
> --- a/security/integrity/ima/ima_crypto.c
> +++ b/security/integrity/ima/ima_crypto.c
> @@ -825,21 +825,21 @@ static int ima_calc_boot_aggregate_tfm(char *digest, u16 alg_id,
>  	 * non-SHA1 boot_aggregate digests to avoid ambiguity.
>  	 */
>  	if (alg_id != TPM_ALG_SHA1) {
>  		for (i = TPM_PCR8; i < TPM_PCR10; i++) {
>  			ima_pcrread(i, &d);
>  			rc = crypto_shash_update(shash, d.digest,
>  						crypto_shash_digestsize(tfm));
>  		}
>  	}
>  	if (!rc)
> -		crypto_shash_final(shash, digest);
> +		rc = crypto_shash_final(shash, digest);
>  	return rc;
>  }
>  
>  int ima_calc_boot_aggregate(struct ima_digest_data *hash)
>  {
>  	struct crypto_shash *tfm;
>  	u16 crypto_id, alg_id;
>  	int rc, i, bank_idx = -1;
>  
>  	for (i = 0; i < ima_tpm_chip->nr_allocated_banks; i++) {


^ permalink raw reply

* Re: [PATCH v4] ima_fs: Avoid creating measurement lists for unsupported hash algos
From: Roberto Sassu @ 2026-02-19  8:54 UTC (permalink / raw)
  To: dima, Mimi Zohar, Roberto Sassu, Dmitry Kasatkin, Eric Snowberg,
	Paul Moore, James Morris, Serge E. Hallyn, Silvia Sisinni,
	Enrico Bravi
  Cc: linux-integrity, linux-security-module, linux-kernel, stable,
	Dmitry Safonov
In-Reply-To: <701de3f87f0f6bde97872dd0c5bf150bfc1f2713.camel@huaweicloud.com>

On Tue, 2026-01-27 at 16:20 +0100, Roberto Sassu wrote:
> On Tue, 2026-01-27 at 15:03 +0000, Dmitry Safonov via B4 Relay wrote:
> > From: Dmitry Safonov <dima@arista.com>
> > 
> > ima_init_crypto() skips initializing ima_algo_array[i] if the algorithm
> > from ima_tpm_chip->allocated_banks[i].crypto_id is not supported.
> > It seems avoid adding the unsupported algorithm to ima_algo_array will
> > break all the logic that relies on indexing by NR_BANKS(ima_tpm_chip).
> 
> The patch looks good, although I didn't try yet myself.
> 
> I would make the commit message slightly better, with a more fluid
> explanation.
> 
> ima_tpm_chip->allocated_banks[i].crypto_id is initialized to
> HASH_ALGO__LAST if the TPM algorithm is not supported. However there
> are places relying on the algorithm to be valid because it is accessed
> by hash_algo_name[].
> 
> Thus solve the problem by creating a file name that does not depend on
> the crypto algorithm to be initialized, ...
> 
> Also print the template entry digest as populated by IMA.
> 
> Something along these lines.
> 
> Also, I have a preference for lower case instead of capital case for
> the file name, given the other names.

Hi Dmitry

do you have time to make these small changes, so that we queue the
patch for the next kernel?

Thanks

Roberto

> Could you also avoid the >, otherwise the mailer thinks it is a reply?
> 
> Thanks
> 
> Roberto
> 
> > On 6.12.40 I observe the following read out-of-bounds in hash_algo_name:
> > 
> > > ==================================================================
> > > BUG: KASAN: global-out-of-bounds in create_securityfs_measurement_lists+0x396/0x440
> > > Read of size 8 at addr ffffffff83e18138 by task swapper/0/1
> > > 
> > > CPU: 4 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.40 #3
> > > Call Trace:
> > >  <TASK>
> > >  dump_stack_lvl+0x61/0x90
> > >  print_report+0xc4/0x580
> > >  ? kasan_addr_to_slab+0x26/0x80
> > >  ? create_securityfs_measurement_lists+0x396/0x440
> > >  kasan_report+0xc2/0x100
> > >  ? create_securityfs_measurement_lists+0x396/0x440
> > >  create_securityfs_measurement_lists+0x396/0x440
> > >  ima_fs_init+0xa3/0x300
> > >  ima_init+0x7d/0xd0
> > >  init_ima+0x28/0x100
> > >  do_one_initcall+0xa6/0x3e0
> > >  kernel_init_freeable+0x455/0x740
> > >  kernel_init+0x24/0x1d0
> > >  ret_from_fork+0x38/0x80
> > >  ret_from_fork_asm+0x11/0x20
> > >  </TASK>
> > > 
> > > The buggy address belongs to the variable:
> > >  hash_algo_name+0xb8/0x420
> > > 
> > > The buggy address belongs to the physical page:
> > > page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x107ce18
> > > flags: 0x8000000000002000(reserved|zone=2)
> > > raw: 8000000000002000 ffffea0041f38608 ffffea0041f38608 0000000000000000
> > > raw: 0000000000000000 0000000000000000 00000001ffffffff 0000000000000000
> > > page dumped because: kasan: bad access detected
> > > 
> > > Memory state around the buggy address:
> > >  ffffffff83e18000: 00 01 f9 f9 f9 f9 f9 f9 00 01 f9 f9 f9 f9 f9 f9
> > >  ffffffff83e18080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
> > > > ffffffff83e18100: 00 00 00 00 00 00 00 f9 f9 f9 f9 f9 00 05 f9 f9
> > >                                         ^
> > >  ffffffff83e18180: f9 f9 f9 f9 00 00 00 00 00 00 00 04 f9 f9 f9 f9
> > >  ffffffff83e18200: 00 00 00 00 00 00 00 00 04 f9 f9 f9 f9 f9 f9 f9
> > > ==================================================================
> > 
> > Seems like the TPM chip supports sha3_256, which isn't yet in
> > tpm_algorithms:
> > > tpm tpm0: TPM with unsupported bank algorithm 0x0027
> > 
> > Use TPM_ALG_<ID> as a postfix for file names for unsupported hashing algorithms.
> > 
> > This is how it looks on the test machine I have:
> > > # ls -1 /sys/kernel/security/ima/
> > > ascii_runtime_measurements
> > > ascii_runtime_measurements_TPM_ALG_27
> > > ascii_runtime_measurements_sha1
> > > ascii_runtime_measurements_sha256
> > > binary_runtime_measurements
> > > binary_runtime_measurements_TPM_ALG_27
> > > binary_runtime_measurements_sha1
> > > binary_runtime_measurements_sha256
> > > policy
> > > runtime_measurements_count
> > > violations
> > 
> > Fixes: 9fa8e7625008 ("ima: add crypto agility support for template-hash algorithm")
> > Signed-off-by: Dmitry Safonov <dima@arista.com>
> > Cc: Enrico Bravi <enrico.bravi@polito.it>
> > Cc: Silvia Sisinni <silvia.sisinni@polito.it>
> > Cc: Roberto Sassu <roberto.sassu@huawei.com>
> > Cc: Mimi Zohar <zohar@linux.ibm.com>
> > ---
> > Changes in v4:
> > - Use ima_tpm_chip->allocated_banks[algo_idx].digest_size instead of hash_digest_size[algo]
> >   (Roberto Sassu)
> > - Link to v3: https://lore.kernel.org/r/20260127-ima-oob-v3-1-1dd09f4c2a6a@arista.com
> > Testing note: I test it on v6.12.40 kernel backport, which slightly differs as
> > lookup_template_data_hash_algo() was yet present.
> > 
> > Changes in v3:
> > - Now fix the spelling *for real* (sorry, messed it up in v2)
> > - Link to v2: https://lore.kernel.org/r/20260127-ima-oob-v2-1-f38a18c850cf@arista.com
> > 
> > Changes in v2:
> > - Instead of skipping unknown algorithms, add files under their TPM_ALG_ID (Roberto Sassu)
> > - Fix spelling (Roberto Sassu)
> > - Copy @stable on the fix
> > - Link to v1: https://lore.kernel.org/r/20260127-ima-oob-v1-1-2d42f3418e57@arista.com
> > ---
> >  security/integrity/ima/ima_fs.c | 34 ++++++++++++++++++----------------
> >  1 file changed, 18 insertions(+), 16 deletions(-)
> > 
> > diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
> > index 012a58959ff0..9a00a0547619 100644
> > --- a/security/integrity/ima/ima_fs.c
> > +++ b/security/integrity/ima/ima_fs.c
> > @@ -132,16 +132,12 @@ int ima_measurements_show(struct seq_file *m, void *v)
> >  	char *template_name;
> >  	u32 pcr, namelen, template_data_len; /* temporary fields */
> >  	bool is_ima_template = false;
> > -	enum hash_algo algo;
> >  	int i, algo_idx;
> >  
> >  	algo_idx = ima_sha1_idx;
> > -	algo = HASH_ALGO_SHA1;
> >  
> > -	if (m->file != NULL) {
> > +	if (m->file != NULL)
> >  		algo_idx = (unsigned long)file_inode(m->file)->i_private;
> > -		algo = ima_algo_array[algo_idx].algo;
> > -	}
> >  
> >  	/* get entry */
> >  	e = qe->entry;
> > @@ -160,7 +156,8 @@ int ima_measurements_show(struct seq_file *m, void *v)
> >  	ima_putc(m, &pcr, sizeof(e->pcr));
> >  
> >  	/* 2nd: template digest */
> > -	ima_putc(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
> > +	ima_putc(m, e->digests[algo_idx].digest,
> > +		 ima_tpm_chip->allocated_banks[algo_idx].digest_size);
> >  
> >  	/* 3rd: template name size */
> >  	namelen = !ima_canonical_fmt ? strlen(template_name) :
> > @@ -229,16 +226,12 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
> >  	struct ima_queue_entry *qe = v;
> >  	struct ima_template_entry *e;
> >  	char *template_name;
> > -	enum hash_algo algo;
> >  	int i, algo_idx;
> >  
> >  	algo_idx = ima_sha1_idx;
> > -	algo = HASH_ALGO_SHA1;
> >  
> > -	if (m->file != NULL) {
> > +	if (m->file != NULL)
> >  		algo_idx = (unsigned long)file_inode(m->file)->i_private;
> > -		algo = ima_algo_array[algo_idx].algo;
> > -	}
> >  
> >  	/* get entry */
> >  	e = qe->entry;
> > @@ -252,7 +245,8 @@ static int ima_ascii_measurements_show(struct seq_file *m, void *v)
> >  	seq_printf(m, "%2d ", e->pcr);
> >  
> >  	/* 2nd: template hash */
> > -	ima_print_digest(m, e->digests[algo_idx].digest, hash_digest_size[algo]);
> > +	ima_print_digest(m, e->digests[algo_idx].digest,
> > +			 ima_tpm_chip->allocated_banks[algo_idx].digest_size);
> >  
> >  	/* 3th:  template name */
> >  	seq_printf(m, " %s", template_name);
> > @@ -404,16 +398,24 @@ static int __init create_securityfs_measurement_lists(void)
> >  		char file_name[NAME_MAX + 1];
> >  		struct dentry *dentry;
> >  
> > -		sprintf(file_name, "ascii_runtime_measurements_%s",
> > -			hash_algo_name[algo]);
> > +		if (algo == HASH_ALGO__LAST)
> > +			sprintf(file_name, "ascii_runtime_measurements_TPM_ALG_%x",
> > +				ima_tpm_chip->allocated_banks[i].alg_id);
> > +		else
> > +			sprintf(file_name, "ascii_runtime_measurements_%s",
> > +				hash_algo_name[algo]);
> >  		dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> >  						ima_dir, (void *)(uintptr_t)i,
> >  						&ima_ascii_measurements_ops);
> >  		if (IS_ERR(dentry))
> >  			return PTR_ERR(dentry);
> >  
> > -		sprintf(file_name, "binary_runtime_measurements_%s",
> > -			hash_algo_name[algo]);
> > +		if (algo == HASH_ALGO__LAST)
> > +			sprintf(file_name, "binary_runtime_measurements_TPM_ALG_%x",
> > +				ima_tpm_chip->allocated_banks[i].alg_id);
> > +		else
> > +			sprintf(file_name, "binary_runtime_measurements_%s",
> > +				hash_algo_name[algo]);
> >  		dentry = securityfs_create_file(file_name, S_IRUSR | S_IRGRP,
> >  						ima_dir, (void *)(uintptr_t)i,
> >  						&ima_measurements_ops);
> > 
> > ---
> > base-commit: 63804fed149a6750ffd28610c5c1c98cce6bd377
> > change-id: 20260127-ima-oob-9fa83a634d7b
> > 
> > Best regards,


^ permalink raw reply

* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Roberto Sassu @ 2026-02-19  9:26 UTC (permalink / raw)
  To: Daniel Hodges
  Cc: zohar, roberto.sassu, dmitry.kasatkin, eric.snowberg, paul,
	jmorris, serge, linux-integrity, linux-security-module,
	linux-kernel
In-Reply-To: <20260206024240.19059-1-git@danielhodges.dev>

On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> The crypto_shash_update() and crypto_shash_final() functions can fail
> and return error codes, but their return values were not being checked
> in several places in security/integrity/evm/evm_crypto.c:
> 
> - hmac_add_misc() ignored returns from crypto_shash_update() and
>   crypto_shash_final()
> - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> - evm_init_hmac() ignored returns from crypto_shash_update()
> 
> If these hash operations fail silently, the resulting HMAC could be
> invalid or incomplete, which could weaken the integrity verification
> security that EVM provides.
> 
> This patch converts hmac_add_misc() from void to int return type and
> adds proper error checking and propagation for all crypto_shash_*
> function calls. All callers are updated to handle the new return values.
> Additionally, error messages are logged when cryptographic operations
> fail to provide visibility into the failure rather than silently
> returning error codes.
> 
> Fixes: 66dbc325afce ("evm: re-release")
> Signed-off-by: Daniel Hodges <git@danielhodges.dev>

After fixing the minor issue below:

Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>

> ---
>  security/integrity/evm/evm_crypto.c | 55 ++++++++++++++++++++++-------
>  1 file changed, 42 insertions(+), 13 deletions(-)
> 
> diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
> index a5e730ffda57..402eb1ca64ce 100644
> --- a/security/integrity/evm/evm_crypto.c
> +++ b/security/integrity/evm/evm_crypto.c
> @@ -139,7 +139,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
>   * (Additional directory/file metadata needs to be added for more complete
>   * protection.)
>   */
> -static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> +static int hmac_add_misc(struct shash_desc *desc, struct inode *inode,
>  			  char type, char *digest)
>  {
>  	struct h_misc {
> @@ -149,6 +149,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
>  		gid_t gid;
>  		umode_t mode;
>  	} hmac_misc;
> +	int error;
>  
>  	memset(&hmac_misc, 0, sizeof(hmac_misc));
>  	/* Don't include the inode or generation number in portable
> @@ -169,14 +170,28 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
>  	hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid);
>  	hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
>  	hmac_misc.mode = inode->i_mode;
> -	crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> +	error = crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> +	if (error) {
> +		pr_err("crypto_shash_update() failed: %d\n", error);
> +		return error;
> +	}
>  	if ((evm_hmac_attrs & EVM_ATTR_FSUUID) &&
> -	    type != EVM_XATTR_PORTABLE_DIGSIG)
> -		crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> -	crypto_shash_final(desc, digest);
> +	    type != EVM_XATTR_PORTABLE_DIGSIG) {
> +		error = crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> +		if (error) {
> +			pr_err("crypto_shash_update() failed: %d\n", error);
> +			return error;
> +		}
> +	}
> +	error = crypto_shash_final(desc, digest);
> +	if (error) {
> +		pr_err("crypto_shash_final() failed: %d\n", error);
> +		return error;
> +	}
>  
>  	pr_debug("hmac_misc: (%zu) [%*phN]\n", sizeof(struct h_misc),
>  		 (int)sizeof(struct h_misc), &hmac_misc);
> +	return 0;
>  }
>  
>  /*
> @@ -260,9 +275,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
>  
>  		if ((req_xattr_name && req_xattr_value)
>  		    && !strcmp(xattr->name, req_xattr_name)) {
> -			error = 0;
> -			crypto_shash_update(desc, (const u8 *)req_xattr_value,
> +			error = crypto_shash_update(desc, (const u8 *)req_xattr_value,
>  					     req_xattr_value_len);

Please align this.

Thanks

Roberto

> +			if (error) {
> +				pr_err("crypto_shash_update() failed: %d\n", error);
> +				goto out;
> +			}
>  			if (is_ima)
>  				ima_present = true;
>  
> @@ -286,15 +304,20 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
>  			pr_debug("file %s: xattr %s size mismatch (kernel: %d, user: %d)\n",
>  				 dentry->d_name.name, xattr->name, size,
>  				 user_space_size);
> -		error = 0;
>  		xattr_size = size;
> -		crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> +		error = crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> +		if (error) {
> +			pr_err("crypto_shash_update() failed: %d\n", error);
> +			goto out;
> +		}
>  		if (is_ima)
>  			ima_present = true;
>  
>  		dump_security_xattr(xattr->name, xattr_value, xattr_size);
>  	}
> -	hmac_add_misc(desc, inode, type, data->digest);
> +	error = hmac_add_misc(desc, inode, type, data->digest);
> +	if (error)
> +		goto out;
>  
>  	if (inode != d_backing_inode(dentry) && iint) {
>  		if (IS_I_VERSION(inode))
> @@ -401,6 +424,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
>  {
>  	struct shash_desc *desc;
>  	const struct xattr *xattr;
> +	int error;
>  
>  	desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
>  	if (IS_ERR(desc)) {
> @@ -412,12 +436,17 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
>  		if (!evm_protected_xattr(xattr->name))
>  			continue;
>  
> -		crypto_shash_update(desc, xattr->value, xattr->value_len);
> +		error = crypto_shash_update(desc, xattr->value, xattr->value_len);
> +		if (error) {
> +			pr_err("crypto_shash_update() failed: %d\n", error);
> +			goto out;
> +		}
>  	}
>  
> -	hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> +	error = hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> +out:
>  	kfree(desc);
> -	return 0;
> +	return error;
>  }
>  
>  /*


^ permalink raw reply

* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Roberto Sassu @ 2026-02-19 12:36 UTC (permalink / raw)
  To: Daniel Hodges
  Cc: zohar, roberto.sassu, dmitry.kasatkin, eric.snowberg, paul,
	jmorris, serge, linux-integrity, linux-security-module,
	linux-kernel
In-Reply-To: <6ce273a26b396232f3ee64a980575562e766c501.camel@huaweicloud.com>

On Thu, 2026-02-19 at 10:26 +0100, Roberto Sassu wrote:
> On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> > The crypto_shash_update() and crypto_shash_final() functions can fail
> > and return error codes, but their return values were not being checked
> > in several places in security/integrity/evm/evm_crypto.c:
> > 
> > - hmac_add_misc() ignored returns from crypto_shash_update() and
> >   crypto_shash_final()
> > - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> > - evm_init_hmac() ignored returns from crypto_shash_update()
> > 
> > If these hash operations fail silently, the resulting HMAC could be
> > invalid or incomplete, which could weaken the integrity verification
> > security that EVM provides.
> > 
> > This patch converts hmac_add_misc() from void to int return type and
> > adds proper error checking and propagation for all crypto_shash_*
> > function calls. All callers are updated to handle the new return values.
> > Additionally, error messages are logged when cryptographic operations
> > fail to provide visibility into the failure rather than silently
> > returning error codes.
> > 
> > Fixes: 66dbc325afce ("evm: re-release")
> > Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> 
> After fixing the minor issue below:

Already did it. The patch is here (after fixing a conflict with
0496fc9cdc38 "evm: Use ordered xattrs list to calculate HMAC in
evm_init_hmac()"):

https://github.com/robertosassu/linux/commit/d5aba42198b602c6de002ef02a4e6cc1d75652d7

Roberto

> Reviewed-by: Roberto Sassu <roberto.sassu@huawei.com>
> 
> > ---
> >  security/integrity/evm/evm_crypto.c | 55 ++++++++++++++++++++++-------
> >  1 file changed, 42 insertions(+), 13 deletions(-)
> > 
> > diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
> > index a5e730ffda57..402eb1ca64ce 100644
> > --- a/security/integrity/evm/evm_crypto.c
> > +++ b/security/integrity/evm/evm_crypto.c
> > @@ -139,7 +139,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
> >   * (Additional directory/file metadata needs to be added for more complete
> >   * protection.)
> >   */
> > -static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> > +static int hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> >  			  char type, char *digest)
> >  {
> >  	struct h_misc {
> > @@ -149,6 +149,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> >  		gid_t gid;
> >  		umode_t mode;
> >  	} hmac_misc;
> > +	int error;
> >  
> >  	memset(&hmac_misc, 0, sizeof(hmac_misc));
> >  	/* Don't include the inode or generation number in portable
> > @@ -169,14 +170,28 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
> >  	hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid);
> >  	hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);
> >  	hmac_misc.mode = inode->i_mode;
> > -	crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> > +	error = crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc));
> > +	if (error) {
> > +		pr_err("crypto_shash_update() failed: %d\n", error);
> > +		return error;
> > +	}
> >  	if ((evm_hmac_attrs & EVM_ATTR_FSUUID) &&
> > -	    type != EVM_XATTR_PORTABLE_DIGSIG)
> > -		crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> > -	crypto_shash_final(desc, digest);
> > +	    type != EVM_XATTR_PORTABLE_DIGSIG) {
> > +		error = crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE);
> > +		if (error) {
> > +			pr_err("crypto_shash_update() failed: %d\n", error);
> > +			return error;
> > +		}
> > +	}
> > +	error = crypto_shash_final(desc, digest);
> > +	if (error) {
> > +		pr_err("crypto_shash_final() failed: %d\n", error);
> > +		return error;
> > +	}
> >  
> >  	pr_debug("hmac_misc: (%zu) [%*phN]\n", sizeof(struct h_misc),
> >  		 (int)sizeof(struct h_misc), &hmac_misc);
> > +	return 0;
> >  }
> >  
> >  /*
> > @@ -260,9 +275,12 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
> >  
> >  		if ((req_xattr_name && req_xattr_value)
> >  		    && !strcmp(xattr->name, req_xattr_name)) {
> > -			error = 0;
> > -			crypto_shash_update(desc, (const u8 *)req_xattr_value,
> > +			error = crypto_shash_update(desc, (const u8 *)req_xattr_value,
> >  					     req_xattr_value_len);
> 
> Please align this.
> 
> Thanks
> 
> Roberto
> 
> > +			if (error) {
> > +				pr_err("crypto_shash_update() failed: %d\n", error);
> > +				goto out;
> > +			}
> >  			if (is_ima)
> >  				ima_present = true;
> >  
> > @@ -286,15 +304,20 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
> >  			pr_debug("file %s: xattr %s size mismatch (kernel: %d, user: %d)\n",
> >  				 dentry->d_name.name, xattr->name, size,
> >  				 user_space_size);
> > -		error = 0;
> >  		xattr_size = size;
> > -		crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> > +		error = crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size);
> > +		if (error) {
> > +			pr_err("crypto_shash_update() failed: %d\n", error);
> > +			goto out;
> > +		}
> >  		if (is_ima)
> >  			ima_present = true;
> >  
> >  		dump_security_xattr(xattr->name, xattr_value, xattr_size);
> >  	}
> > -	hmac_add_misc(desc, inode, type, data->digest);
> > +	error = hmac_add_misc(desc, inode, type, data->digest);
> > +	if (error)
> > +		goto out;
> >  
> >  	if (inode != d_backing_inode(dentry) && iint) {
> >  		if (IS_I_VERSION(inode))
> > @@ -401,6 +424,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
> >  {
> >  	struct shash_desc *desc;
> >  	const struct xattr *xattr;
> > +	int error;
> >  
> >  	desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
> >  	if (IS_ERR(desc)) {
> > @@ -412,12 +436,17 @@ int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
> >  		if (!evm_protected_xattr(xattr->name))
> >  			continue;
> >  
> > -		crypto_shash_update(desc, xattr->value, xattr->value_len);
> > +		error = crypto_shash_update(desc, xattr->value, xattr->value_len);
> > +		if (error) {
> > +			pr_err("crypto_shash_update() failed: %d\n", error);
> > +			goto out;
> > +		}
> >  	}
> >  
> > -	hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> > +	error = hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
> > +out:
> >  	kfree(desc);
> > -	return 0;
> > +	return error;
> >  }
> >  
> >  /*


^ permalink raw reply

* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Daniel Hodges @ 2026-02-19 15:01 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: Daniel Hodges, zohar, roberto.sassu, dmitry.kasatkin,
	eric.snowberg, paul, jmorris, serge, linux-integrity,
	linux-security-module, linux-kernel
In-Reply-To: <cfbd9e3c63e03500279198ec7a80ba009dfccc63.camel@huaweicloud.com>

On Thu, Feb 19, 2026 at 01:36:39PM +0100, Roberto Sassu wrote:
> On Thu, 2026-02-19 at 10:26 +0100, Roberto Sassu wrote:
> > On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> > > The crypto_shash_update() and crypto_shash_final() functions can fail
> > > and return error codes, but their return values were not being checked
> > > in several places in security/integrity/evm/evm_crypto.c:
> > > 
> > > - hmac_add_misc() ignored returns from crypto_shash_update() and
> > >   crypto_shash_final()
> > > - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> > > - evm_init_hmac() ignored returns from crypto_shash_update()
> > > 
> > > If these hash operations fail silently, the resulting HMAC could be
> > > invalid or incomplete, which could weaken the integrity verification
> > > security that EVM provides.
> > > 
> > > This patch converts hmac_add_misc() from void to int return type and
> > > adds proper error checking and propagation for all crypto_shash_*
> > > function calls. All callers are updated to handle the new return values.
> > > Additionally, error messages are logged when cryptographic operations
> > > fail to provide visibility into the failure rather than silently
> > > returning error codes.
> > > 
> > > Fixes: 66dbc325afce ("evm: re-release")
> > > Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> > 
> > After fixing the minor issue below:
> 
> Already did it. The patch is here (after fixing a conflict with
> 0496fc9cdc38 "evm: Use ordered xattrs list to calculate HMAC in
> evm_init_hmac()"):
> 
> https://github.com/robertosassu/linux/commit/d5aba42198b602c6de002ef02a4e6cc1d75652d7
> 
> Roberto

Nice, thanks for handling that!

-Daniel

^ permalink raw reply

* Re: [PATCH v4 15/17] module: Introduce hash-based integrity checking
From: Nicolas Schier @ 2026-02-19 14:27 UTC (permalink / raw)
  To: Thomas Weißschuh
  Cc: Petr Pavlu, Nathan Chancellor, Arnd Bergmann, Luis Chamberlain,
	Sami Tolvanen, Daniel Gomez, Paul Moore, James Morris,
	Serge E. Hallyn, Jonathan Corbet, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Naveen N Rao, Mimi Zohar,
	Roberto Sassu, Dmitry Kasatkin, Eric Snowberg, Daniel Gomez,
	Aaron Tomlin, Christophe Leroy (CS GROUP), Nicolas Bouchinet,
	Xiu Jianfeng, Fabian Grünbichler, Arnout Engelen,
	Mattia Rizzolo, kpcyrd, Christian Heusel, Câju Mihai-Drosi,
	Sebastian Andrzej Siewior, linux-kbuild, linux-kernel, linux-arch,
	linux-modules, linux-security-module, linux-doc, linuxppc-dev,
	linux-integrity
In-Reply-To: <28cf8d51-7530-41d5-a47b-cad5ecabd269@t-8ch.de>

On Tue, Feb 03, 2026 at 01:55:05PM +0100, Thomas Weißschuh wrote:
> On 2026-01-30 18:06:20+0100, Petr Pavlu wrote:
> > On 1/13/26 1:28 PM, Thomas Weißschuh wrote:
> > > Normally the .ko module files depend on a fully built vmlinux to be
> > > available for modpost validation and BTF generation. With
> > > CONFIG_MODULE_HASHES, vmlinux now depends on the modules
> > > to build a merkle tree. This introduces a dependency cycle which is
> > > impossible to satisfy. Work around this by building the modules during
> > > link-vmlinux.sh, after vmlinux is complete enough for modpost and BTF
> > > but before the final module hashes are
> > 
> > I wonder if this dependency cycle could be resolved by utilizing the
> > split into vmlinux.unstripped and vmlinux that occurred last year.
> > 
> > The idea is to create the following ordering: vmlinux.unstripped ->
> > modules -> vmlinux, and to patch in .module_hashes only when building
> > the final vmlinux.
> > 
> > This would require the following:
> > * Split scripts/Makefile.vmlinux into two Makefiles, one that builds the
> >   current vmlinux.unstripped and the second one that builds the final
> >   vmlinux from it.
> > * Modify the top Makefile to recognize vmlinux.unstripped and update the
> >   BTF generation rule 'modules: vmlinux' to
> >   'modules: vmlinux.unstripped'.
> > * Add the 'vmlinux: modules' ordering in the top Makefile for
> >   CONFIG_MODULE_HASHES=y.
> > * Remove the patching of vmlinux.unstripped in scripts/link-vmlinux.sh
> >   and instead move it into scripts/Makefile.vmlinux when running objcopy
> >   to produce the final vmlinux.
> > 
> > I think this approach has two main advantages:
> > * CONFIG_MODULE_HASHES can be made orthogonal to
> >   CONFIG_DEBUG_INFO_BTF_MODULES.
> > * All dependencies are expressed at the Makefile level instead of having
> >   scripts/link-vmlinux.sh invoke 'make -f Makefile modules'.
> > 
> > Below is a rough prototype that applies on top of this series. It is a
> > bit verbose due to the splitting of part of scripts/Makefile.vmlinux
> > into scripts/Makefile.vmlinux_unstripped.
> 
> That looks like a feasible alternative. Before adopting it, I'd like to
> hear the preference of the kbuild folks.
> 
> > diff --git a/Makefile b/Makefile
> > index 841772a5a260..19a3beb82fa7 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -1259,7 +1259,7 @@ vmlinux_o: vmlinux.a $(KBUILD_VMLINUX_LIBS)
> >  vmlinux.o modules.builtin.modinfo modules.builtin: vmlinux_o
> >  	@:
> >  
> > -PHONY += vmlinux
> > +PHONY += vmlinux.unstripped vmlinux
> >  # LDFLAGS_vmlinux in the top Makefile defines linker flags for the top vmlinux,
> >  # not for decompressors. LDFLAGS_vmlinux in arch/*/boot/compressed/Makefile is
> >  # unrelated; the decompressors just happen to have the same base name,
> > @@ -1270,9 +1270,11 @@ PHONY += vmlinux
> >  #   https://savannah.gnu.org/bugs/?61463
> >  # For Make > 4.4, the following simple code will work:
> >  #  vmlinux: private export LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > -vmlinux: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > -vmlinux: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
> > -vmlinux: vmlinux.o $(KBUILD_LDS) modpost
> > +vmlinux.unstripped: private _LDFLAGS_vmlinux := $(LDFLAGS_vmlinux)
> > +vmlinux.unstripped: export LDFLAGS_vmlinux = $(_LDFLAGS_vmlinux)
> > +vmlinux.unstripped: vmlinux.o $(KBUILD_LDS) modpost
> > +	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux_unstripped
> > +vmlinux: vmlinux.unstripped
> >  	$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.vmlinux
> 
> Maybe we could keep them together in a single Makefile,
> and instead have different targets in it.
> 

yes, I think so, too.  I like the Petr's alternative.

Kind regards,
Nicolas

^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: H. Peter Anvin @ 2026-02-19 17:10 UTC (permalink / raw)
  To: Ard Biesheuvel, Andy Lutomirski, Simo Sorce
  Cc: Daniel P. Smith, Ross Philipson, linux-kernel, x86,
	linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu,
	dave.hansen, Thomas Gleixner, Ingo Molnar, Borislav Petkov, mjg59,
	James.Bottomley, peterhuewe, Jarkko Sakkinen, jgg, nivedita,
	Herbert Xu, davem, corbet, ebiederm, dwmw2, baolu.lu,
	kanth.ghatraju, andrew.cooper3, trenchboot-devel
In-Reply-To: <558d0f28-01fb-4447-891c-2ffbf869c077@app.fastmail.com>

On February 18, 2026 11:54:55 PM PST, Ard Biesheuvel <ardb@kernel.org> wrote:
>On Wed, 18 Feb 2026, at 22:54, Andy Lutomirski wrote:
>> On Wed, Feb 18, 2026 at 1:04 PM Simo Sorce <simo@redhat.com> wrote:
>>>
>>> On Wed, 2026-02-18 at 12:34 -0800, Andy Lutomirski wrote:
>>> > On Wed, Feb 18, 2026 at 12:29 PM H. Peter Anvin <hpa@zytor.com> wrote:
>>> > >
>>> > > On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
>>> > > > On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>>> > > > >
>>> > > > > On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
>>> > > > > > On 2/9/26 09:04, Ard Biesheuvel wrote:
>>> > > > > ...
>>> > > > > But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
>>> > > >
>>> > > > So I have a possible way to disable EFI runtime service without losing
>>> > > > the ability to write EFI vars.  We come up with a simple file format
>>> > > > to store deferred EFI var updates and we come up with a place to put
>>> > > > it so that we find it early-ish in boot the next time around.  (This
>>> > > > could be done via integration with systemd-boot or shim some other
>>> > > > boot loader or it could actually be part of the kernel.)  And then,
>>> > > > instead of writing variables directly, we write them to the deferred
>>> > > > list and then update them on reboot (before TXT launch, etc).  [0]
>>> > > > This would be a distincly nontrivial project and would not work for
>>> > > > all configurations.
>>> > > >
>>> > > > As a maybe less painful option, we could disable EFI runtime services
>>> > > > but have a root-writable thing in sysfs that (a) turns them back on
>>> > > > but (b) first extends a PCR to say that they're turned back on.
>>> > > >
>>> > > > (Or someone could try running runtime services at CPL3...)
>>> > > >
>>> > > > [0] I have thought for years that Intel and AMD should do this on
>>> > > > their end, too.  Keep the sensitive part of SMI flash entirely locked
>>> > > > after boot and, instead of using magic SMM stuff to validate that
>>> > > > write attempts have the appropriate permissions and signatures, queue
>>> > > > them up as deferred upates and validate the signatures on the next
>>> > > > boot before locking flash.
>>> > > >
>>> > >
>>> > > *If* a physical EFI partition exists there is a lot to be said for this approach.
>>> > >
>>> > > The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)
>>> >
>>> > Hmm, I guess my approach is a 100% complete nonstarter for installing
>>> > Linux from a CD, and it's really not awesome for installing Linux from
>>> > a USB stick.
>>>
>>> Doing any of this on a removable device feels generally like a trap.
>>> You get your USB disk in, try to boot, and it saves vars, but reboot
>>> fails for whatever reason, you plug it in another machine ... and it
>>> tries to "continue" from there? The amount of validation needed and
>>> testing for failure modes across reboots sounds really painful.
>>
>> I kind of stand by my other previous suggestion, though:
>>
>> As a maybe less painful option, we could disable EFI runtime services
>> but have a root-writable thing in sysfs that (a) turns them back on
>> but (b) first extends a PCR to say that they're turned back on.
>>
>
>After setting the EFI boot path to GRUB (or systemd-boot or whatever) at installation time, what other meaningful interactions do we expect with the EFI runtime services?
>
>And given that the secure launch is orchestrated by the bootloader , with which the kernel has a backchannel via its configuration file, it should be rather straight-forward to implement the staging of variable updates there if we really need it. 
>
>Doing any of this at the EFI/spec level might lead to a situation where the OS now has to guess which of the provided APIs to manipulate variables is the least broken.
>
>Of course, for readinf variables, dumping the RT variables into a memory buffer at boot time and exposing it via a EFI config table would be rather straight-forward, but it is also something I feel should be the job of the boot component that takes part in the decision to shield the runtime services from the OS.
>
>
>
>

The statement "that the kernel has a backchannel to" is *not true in general*.

^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: Andy Lutomirski @ 2026-02-19 17:34 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Simo Sorce, H . Peter Anvin, Daniel P. Smith, Ross Philipson,
	linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
	kexec, linux-efi, iommu, dave.hansen, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, mjg59, James.Bottomley, peterhuewe,
	Jarkko Sakkinen, jgg, nivedita, Herbert Xu, davem, corbet,
	ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
	trenchboot-devel
In-Reply-To: <558d0f28-01fb-4447-891c-2ffbf869c077@app.fastmail.com>

On Wed, Feb 18, 2026 at 11:55 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Wed, 18 Feb 2026, at 22:54, Andy Lutomirski wrote:
> > On Wed, Feb 18, 2026 at 1:04 PM Simo Sorce <simo@redhat.com> wrote:
> >>
> >> On Wed, 2026-02-18 at 12:34 -0800, Andy Lutomirski wrote:
> >> > On Wed, Feb 18, 2026 at 12:29 PM H. Peter Anvin <hpa@zytor.com> wrote:
> >> > >
> >> > > On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
> >> > > > On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
> >> > > > >
> >> > > > > On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
> >> > > > > > On 2/9/26 09:04, Ard Biesheuvel wrote:
> >> > > > > ...
> >> > > > > But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
> >> > > >
> >> > > > So I have a possible way to disable EFI runtime service without losing
> >> > > > the ability to write EFI vars.  We come up with a simple file format
> >> > > > to store deferred EFI var updates and we come up with a place to put
> >> > > > it so that we find it early-ish in boot the next time around.  (This
> >> > > > could be done via integration with systemd-boot or shim some other
> >> > > > boot loader or it could actually be part of the kernel.)  And then,
> >> > > > instead of writing variables directly, we write them to the deferred
> >> > > > list and then update them on reboot (before TXT launch, etc).  [0]
> >> > > > This would be a distincly nontrivial project and would not work for
> >> > > > all configurations.
> >> > > >
> >> > > > As a maybe less painful option, we could disable EFI runtime services
> >> > > > but have a root-writable thing in sysfs that (a) turns them back on
> >> > > > but (b) first extends a PCR to say that they're turned back on.
> >> > > >
> >> > > > (Or someone could try running runtime services at CPL3...)
> >> > > >
> >> > > > [0] I have thought for years that Intel and AMD should do this on
> >> > > > their end, too.  Keep the sensitive part of SMI flash entirely locked
> >> > > > after boot and, instead of using magic SMM stuff to validate that
> >> > > > write attempts have the appropriate permissions and signatures, queue
> >> > > > them up as deferred upates and validate the signatures on the next
> >> > > > boot before locking flash.
> >> > > >
> >> > >
> >> > > *If* a physical EFI partition exists there is a lot to be said for this approach.
> >> > >
> >> > > The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)
> >> >
> >> > Hmm, I guess my approach is a 100% complete nonstarter for installing
> >> > Linux from a CD, and it's really not awesome for installing Linux from
> >> > a USB stick.
> >>
> >> Doing any of this on a removable device feels generally like a trap.
> >> You get your USB disk in, try to boot, and it saves vars, but reboot
> >> fails for whatever reason, you plug it in another machine ... and it
> >> tries to "continue" from there? The amount of validation needed and
> >> testing for failure modes across reboots sounds really painful.
> >
> > I kind of stand by my other previous suggestion, though:
> >
> > As a maybe less painful option, we could disable EFI runtime services
> > but have a root-writable thing in sysfs that (a) turns them back on
> > but (b) first extends a PCR to say that they're turned back on.
> >
>
> After setting the EFI boot path to GRUB (or systemd-boot or whatever) at installation time, what other meaningful interactions do we expect with the EFI runtime services?
>
> And given that the secure launch is orchestrated by the bootloader , with which the kernel has a backchannel via its configuration file, it should be rather straight-forward to implement the staging of variable updates there if we really need it.
>
> Doing any of this at the EFI/spec level might lead to a situation where the OS now has to guess which of the provided APIs to manipulate variables is the least broken.
>
> Of course, for readinf variables, dumping the RT variables into a memory buffer at boot time and exposing it via a EFI config table would be rather straight-forward, but it is also something I feel should be the job of the boot component that takes part in the decision to shield the runtime services from the OS.

So there's sort of a usability issue here.  On the one hand, this can
all be orchestrated to work.  We build a kernel, and the kernel
supports secure launch.  Someone makes an installer image, and that
image is configured to skip secure launch, then install to disk, then
program EFI vars, then reboot.  And the installed image is configured
to do the secure launch, and EFI variable writes are turned off.

On the other hand, this all sucks.  I'm getting sick of having the
kernel tell me that I am not permitted to do things.  I'm sick of
writing software that deals with unnecessary restrictions.  If I were
writing an OS with a USB stick-based installer, I might want to be
able to boot the thing and decide later whether I'm installing an OS
to disk.  (In fact, many USB installers work this way.)  But, in the
model where EFI variable writes are hard-disabled on a secure launch,
the decision to do the secure launch happens before the decision to
install an OS, and we all lose.

So I'm proposing that EFI variable writes be treated a bit like kexec
[0] -- root (which is already part of the TCB for any practical
purpose) is going to decide, like a grown up, to execute some code
that it doesn't fully trust -- in this case, the EFI variable writes.
And root will coordinate, correctly, with whomever it's busy using the
TPM to coordinate with, and tell it that it's going to do something
that will change its trustworthiness.  So it works like this:

1. Secure launch the environment on the stick.  (At this stage,
neither the boot loader nor the kernel has the faintest clue whether
anyone needs that secure launch, but this doesn't matter.)

2. The owner of the machine clicks "install".

3. The installer makes some partitions and writes some files.

(Up until now, the security posture of the running environment has not changed.)

4. The installer decides that it's now time to do untrustworthy
things, namely writing EFI vars.  So it unmounts anything it mounted
using TPM-sealed keys (or not -- this is between the distro and
whoever trusts the distro), and it does:

# echo 1 >/sys/.../extend_pcr_and_unlock_efi

which *first* extends a PCR because we are about to change our
security posture and *second* sets whatever flag permits use of EFI
runtime services.

5. The installer writes to EFI variables.  And the installer can no
longer generate attestations to its previous security posture, which
is the correct behavior.  And maybe the user can no longer unlock
their home directory or whatever until they reboot.  Which is not
really a big deal.

(This is *dynamic* root of trust.  In theory the system could do a
DRTM re-launch and recover its security posture, but I don't think
this is implemented.)


One thing I like about this is that it involves very little code.

[0] Do we actually handle kexec intelligently?  I have no idea.  I'm
still getting used to the time that gdb fails half the time because
someone has a strange concept of security.

^ permalink raw reply

* Re: [PATCH v15 00/28] x86: Secure Launch support for Intel TXT
From: Ard Biesheuvel @ 2026-02-20  8:30 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Simo Sorce, H . Peter Anvin, Daniel P. Smith, Ross Philipson,
	linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
	kexec, linux-efi, iommu, dave.hansen, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, mjg59, James.Bottomley, peterhuewe,
	Jarkko Sakkinen, jgg, nivedita, Herbert Xu, davem, corbet,
	ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
	trenchboot-devel
In-Reply-To: <CALCETrWynypSD7vEjJNLcym3JhBw4k0ovDiR_3YuOHh92TnM=A@mail.gmail.com>



On Thu, 19 Feb 2026, at 18:34, Andy Lutomirski wrote:
> On Wed, Feb 18, 2026 at 11:55 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>>
>> On Wed, 18 Feb 2026, at 22:54, Andy Lutomirski wrote:
>> > On Wed, Feb 18, 2026 at 1:04 PM Simo Sorce <simo@redhat.com> wrote:
>> >>
>> >> On Wed, 2026-02-18 at 12:34 -0800, Andy Lutomirski wrote:
>> >> > On Wed, Feb 18, 2026 at 12:29 PM H. Peter Anvin <hpa@zytor.com> wrote:
>> >> > >
>> >> > > On February 18, 2026 12:03:27 PM PST, Andy Lutomirski <luto@amacapital.net> wrote:
>> >> > > > On Thu, Feb 12, 2026 at 12:40 PM Ard Biesheuvel <ardb@kernel.org> wrote:
>> >> > > > >
>> >> > > > > On Thu, 12 Feb 2026, at 20:49, Daniel P. Smith wrote:
>> >> > > > > > On 2/9/26 09:04, Ard Biesheuvel wrote:
>> >> > > > > ...
>> >> > > > > But would it be better to disable the runtime services by default when doing a secure launch? PREEMPT_RT already does the same.
>> >> > > >
>> >> > > > So I have a possible way to disable EFI runtime service without losing
>> >> > > > the ability to write EFI vars.  We come up with a simple file format
>> >> > > > to store deferred EFI var updates and we come up with a place to put
>> >> > > > it so that we find it early-ish in boot the next time around.  (This
>> >> > > > could be done via integration with systemd-boot or shim some other
>> >> > > > boot loader or it could actually be part of the kernel.)  And then,
>> >> > > > instead of writing variables directly, we write them to the deferred
>> >> > > > list and then update them on reboot (before TXT launch, etc).  [0]
>> >> > > > This would be a distincly nontrivial project and would not work for
>> >> > > > all configurations.
>> >> > > >
>> >> > > > As a maybe less painful option, we could disable EFI runtime services
>> >> > > > but have a root-writable thing in sysfs that (a) turns them back on
>> >> > > > but (b) first extends a PCR to say that they're turned back on.
>> >> > > >
>> >> > > > (Or someone could try running runtime services at CPL3...)
>> >> > > >
>> >> > > > [0] I have thought for years that Intel and AMD should do this on
>> >> > > > their end, too.  Keep the sensitive part of SMI flash entirely locked
>> >> > > > after boot and, instead of using magic SMM stuff to validate that
>> >> > > > write attempts have the appropriate permissions and signatures, queue
>> >> > > > them up as deferred upates and validate the signatures on the next
>> >> > > > boot before locking flash.
>> >> > > >
>> >> > >
>> >> > > *If* a physical EFI partition exists there is a lot to be said for this approach.
>> >> > >
>> >> > > The only issue with this that I can see is for things like network or CD/DVD booting where there isn't necessarily any EFI boot partition, it might not be writable, or it might not be persistent (e.g. http booting typically uses a ramdisk, like the old Linux initrd.)
>> >> >
>> >> > Hmm, I guess my approach is a 100% complete nonstarter for installing
>> >> > Linux from a CD, and it's really not awesome for installing Linux from
>> >> > a USB stick.
>> >>
>> >> Doing any of this on a removable device feels generally like a trap.
>> >> You get your USB disk in, try to boot, and it saves vars, but reboot
>> >> fails for whatever reason, you plug it in another machine ... and it
>> >> tries to "continue" from there? The amount of validation needed and
>> >> testing for failure modes across reboots sounds really painful.
>> >
>> > I kind of stand by my other previous suggestion, though:
>> >
>> > As a maybe less painful option, we could disable EFI runtime services
>> > but have a root-writable thing in sysfs that (a) turns them back on
>> > but (b) first extends a PCR to say that they're turned back on.
>> >
>>
>> After setting the EFI boot path to GRUB (or systemd-boot or whatever) at installation time, what other meaningful interactions do we expect with the EFI runtime services?
>>
>> And given that the secure launch is orchestrated by the bootloader , with which the kernel has a backchannel via its configuration file, it should be rather straight-forward to implement the staging of variable updates there if we really need it.
>>
>> Doing any of this at the EFI/spec level might lead to a situation where the OS now has to guess which of the provided APIs to manipulate variables is the least broken.
>>
>> Of course, for readinf variables, dumping the RT variables into a memory buffer at boot time and exposing it via a EFI config table would be rather straight-forward, but it is also something I feel should be the job of the boot component that takes part in the decision to shield the runtime services from the OS.
>
> So there's sort of a usability issue here.  On the one hand, this can
> all be orchestrated to work.  We build a kernel, and the kernel
> supports secure launch.  Someone makes an installer image, and that
> image is configured to skip secure launch, then install to disk, then
> program EFI vars, then reboot.  And the installed image is configured
> to do the secure launch, and EFI variable writes are turned off.
>
> On the other hand, this all sucks.  I'm getting sick of having the
> kernel tell me that I am not permitted to do things.  I'm sick of
> writing software that deals with unnecessary restrictions.  If I were
> writing an OS with a USB stick-based installer, I might want to be
> able to boot the thing and decide later whether I'm installing an OS
> to disk.  (In fact, many USB installers work this way.)  But, in the
> model where EFI variable writes are hard-disabled on a secure launch,
> the decision to do the secure launch happens before the decision to
> install an OS, and we all lose.
>
> So I'm proposing that EFI variable writes be treated a bit like kexec
> [0] -- root (which is already part of the TCB for any practical
> purpose) is going to decide, like a grown up, to execute some code
> that it doesn't fully trust -- in this case, the EFI variable writes.
> And root will coordinate, correctly, with whomever it's busy using the
> TPM to coordinate with, and tell it that it's going to do something
> that will change its trustworthiness.  So it works like this:
>
> 1. Secure launch the environment on the stick.  (At this stage,
> neither the boot loader nor the kernel has the faintest clue whether
> anyone needs that secure launch, but this doesn't matter.)
>
> 2. The owner of the machine clicks "install".
>
> 3. The installer makes some partitions and writes some files.
>
> (Up until now, the security posture of the running environment has not changed.)
>
> 4. The installer decides that it's now time to do untrustworthy
> things, namely writing EFI vars.  So it unmounts anything it mounted
> using TPM-sealed keys (or not -- this is between the distro and
> whoever trusts the distro), and it does:
>
> # echo 1 >/sys/.../extend_pcr_and_unlock_efi
>
> which *first* extends a PCR because we are about to change our
> security posture and *second* sets whatever flag permits use of EFI
> runtime services.
>
> 5. The installer writes to EFI variables.  And the installer can no
> longer generate attestations to its previous security posture, which
> is the correct behavior.  And maybe the user can no longer unlock
> their home directory or whatever until they reboot.  Which is not
> really a big deal.
>
> (This is *dynamic* root of trust.  In theory the system could do a
> DRTM re-launch and recover its security posture, but I don't think
> this is implemented.)
>
>
> One thing I like about this is that it involves very little code.
>

It does seem rather straight-forward, and it doesn't have to be specific to TXT either. I.e., we should probably always measure the runtime enabled/disabled state into the PCRs.

But given the actual problem at hand (untrustworthy glue code running in ring 3 that does little more than poke SMM, which itself fundamentally remains part of the TCB), it would be nice if we could just sandbox that code using virtualization.

This came up in a separate discussion regarding ACPI PRM (the new dumping ground for evil vendor code now that SMM has gone out of fashion), although there it should be feasible to run it unprivileged, as the spec requires that capability for the PRM payloads.

^ permalink raw reply

* Re: [PATCH v2 v2] evm: check return values of crypto_shash functions
From: Roberto Sassu @ 2026-02-20  9:06 UTC (permalink / raw)
  To: Daniel Hodges
  Cc: Daniel Hodges, zohar, roberto.sassu, dmitry.kasatkin,
	eric.snowberg, paul, jmorris, serge, linux-integrity,
	linux-security-module, linux-kernel
In-Reply-To: <lj2loy57pavtihqeuywpc2aev7zy3k3poop346dtmelmocp75q@lbejeufrrxwr>

On Thu, 2026-02-19 at 10:01 -0500, Daniel Hodges wrote:
> On Thu, Feb 19, 2026 at 01:36:39PM +0100, Roberto Sassu wrote:
> > On Thu, 2026-02-19 at 10:26 +0100, Roberto Sassu wrote:
> > > On Thu, 2026-02-05 at 21:42 -0500, Daniel Hodges wrote:
> > > > The crypto_shash_update() and crypto_shash_final() functions can fail
> > > > and return error codes, but their return values were not being checked
> > > > in several places in security/integrity/evm/evm_crypto.c:
> > > > 
> > > > - hmac_add_misc() ignored returns from crypto_shash_update() and
> > > >   crypto_shash_final()
> > > > - evm_calc_hmac_or_hash() ignored returns from crypto_shash_update()
> > > > - evm_init_hmac() ignored returns from crypto_shash_update()
> > > > 
> > > > If these hash operations fail silently, the resulting HMAC could be
> > > > invalid or incomplete, which could weaken the integrity verification
> > > > security that EVM provides.
> > > > 
> > > > This patch converts hmac_add_misc() from void to int return type and
> > > > adds proper error checking and propagation for all crypto_shash_*
> > > > function calls. All callers are updated to handle the new return values.
> > > > Additionally, error messages are logged when cryptographic operations
> > > > fail to provide visibility into the failure rather than silently
> > > > returning error codes.
> > > > 
> > > > Fixes: 66dbc325afce ("evm: re-release")
> > > > Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> > > 
> > > After fixing the minor issue below:
> > 
> > Already did it. The patch is here (after fixing a conflict with
> > 0496fc9cdc38 "evm: Use ordered xattrs list to calculate HMAC in
> > evm_init_hmac()"):
> > 
> > https://github.com/robertosassu/linux/commit/d5aba42198b602c6de002ef02a4e6cc1d75652d7
> > 
> > Roberto
> 
> Nice, thanks for handling that!

Welcome!

Roberto


^ permalink raw reply

* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
From: Ard Biesheuvel @ 2026-02-20 15:35 UTC (permalink / raw)
  To: Daniel P. Smith, Thomas Gleixner, Eric W. Biederman, Eric Biggers
  Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
	linux-crypto, kexec, linux-efi, iommu, Ingo Molnar,
	Borislav Petkov, H . Peter Anvin, dave.hansen, Matthew Garrett,
	James Bottomley, peterhuewe, Jarkko Sakkinen, jgg,
	Andy Lutomirski, nivedita, Herbert Xu, davem, corbet, dwmw2,
	baolu.lu, kanth.ghatraju, Andrew Cooper, trenchboot-devel
In-Reply-To: <281c3bb3-13f6-47a2-9a9a-134e397bf686@apertussolutions.com>

Coming back to this old thread after having spent some time playing with the code:

On Thu, 22 Aug 2024, at 20:29, Daniel P. Smith wrote:

<selective snip>

> Another fact to consider is that the current Intel's TXT MLE 
> specification dictates SHA1 as a valid configuration. Secure Launch's 
> use of SHA1 is therefore to comply with Intel's specification for TXT. 

As I understand the Intel TXT spec and the code:

- TPM 1.2 is no longer supported by the TXT spec (since 2023)
- TPM 1.2 is not supported by your GRUB implementation
- in TPM 2.0 mode, SHA1 is only supported by the TXT spec if it is the /only/ algo supported by the TPM
- the proposed kernel implementation ignores any SHA-384 and SM3-256 PCR banks if they are active, and caps them using a { 1, 0, ... } fake digest.

So apologies for being slow, but I still struggle to understand why it is so important to have a SHA-1 implementation to cap those PCRs. Is it just to support systems with a TPM 2.0 that only has SHA-1 banks enabled?

Assuming that this code will get merged this year, it will be in a LTS branch by 2027, by which time distros like Debian will pick it up. 

I fully understand that this code has lived out-of-tree for more than a decade, and you likely prefer to get everything upstream that your current users may be relying on. But for Linux, this is a new feature, and merging code now that is basically obsolete on day 1 is not something we should entertain imo.

(and apologies for re-opening yet another can of worms - I assure you I am trying to be constructive here)

-- 
Ard.


^ 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 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

* [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

* [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 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] 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


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