Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-20 Thread David Hildenbrand (Arm)
On 4/20/26 08:46, Kevin Brodsky wrote:
> On 17/04/2026 19:38, David Hildenbrand (Arm) wrote:
>> On 4/17/26 17:59, Kevin Brodsky wrote:
>>> The first two are not meant to be directly called, they're the
>>> arch-specific implementation of kpkeys_set_level() and
>>> kpkeys_restore_pkey_reg(), and those generic functions handle some
>>> generic logic.
>>>
>>> arch_kpkeys_enabled() is directly used in generic code, so I suppose it
>>> could be renamed to kpkeys_enabled()? It's actually implemented in an
>>> arch header so I wasn't too sure about it.
>> I was skimming over patch #13 and spotted:
>>
>> +void·__init·kpkeys_hardened_pgtables_init(void)
>> +{
>> +›   if·(!arch_kpkeys_enabled())
>> +›   ›   return;
>> +
>> +›   static_branch_enable(&kpkeys_hardened_pgtables_key);
>> +}
>>
>> The arch_* there can just go IMHO.
>>
>> I'd also do it for the two ones used by the GUARD macros. If we don't
>> expect common code wrappers (arch_kpkeys_enabled() vs. kpkeys_enabled),
>> then the arch_ is unnecessary information -- IMHO
> 
> Makes sense. I could just rename arch_kpkeys_enabled() to
> kpkeys_enabled(), but I'm thinking having an arch abstraction could be
> clearer, after looking into protecting sparse-vmemmap page tables. The
> new version would look like this:
> 
> * :
>     - arch_supports_kpkeys()
>     - arch_supports_kpkeys_early() [can be called before features have
> been detected]
> 
> *  defines:
>     - kpkeys_enabled() -> arch_supports_kpkeys()
>     - kpkeys_hardened_pgtables_enabled() -> static key
>     - kpkeys_hardened_pgtables_early_enabled() ->
> arch_supports_kpkeys_early() [called when setting up sparse-vmemmap,
> linear map, etc.]
> 
> There is extra #ifdef'ing going on in , but
>  doesn't need to worry about it. I think this might be
> easier to follow, I don't like too much having an interface function
> like kpkeys_enabled() defined in an arch header (not great for
> kernel-doc comments either). Any thoughts?

No strong opinion on the indirection as long as we don't call arch_
stuff from ordinary pkey user code :)

-- 
Cheers,

David



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-19 Thread Kevin Brodsky
On 17/04/2026 19:38, David Hildenbrand (Arm) wrote:
> On 4/17/26 17:59, Kevin Brodsky wrote:
>> On 17/04/2026 16:37, David Hildenbrand (Arm) wrote:
>>> On 2/27/26 18:54, Kevin Brodsky wrote:
 kpkeys is a simple framework to enable the use of protection keys
 (pkeys) to harden the kernel itself. This patch introduces the basic
 API in : a couple of functions to set and restore
 the pkey register and macros to define guard objects.

 kpkeys introduces a new concept on top of pkeys: the kpkeys level.
 Each level is associated to a set of permissions for the pkeys
 managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
 permissions according to lvl, and returns the original pkey
 register, to be later restored by kpkeys_restore_pkey_reg(). To
 start with, only KPKEYS_LVL_DEFAULT is available, which is meant
 to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
 this is the only available pkey for now).

 Because each architecture implementing pkeys uses a different
 representation for the pkey register, and may reserve certain pkeys
 for specific uses, support for kpkeys must be explicitly indicated
 by selecting ARCH_HAS_KPKEYS and defining the following functions in
 , in addition to the macros provided in
 :

 - arch_kpkeys_set_level()
 - arch_kpkeys_restore_pkey_reg()
 - arch_kpkeys_enabled()
>>> Another thing: why not simply drop the "arch_" stuff from these helpers?
>> The first two are not meant to be directly called, they're the
>> arch-specific implementation of kpkeys_set_level() and
>> kpkeys_restore_pkey_reg(), and those generic functions handle some
>> generic logic.
>>
>> arch_kpkeys_enabled() is directly used in generic code, so I suppose it
>> could be renamed to kpkeys_enabled()? It's actually implemented in an
>> arch header so I wasn't too sure about it.
> I was skimming over patch #13 and spotted:
>
> +void·__init·kpkeys_hardened_pgtables_init(void)
> +{
> +›if·(!arch_kpkeys_enabled())
> +››   return;
> +
> +›static_branch_enable(&kpkeys_hardened_pgtables_key);
> +}
>
> The arch_* there can just go IMHO.
>
> I'd also do it for the two ones used by the GUARD macros. If we don't
> expect common code wrappers (arch_kpkeys_enabled() vs. kpkeys_enabled),
> then the arch_ is unnecessary information -- IMHO

Makes sense. I could just rename arch_kpkeys_enabled() to
kpkeys_enabled(), but I'm thinking having an arch abstraction could be
clearer, after looking into protecting sparse-vmemmap page tables. The
new version would look like this:

* :
    - arch_supports_kpkeys()
    - arch_supports_kpkeys_early() [can be called before features have
been detected]

*  defines:
    - kpkeys_enabled() -> arch_supports_kpkeys()
    - kpkeys_hardened_pgtables_enabled() -> static key
    - kpkeys_hardened_pgtables_early_enabled() ->
arch_supports_kpkeys_early() [called when setting up sparse-vmemmap,
linear map, etc.]

There is extra #ifdef'ing going on in , but
 doesn't need to worry about it. I think this might be
easier to follow, I don't like too much having an interface function
like kpkeys_enabled() defined in an arch header (not great for
kernel-doc comments either). Any thoughts?

- Kevin



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-17 Thread David Hildenbrand (Arm)
On 4/17/26 17:59, Kevin Brodsky wrote:
> On 17/04/2026 16:37, David Hildenbrand (Arm) wrote:
>> On 2/27/26 18:54, Kevin Brodsky wrote:
>>> kpkeys is a simple framework to enable the use of protection keys
>>> (pkeys) to harden the kernel itself. This patch introduces the basic
>>> API in : a couple of functions to set and restore
>>> the pkey register and macros to define guard objects.
>>>
>>> kpkeys introduces a new concept on top of pkeys: the kpkeys level.
>>> Each level is associated to a set of permissions for the pkeys
>>> managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
>>> permissions according to lvl, and returns the original pkey
>>> register, to be later restored by kpkeys_restore_pkey_reg(). To
>>> start with, only KPKEYS_LVL_DEFAULT is available, which is meant
>>> to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
>>> this is the only available pkey for now).
>>>
>>> Because each architecture implementing pkeys uses a different
>>> representation for the pkey register, and may reserve certain pkeys
>>> for specific uses, support for kpkeys must be explicitly indicated
>>> by selecting ARCH_HAS_KPKEYS and defining the following functions in
>>> , in addition to the macros provided in
>>> :
>>>
>>> - arch_kpkeys_set_level()
>>> - arch_kpkeys_restore_pkey_reg()
>>> - arch_kpkeys_enabled()
>> Another thing: why not simply drop the "arch_" stuff from these helpers?
> 
> The first two are not meant to be directly called, they're the
> arch-specific implementation of kpkeys_set_level() and
> kpkeys_restore_pkey_reg(), and those generic functions handle some
> generic logic.
> 
> arch_kpkeys_enabled() is directly used in generic code, so I suppose it
> could be renamed to kpkeys_enabled()? It's actually implemented in an
> arch header so I wasn't too sure about it.
I was skimming over patch #13 and spotted:

+void·__init·kpkeys_hardened_pgtables_init(void)
+{
+›  if·(!arch_kpkeys_enabled())
+›  ›   return;
+
+›  static_branch_enable(&kpkeys_hardened_pgtables_key);
+}

The arch_* there can just go IMHO.

I'd also do it for the two ones used by the GUARD macros. If we don't
expect common code wrappers (arch_kpkeys_enabled() vs. kpkeys_enabled),
then the arch_ is unnecessary information -- IMHO

-- 
Cheers,

David



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-17 Thread Kevin Brodsky
On 17/04/2026 16:37, David Hildenbrand (Arm) wrote:
> On 2/27/26 18:54, Kevin Brodsky wrote:
>> kpkeys is a simple framework to enable the use of protection keys
>> (pkeys) to harden the kernel itself. This patch introduces the basic
>> API in : a couple of functions to set and restore
>> the pkey register and macros to define guard objects.
>>
>> kpkeys introduces a new concept on top of pkeys: the kpkeys level.
>> Each level is associated to a set of permissions for the pkeys
>> managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
>> permissions according to lvl, and returns the original pkey
>> register, to be later restored by kpkeys_restore_pkey_reg(). To
>> start with, only KPKEYS_LVL_DEFAULT is available, which is meant
>> to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
>> this is the only available pkey for now).
>>
>> Because each architecture implementing pkeys uses a different
>> representation for the pkey register, and may reserve certain pkeys
>> for specific uses, support for kpkeys must be explicitly indicated
>> by selecting ARCH_HAS_KPKEYS and defining the following functions in
>> , in addition to the macros provided in
>> :
>>
>> - arch_kpkeys_set_level()
>> - arch_kpkeys_restore_pkey_reg()
>> - arch_kpkeys_enabled()
> Another thing: why not simply drop the "arch_" stuff from these helpers?

The first two are not meant to be directly called, they're the
arch-specific implementation of kpkeys_set_level() and
kpkeys_restore_pkey_reg(), and those generic functions handle some
generic logic.

arch_kpkeys_enabled() is directly used in generic code, so I suppose it
could be renamed to kpkeys_enabled()? It's actually implemented in an
arch header so I wasn't too sure about it.

- Kevin



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-17 Thread David Hildenbrand (Arm)
On 2/27/26 18:54, Kevin Brodsky wrote:
> kpkeys is a simple framework to enable the use of protection keys
> (pkeys) to harden the kernel itself. This patch introduces the basic
> API in : a couple of functions to set and restore
> the pkey register and macros to define guard objects.
> 
> kpkeys introduces a new concept on top of pkeys: the kpkeys level.
> Each level is associated to a set of permissions for the pkeys
> managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
> permissions according to lvl, and returns the original pkey
> register, to be later restored by kpkeys_restore_pkey_reg(). To
> start with, only KPKEYS_LVL_DEFAULT is available, which is meant
> to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
> this is the only available pkey for now).
> 
> Because each architecture implementing pkeys uses a different
> representation for the pkey register, and may reserve certain pkeys
> for specific uses, support for kpkeys must be explicitly indicated
> by selecting ARCH_HAS_KPKEYS and defining the following functions in
> , in addition to the macros provided in
> :
> 
> - arch_kpkeys_set_level()
> - arch_kpkeys_restore_pkey_reg()
> - arch_kpkeys_enabled()

Another thing: why not simply drop the "arch_" stuff from these helpers?

-- 
Cheers,

David



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-17 Thread Kevin Brodsky
On 17/04/2026 14:00, David Hildenbrand (Arm) wrote:
> On 4/15/26 17:50, Kevin Brodsky wrote:
>> On 15/04/2026 15:00, David Hildenbrand (Arm) wrote:
>>> On 2/27/26 18:54, Kevin Brodsky wrote:
 kpkeys is a simple framework to enable the use of protection keys
 (pkeys) to harden the kernel itself. This patch introduces the basic
 API in : a couple of functions to set and restore
 the pkey register and macros to define guard objects.

 kpkeys introduces a new concept on top of pkeys: the kpkeys level.
 Each level is associated to a set of permissions for the pkeys
 managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
 permissions according to lvl, and returns the original pkey
 register, to be later restored by kpkeys_restore_pkey_reg(). To
 start with, only KPKEYS_LVL_DEFAULT is available, which is meant
 to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
 this is the only available pkey for now).

 Because each architecture implementing pkeys uses a different
 representation for the pkey register, and may reserve certain pkeys
 for specific uses, support for kpkeys must be explicitly indicated
 by selecting ARCH_HAS_KPKEYS and defining the following functions in
 , in addition to the macros provided in
 :
>>> I don't quite understand the reason for using levels. Levels sounds like
>>> it would all be in some ordered fashion, where higher levels have access
>>> to lower levels.
>> That was originally the idea indeed, but in practice I don't expect
>> levels to have a strict ordering, as it's not practical for composing
>> features.
>>
>>> Think of that as a key that can unlock all "lower" locks, not just a
>>> single lock.
>>>
>>> Then, the question is about the ordering once we introduce new
>>> keys/locks. With two, it obviously doesn't matter :)
>>>
>>> So naturally I wonder whether levels is really the right abstraction
>>> here, and why we are not simply using "distinct" keys, like
>>>
>>> KPKEY_DEFAULT
>>> KPKEY_PGTABLE
>>> KPKEY_SUPER_SECRET1
>>> KPKEY_SUPER_SECRET2
>>>
>>> Is it because you want KPKEY_PGTABLE also be able to write to KPKEY_DEFAULT?
>> Right, and in general a given level may be able to write to any number
>> of pkeys. That's why I don't want to conflate pkeys and levels. Agreed
>> that "level" might not be the clearest term though, since there's no
>> strict ordering.
> As discussed offline, maybe the right terminology to use here would be
> something like a "context".
>
> You'd be activating/setting a context.
>
> KPKEY_CTX_DEFAULT
> KPKEY_CTX_PGTABLE
> KPKEY_CTX_SUPER_SECRET1

Sounds good to me, that's more accurate than "level" if it is possible
to give access to arbitrary pkeys to each context, which is the current
assumption.

> What is accessible (and how) is defined for each context. For example, I
> would assume that all context allow for read/write access to everything
> that KPKEY_CTX_DEFAULT has access to.

Most contexts would, although as I mentioned in the previous email,
unprivileged contexts such as eBPF programs may be further restricted.

- Kevin



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-17 Thread David Hildenbrand (Arm)
On 4/15/26 17:50, Kevin Brodsky wrote:
> On 15/04/2026 15:00, David Hildenbrand (Arm) wrote:
>> On 2/27/26 18:54, Kevin Brodsky wrote:
>>> kpkeys is a simple framework to enable the use of protection keys
>>> (pkeys) to harden the kernel itself. This patch introduces the basic
>>> API in : a couple of functions to set and restore
>>> the pkey register and macros to define guard objects.
>>>
>>> kpkeys introduces a new concept on top of pkeys: the kpkeys level.
>>> Each level is associated to a set of permissions for the pkeys
>>> managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
>>> permissions according to lvl, and returns the original pkey
>>> register, to be later restored by kpkeys_restore_pkey_reg(). To
>>> start with, only KPKEYS_LVL_DEFAULT is available, which is meant
>>> to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
>>> this is the only available pkey for now).
>>>
>>> Because each architecture implementing pkeys uses a different
>>> representation for the pkey register, and may reserve certain pkeys
>>> for specific uses, support for kpkeys must be explicitly indicated
>>> by selecting ARCH_HAS_KPKEYS and defining the following functions in
>>> , in addition to the macros provided in
>>> :
>> I don't quite understand the reason for using levels. Levels sounds like
>> it would all be in some ordered fashion, where higher levels have access
>> to lower levels.
> 
> That was originally the idea indeed, but in practice I don't expect
> levels to have a strict ordering, as it's not practical for composing
> features.
> 
>> Think of that as a key that can unlock all "lower" locks, not just a
>> single lock.
>>
>> Then, the question is about the ordering once we introduce new
>> keys/locks. With two, it obviously doesn't matter :)
>>
>> So naturally I wonder whether levels is really the right abstraction
>> here, and why we are not simply using "distinct" keys, like
>>
>> KPKEY_DEFAULT
>> KPKEY_PGTABLE
>> KPKEY_SUPER_SECRET1
>> KPKEY_SUPER_SECRET2
>>
>> Is it because you want KPKEY_PGTABLE also be able to write to KPKEY_DEFAULT?
> 
> Right, and in general a given level may be able to write to any number
> of pkeys. That's why I don't want to conflate pkeys and levels. Agreed
> that "level" might not be the clearest term though, since there's no
> strict ordering.

As discussed offline, maybe the right terminology to use here would be
something like a "context".

You'd be activating/setting a context.

KPKEY_CTX_DEFAULT
KPKEY_CTX_PGTABLE
KPKEY_CTX_SUPER_SECRET1

What is accessible (and how) is defined for each context. For example, I
would assume that all context allow for read/write access to everything
that KPKEY_CTX_DEFAULT has access to.

-- 
Cheers,

David



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-15 Thread Kevin Brodsky
On 15/04/2026 15:00, David Hildenbrand (Arm) wrote:
> On 2/27/26 18:54, Kevin Brodsky wrote:
>> kpkeys is a simple framework to enable the use of protection keys
>> (pkeys) to harden the kernel itself. This patch introduces the basic
>> API in : a couple of functions to set and restore
>> the pkey register and macros to define guard objects.
>>
>> kpkeys introduces a new concept on top of pkeys: the kpkeys level.
>> Each level is associated to a set of permissions for the pkeys
>> managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
>> permissions according to lvl, and returns the original pkey
>> register, to be later restored by kpkeys_restore_pkey_reg(). To
>> start with, only KPKEYS_LVL_DEFAULT is available, which is meant
>> to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
>> this is the only available pkey for now).
>>
>> Because each architecture implementing pkeys uses a different
>> representation for the pkey register, and may reserve certain pkeys
>> for specific uses, support for kpkeys must be explicitly indicated
>> by selecting ARCH_HAS_KPKEYS and defining the following functions in
>> , in addition to the macros provided in
>> :
> I don't quite understand the reason for using levels. Levels sounds like
> it would all be in some ordered fashion, where higher levels have access
> to lower levels.

That was originally the idea indeed, but in practice I don't expect
levels to have a strict ordering, as it's not practical for composing
features.

> Think of that as a key that can unlock all "lower" locks, not just a
> single lock.
>
> Then, the question is about the ordering once we introduce new
> keys/locks. With two, it obviously doesn't matter :)
>
> So naturally I wonder whether levels is really the right abstraction
> here, and why we are not simply using "distinct" keys, like
>
> KPKEY_DEFAULT
> KPKEY_PGTABLE
> KPKEY_SUPER_SECRET1
> KPKEY_SUPER_SECRET2
>
> Is it because you want KPKEY_PGTABLE also be able to write to KPKEY_DEFAULT?

Right, and in general a given level may be able to write to any number
of pkeys. That's why I don't want to conflate pkeys and levels. Agreed
that "level" might not be the clearest term though, since there's no
strict ordering.

> But how would you handle KPKEY_SUPER_SECRET1 and KPKEY_SUPER_SECRET2 then?

Presumably those would also have access to KPKEY_DEFAULT. However, if
you consider the reverse situation where the level is less privileged
than the default (say an eBPF program), then write access to
KPKEY_DEFAULT would not be granted.

Also worth noting on the notion of level that POE2 will bring further
per-level restrictions, besides which pkeys can be accessed. For
instance, we could prevent an unprivileged level from executing certain
instructions. This isn't in scope for this series, but this is a
consideration in the design of the kpkeys abstractions.

- Kevin



Re: [PATCH v6 01/30] mm: Introduce kpkeys

2026-04-15 Thread David Hildenbrand (Arm)
On 2/27/26 18:54, Kevin Brodsky wrote:
> kpkeys is a simple framework to enable the use of protection keys
> (pkeys) to harden the kernel itself. This patch introduces the basic
> API in : a couple of functions to set and restore
> the pkey register and macros to define guard objects.
> 
> kpkeys introduces a new concept on top of pkeys: the kpkeys level.
> Each level is associated to a set of permissions for the pkeys
> managed by the kpkeys framework. kpkeys_set_level(lvl) sets those
> permissions according to lvl, and returns the original pkey
> register, to be later restored by kpkeys_restore_pkey_reg(). To
> start with, only KPKEYS_LVL_DEFAULT is available, which is meant
> to grant RW access to KPKEYS_PKEY_DEFAULT (i.e. all memory since
> this is the only available pkey for now).
> 
> Because each architecture implementing pkeys uses a different
> representation for the pkey register, and may reserve certain pkeys
> for specific uses, support for kpkeys must be explicitly indicated
> by selecting ARCH_HAS_KPKEYS and defining the following functions in
> , in addition to the macros provided in
> :

I don't quite understand the reason for using levels. Levels sounds like
it would all be in some ordered fashion, where higher levels have access
to lower levels.

Think of that as a key that can unlock all "lower" locks, not just a
single lock.

Then, the question is about the ordering once we introduce new
keys/locks. With two, it obviously doesn't matter :)

So naturally I wonder whether levels is really the right abstraction
here, and why we are not simply using "distinct" keys, like

KPKEY_DEFAULT
KPKEY_PGTABLE
KPKEY_SUPER_SECRET1
KPKEY_SUPER_SECRET2

Is it because you want KPKEY_PGTABLE also be able to write to KPKEY_DEFAULT?

But how would you handle KPKEY_SUPER_SECRET1 and KPKEY_SUPER_SECRET2 then?

-- 
Cheers,

David