Skip to content

Commit 7a3fad3

Browse files
committed
Merge tag 'random-6.11-rc1-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random
Pull random number generator updates from Jason Donenfeld: "This adds getrandom() support to the vDSO. First, it adds a new kind of mapping to mmap(2), MAP_DROPPABLE, which lets the kernel zero out pages anytime under memory pressure, which enables allocating memory that never gets swapped to disk but also doesn't count as being mlocked. Then, the vDSO implementation of getrandom() is introduced in a generic manner and hooked into random.c. Next, this is implemented on x86. (Also, though it's not ready for this pull, somebody has begun an arm64 implementation already) Finally, two vDSO selftests are added. There are also two housekeeping cleanup commits" * tag 'random-6.11-rc1-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/crng/random: MAINTAINERS: add random.h headers to RNG subsection random: note that RNDGETPOOL was removed in 2.6.9-rc2 selftests/vDSO: add tests for vgetrandom x86: vdso: Wire up getrandom() vDSO implementation random: introduce generic vDSO getrandom() implementation mm: add MAP_DROPPABLE for designating always lazily freeable mappings
2 parents d1e9a63 + ad8070c commit 7a3fad3

37 files changed

+1121
-18
lines changed

MAINTAINERS

+6
Original file line numberDiff line numberDiff line change
@@ -19057,7 +19057,13 @@ S: Maintained
1905719057
T: git https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git
1905819058
F: Documentation/devicetree/bindings/rng/microsoft,vmgenid.yaml
1905919059
F: drivers/char/random.c
19060+
F: include/linux/random.h
19061+
F: include/uapi/linux/random.h
1906019062
F: drivers/virt/vmgenid.c
19063+
F: include/vdso/getrandom.h
19064+
F: lib/vdso/getrandom.c
19065+
F: arch/x86/entry/vdso/vgetrandom*
19066+
F: arch/x86/include/asm/vdso/getrandom*
1906119067

1906219068
RAPIDIO SUBSYSTEM
1906319069
M: Matt Porter <[email protected]>

arch/x86/Kconfig

+1
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ config X86
287287
select HAVE_UNSTABLE_SCHED_CLOCK
288288
select HAVE_USER_RETURN_NOTIFIER
289289
select HAVE_GENERIC_VDSO
290+
select VDSO_GETRANDOM if X86_64
290291
select HOTPLUG_PARALLEL if SMP && X86_64
291292
select HOTPLUG_SMT if SMP
292293
select HOTPLUG_SPLIT_STARTUP if SMP && X86_32

arch/x86/entry/vdso/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
include $(srctree)/lib/vdso/Makefile
88

99
# Files to link into the vDSO:
10-
vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
10+
vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vgetrandom.o vgetrandom-chacha.o
1111
vobjs32-y := vdso32/note.o vdso32/system_call.o vdso32/sigreturn.o
1212
vobjs32-y += vdso32/vclock_gettime.o vdso32/vgetcpu.o
1313
vobjs-$(CONFIG_X86_SGX) += vsgx.o
@@ -73,6 +73,7 @@ CFLAGS_REMOVE_vdso32/vclock_gettime.o = -pg
7373
CFLAGS_REMOVE_vgetcpu.o = -pg
7474
CFLAGS_REMOVE_vdso32/vgetcpu.o = -pg
7575
CFLAGS_REMOVE_vsgx.o = -pg
76+
CFLAGS_REMOVE_vgetrandom.o = -pg
7677

7778
#
7879
# X32 processes use x32 vDSO to access 64bit kernel data.

arch/x86/entry/vdso/vdso.lds.S

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ VERSION {
3030
#ifdef CONFIG_X86_SGX
3131
__vdso_sgx_enter_enclave;
3232
#endif
33+
getrandom;
34+
__vdso_getrandom;
3335
local: *;
3436
};
3537
}
+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2022-2024 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
4+
*/
5+
6+
#include <linux/linkage.h>
7+
#include <asm/frame.h>
8+
9+
.section .rodata, "a"
10+
.align 16
11+
CONSTANTS: .octa 0x6b20657479622d323320646e61707865
12+
.text
13+
14+
/*
15+
* Very basic SSE2 implementation of ChaCha20. Produces a given positive number
16+
* of blocks of output with a nonce of 0, taking an input key and 8-byte
17+
* counter. Importantly does not spill to the stack. Its arguments are:
18+
*
19+
* rdi: output bytes
20+
* rsi: 32-byte key input
21+
* rdx: 8-byte counter input/output
22+
* rcx: number of 64-byte blocks to write to output
23+
*/
24+
SYM_FUNC_START(__arch_chacha20_blocks_nostack)
25+
26+
.set output, %rdi
27+
.set key, %rsi
28+
.set counter, %rdx
29+
.set nblocks, %rcx
30+
.set i, %al
31+
/* xmm registers are *not* callee-save. */
32+
.set temp, %xmm0
33+
.set state0, %xmm1
34+
.set state1, %xmm2
35+
.set state2, %xmm3
36+
.set state3, %xmm4
37+
.set copy0, %xmm5
38+
.set copy1, %xmm6
39+
.set copy2, %xmm7
40+
.set copy3, %xmm8
41+
.set one, %xmm9
42+
43+
/* copy0 = "expand 32-byte k" */
44+
movaps CONSTANTS(%rip),copy0
45+
/* copy1,copy2 = key */
46+
movups 0x00(key),copy1
47+
movups 0x10(key),copy2
48+
/* copy3 = counter || zero nonce */
49+
movq 0x00(counter),copy3
50+
/* one = 1 || 0 */
51+
movq $1,%rax
52+
movq %rax,one
53+
54+
.Lblock:
55+
/* state0,state1,state2,state3 = copy0,copy1,copy2,copy3 */
56+
movdqa copy0,state0
57+
movdqa copy1,state1
58+
movdqa copy2,state2
59+
movdqa copy3,state3
60+
61+
movb $10,i
62+
.Lpermute:
63+
/* state0 += state1, state3 = rotl32(state3 ^ state0, 16) */
64+
paddd state1,state0
65+
pxor state0,state3
66+
movdqa state3,temp
67+
pslld $16,temp
68+
psrld $16,state3
69+
por temp,state3
70+
71+
/* state2 += state3, state1 = rotl32(state1 ^ state2, 12) */
72+
paddd state3,state2
73+
pxor state2,state1
74+
movdqa state1,temp
75+
pslld $12,temp
76+
psrld $20,state1
77+
por temp,state1
78+
79+
/* state0 += state1, state3 = rotl32(state3 ^ state0, 8) */
80+
paddd state1,state0
81+
pxor state0,state3
82+
movdqa state3,temp
83+
pslld $8,temp
84+
psrld $24,state3
85+
por temp,state3
86+
87+
/* state2 += state3, state1 = rotl32(state1 ^ state2, 7) */
88+
paddd state3,state2
89+
pxor state2,state1
90+
movdqa state1,temp
91+
pslld $7,temp
92+
psrld $25,state1
93+
por temp,state1
94+
95+
/* state1[0,1,2,3] = state1[1,2,3,0] */
96+
pshufd $0x39,state1,state1
97+
/* state2[0,1,2,3] = state2[2,3,0,1] */
98+
pshufd $0x4e,state2,state2
99+
/* state3[0,1,2,3] = state3[3,0,1,2] */
100+
pshufd $0x93,state3,state3
101+
102+
/* state0 += state1, state3 = rotl32(state3 ^ state0, 16) */
103+
paddd state1,state0
104+
pxor state0,state3
105+
movdqa state3,temp
106+
pslld $16,temp
107+
psrld $16,state3
108+
por temp,state3
109+
110+
/* state2 += state3, state1 = rotl32(state1 ^ state2, 12) */
111+
paddd state3,state2
112+
pxor state2,state1
113+
movdqa state1,temp
114+
pslld $12,temp
115+
psrld $20,state1
116+
por temp,state1
117+
118+
/* state0 += state1, state3 = rotl32(state3 ^ state0, 8) */
119+
paddd state1,state0
120+
pxor state0,state3
121+
movdqa state3,temp
122+
pslld $8,temp
123+
psrld $24,state3
124+
por temp,state3
125+
126+
/* state2 += state3, state1 = rotl32(state1 ^ state2, 7) */
127+
paddd state3,state2
128+
pxor state2,state1
129+
movdqa state1,temp
130+
pslld $7,temp
131+
psrld $25,state1
132+
por temp,state1
133+
134+
/* state1[0,1,2,3] = state1[3,0,1,2] */
135+
pshufd $0x93,state1,state1
136+
/* state2[0,1,2,3] = state2[2,3,0,1] */
137+
pshufd $0x4e,state2,state2
138+
/* state3[0,1,2,3] = state3[1,2,3,0] */
139+
pshufd $0x39,state3,state3
140+
141+
decb i
142+
jnz .Lpermute
143+
144+
/* output0 = state0 + copy0 */
145+
paddd copy0,state0
146+
movups state0,0x00(output)
147+
/* output1 = state1 + copy1 */
148+
paddd copy1,state1
149+
movups state1,0x10(output)
150+
/* output2 = state2 + copy2 */
151+
paddd copy2,state2
152+
movups state2,0x20(output)
153+
/* output3 = state3 + copy3 */
154+
paddd copy3,state3
155+
movups state3,0x30(output)
156+
157+
/* ++copy3.counter */
158+
paddq one,copy3
159+
160+
/* output += 64, --nblocks */
161+
addq $64,output
162+
decq nblocks
163+
jnz .Lblock
164+
165+
/* counter = copy3.counter */
166+
movq copy3,0x00(counter)
167+
168+
/* Zero out the potentially sensitive regs, in case nothing uses these again. */
169+
pxor state0,state0
170+
pxor state1,state1
171+
pxor state2,state2
172+
pxor state3,state3
173+
pxor copy1,copy1
174+
pxor copy2,copy2
175+
pxor temp,temp
176+
177+
ret
178+
SYM_FUNC_END(__arch_chacha20_blocks_nostack)

arch/x86/entry/vdso/vgetrandom.c

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2022-2024 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
4+
*/
5+
#include <linux/types.h>
6+
7+
#include "../../../../lib/vdso/getrandom.c"
8+
9+
ssize_t __vdso_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len);
10+
11+
ssize_t __vdso_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len)
12+
{
13+
return __cvdso_getrandom(buffer, len, flags, opaque_state, opaque_len);
14+
}
15+
16+
ssize_t getrandom(void *, size_t, unsigned int, void *, size_t)
17+
__attribute__((weak, alias("__vdso_getrandom")));

arch/x86/include/asm/vdso/getrandom.h

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* Copyright (C) 2022-2024 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
4+
*/
5+
#ifndef __ASM_VDSO_GETRANDOM_H
6+
#define __ASM_VDSO_GETRANDOM_H
7+
8+
#ifndef __ASSEMBLY__
9+
10+
#include <asm/unistd.h>
11+
#include <asm/vvar.h>
12+
13+
/**
14+
* getrandom_syscall - Invoke the getrandom() syscall.
15+
* @buffer: Destination buffer to fill with random bytes.
16+
* @len: Size of @buffer in bytes.
17+
* @flags: Zero or more GRND_* flags.
18+
* Returns: The number of random bytes written to @buffer, or a negative value indicating an error.
19+
*/
20+
static __always_inline ssize_t getrandom_syscall(void *buffer, size_t len, unsigned int flags)
21+
{
22+
long ret;
23+
24+
asm ("syscall" : "=a" (ret) :
25+
"0" (__NR_getrandom), "D" (buffer), "S" (len), "d" (flags) :
26+
"rcx", "r11", "memory");
27+
28+
return ret;
29+
}
30+
31+
#define __vdso_rng_data (VVAR(_vdso_rng_data))
32+
33+
static __always_inline const struct vdso_rng_data *__arch_get_vdso_rng_data(void)
34+
{
35+
if (IS_ENABLED(CONFIG_TIME_NS) && __vdso_data->clock_mode == VDSO_CLOCKMODE_TIMENS)
36+
return (void *)&__vdso_rng_data + ((void *)&__timens_vdso_data - (void *)&__vdso_data);
37+
return &__vdso_rng_data;
38+
}
39+
40+
/**
41+
* __arch_chacha20_blocks_nostack - Generate ChaCha20 stream without using the stack.
42+
* @dst_bytes: Destination buffer to hold @nblocks * 64 bytes of output.
43+
* @key: 32-byte input key.
44+
* @counter: 8-byte counter, read on input and updated on return.
45+
* @nblocks: Number of blocks to generate.
46+
*
47+
* Generates a given positive number of blocks of ChaCha20 output with nonce=0, and does not write
48+
* to any stack or memory outside of the parameters passed to it, in order to mitigate stack data
49+
* leaking into forked child processes.
50+
*/
51+
extern void __arch_chacha20_blocks_nostack(u8 *dst_bytes, const u32 *key, u32 *counter, size_t nblocks);
52+
53+
#endif /* !__ASSEMBLY__ */
54+
55+
#endif /* __ASM_VDSO_GETRANDOM_H */

arch/x86/include/asm/vdso/vsyscall.h

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <asm/vvar.h>
1111

1212
DEFINE_VVAR(struct vdso_data, _vdso_data);
13+
DEFINE_VVAR_SINGLE(struct vdso_rng_data, _vdso_rng_data);
14+
1315
/*
1416
* Update the vDSO data page to keep in sync with kernel timekeeping.
1517
*/

arch/x86/include/asm/vvar.h

+16
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
*/
2727
#define DECLARE_VVAR(offset, type, name) \
2828
EMIT_VVAR(name, offset)
29+
#define DECLARE_VVAR_SINGLE(offset, type, name) \
30+
EMIT_VVAR(name, offset)
2931

3032
#else
3133

@@ -37,19 +39,33 @@ extern char __vvar_page;
3739
extern type timens_ ## name[CS_BASES] \
3840
__attribute__((visibility("hidden"))); \
3941

42+
#define DECLARE_VVAR_SINGLE(offset, type, name) \
43+
extern type vvar_ ## name \
44+
__attribute__((visibility("hidden"))); \
45+
4046
#define VVAR(name) (vvar_ ## name)
4147
#define TIMENS(name) (timens_ ## name)
4248

4349
#define DEFINE_VVAR(type, name) \
4450
type name[CS_BASES] \
4551
__attribute__((section(".vvar_" #name), aligned(16))) __visible
4652

53+
#define DEFINE_VVAR_SINGLE(type, name) \
54+
type name \
55+
__attribute__((section(".vvar_" #name), aligned(16))) __visible
56+
4757
#endif
4858

4959
/* DECLARE_VVAR(offset, type, name) */
5060

5161
DECLARE_VVAR(128, struct vdso_data, _vdso_data)
5262

63+
#if !defined(_SINGLE_DATA)
64+
#define _SINGLE_DATA
65+
DECLARE_VVAR_SINGLE(640, struct vdso_rng_data, _vdso_rng_data)
66+
#endif
67+
5368
#undef DECLARE_VVAR
69+
#undef DECLARE_VVAR_SINGLE
5470

5571
#endif

drivers/char/random.c

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
22
/*
3-
* Copyright (C) 2017-2022 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
3+
* Copyright (C) 2017-2024 Jason A. Donenfeld <[email protected]>. All Rights Reserved.
44
* Copyright Matt Mackall <[email protected]>, 2003, 2004, 2005
55
* Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All rights reserved.
66
*
@@ -56,6 +56,10 @@
5656
#include <linux/sched/isolation.h>
5757
#include <crypto/chacha.h>
5858
#include <crypto/blake2s.h>
59+
#ifdef CONFIG_VDSO_GETRANDOM
60+
#include <vdso/getrandom.h>
61+
#include <vdso/datapage.h>
62+
#endif
5963
#include <asm/archrandom.h>
6064
#include <asm/processor.h>
6165
#include <asm/irq.h>
@@ -271,6 +275,15 @@ static void crng_reseed(struct work_struct *work)
271275
if (next_gen == ULONG_MAX)
272276
++next_gen;
273277
WRITE_ONCE(base_crng.generation, next_gen);
278+
#ifdef CONFIG_VDSO_GETRANDOM
279+
/* base_crng.generation's invalid value is ULONG_MAX, while
280+
* _vdso_rng_data.generation's invalid value is 0, so add one to the
281+
* former to arrive at the latter. Use smp_store_release so that this
282+
* is ordered with the write above to base_crng.generation. Pairs with
283+
* the smp_rmb() before the syscall in the vDSO code.
284+
*/
285+
smp_store_release(&_vdso_rng_data.generation, next_gen + 1);
286+
#endif
274287
if (!static_branch_likely(&crng_is_ready))
275288
crng_init = CRNG_READY;
276289
spin_unlock_irqrestore(&base_crng.lock, flags);
@@ -721,6 +734,9 @@ static void __cold _credit_init_bits(size_t bits)
721734
if (static_key_initialized && system_unbound_wq)
722735
queue_work(system_unbound_wq, &set_ready);
723736
atomic_notifier_call_chain(&random_ready_notifier, 0, NULL);
737+
#ifdef CONFIG_VDSO_GETRANDOM
738+
WRITE_ONCE(_vdso_rng_data.is_ready, true);
739+
#endif
724740
wake_up_interruptible(&crng_init_wait);
725741
kill_fasync(&fasync, SIGIO, POLL_IN);
726742
pr_notice("crng init done\n");

0 commit comments

Comments
 (0)