On 16/12/2025 08:30, Ard Biesheuvel wrote:
> On Tue, 16 Dec 2025 at 09:27, Kees Cook <[email protected]> wrote:
>>
>> On Mon, Dec 15, 2025 at 04:35:17PM +0000, Ryan Roberts wrote:
>>> [...]
>>> @@ -45,9 +46,22 @@
>>> DECLARE_STATIC_KEY_MAYBE(CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT,
>>> #define KSTACK_OFFSET_MAX(x) ((x) & 0b1111111100)
>>> #endif
>>>
>>> +DECLARE_PER_CPU(struct rnd_state, kstack_rnd_state);
>>> +
>>> +static __always_inline u32 get_kstack_offset(void)
>>> +{
>>> + struct rnd_state *state;
>>> + u32 rnd;
>>> +
>>> + state = &get_cpu_var(kstack_rnd_state);
>>> + rnd = prandom_u32_state(state);
>>> + put_cpu_var(kstack_rnd_state);
>>> +
>>> + return rnd;
>>> +}
>>> [...]
>>> -static inline void random_kstack_task_init(struct task_struct *tsk)
>>> +static int random_kstack_init(void)
>>> {
>>> - tsk->kstack_offset = 0;
>>> + prandom_seed_full_state(&kstack_rnd_state);
>>> + return 0;
>>> }
>>> +
>>> +late_initcall(random_kstack_init);
>>
>> Doesn't this need to be run for every CPU? (And how does hotplug work
>> for such things?) And doesn't it need a get_cpu_var?
>>
>
>
> prandom_seed_full_state() takes a 'struct rnd_state __percpu
> *pcpu_state', and performs the initialization for all possible CPUs.
Yes, indeed, prandom_seed_full_state() is initializing all possible CPUs so it
doesn't matter if it gets migrated. I believe this is correct as is.
void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state)
{
int i;
for_each_possible_cpu(i) {
struct rnd_state *state = per_cpu_ptr(pcpu_state, i);
u32 seeds[4];
get_random_bytes(&seeds, sizeof(seeds));
state->s1 = __seed(seeds[0], 2U);
state->s2 = __seed(seeds[1], 8U);
state->s3 = __seed(seeds[2], 16U);
state->s4 = __seed(seeds[3], 128U);
prandom_warmup(state);
}
}