xref: /freebsd/tools/test/stress2/misc/getrandom2.sh (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2020 Peter Holm
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30# getrandom(2) DoS scenario.
31
32# panic: pmap_growkernel: no memory to grow kernel
33# cpuid = 8
34# time = 1582102582
35# KDB: stack backtrace:
36# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe03e6992450
37# vpanic() at vpanic+0x185/frame 0xfffffe03e69924b0
38# panic() at panic+0x43/frame 0xfffffe03e6992510
39# pmap_growkernel() at pmap_growkernel+0x2d4/frame 0xfffffe03e6992550
40# vm_map_insert() at vm_map_insert+0x296/frame 0xfffffe03e69925f0
41# vm_map_find() at vm_map_find+0x617/frame 0xfffffe03e69926d0
42# kva_import() at kva_import+0x3c/frame 0xfffffe03e6992710
43# vmem_try_fetch() at vmem_try_fetch+0xde/frame 0xfffffe03e6992760
44# vmem_xalloc() at vmem_xalloc+0x4bb/frame 0xfffffe03e69927e0
45# kva_import_domain() at kva_import_domain+0x36/frame 0xfffffe03e6992810
46# vmem_try_fetch() at vmem_try_fetch+0xde/frame 0xfffffe03e6992860
47# vmem_xalloc() at vmem_xalloc+0x4bb/frame 0xfffffe03e69928e0
48# vmem_alloc() at vmem_alloc+0x8a/frame 0xfffffe03e6992930
49# kmem_malloc_domainset() at kmem_malloc_domainset+0x92/frame 0xfffffe03e69929a0
50# malloc() at malloc+0x162/frame 0xfffffe03e69929f0
51# read_random_uio() at read_random_uio+0xa5/frame 0xfffffe03e6992a40
52# sys_getrandom() at sys_getrandom+0x7b/frame 0xfffffe03e6992ac0
53# amd64_syscall() at amd64_syscall+0x183/frame 0xfffffe03e6992bf0
54# fast_syscall_common() at fast_syscall_common+0x101/frame 0xfffffe03e6992bf0
55# --- syscall (563, FreeBSD ELF64, sys_getrandom), rip = 0x80041899a, rsp = 0x7ffffffc3cb8, rbp = 0x7ffffffc3cd0 ---
56# KDB: enter: panic
57# [ thread pid 12095 tid 186584 ]
58# Stopped at      kdb_enter+0x37: movq    $0,0x1084916(%rip)
59# db> x/s version
60# version:        FreeBSD 13.0-CURRENT #0 r358094: Wed Feb 19 06:25:16 CET 2020\012    pho@t2.osted.lan:/usr/src/sys/amd64/compile/PHO\012
61# db>
62
63. ../default.cfg
64
65dir=/tmp
66odir=`pwd`
67cd $dir
68sed '1,/^EOF/d' < $odir/$0 > $dir/getrandom2.c
69mycc -o getrandom2 -Wall -Wextra -O0 -g getrandom2.c || exit 1
70rm -f getrandom2.c
71cd $odir
72
73cd /tmp
74$dir/getrandom2
75s=$?
76[ -f getrandom2.core -a $s -eq 0 ] &&
77    { ls -l getrandom2.core; s=1; }
78cd $odir
79
80rm -rf $dir/getrandom2
81exit $s
82
83EOF
84#include <sys/param.h>
85#include <sys/mman.h>
86#include <sys/random.h>
87#include <sys/resource.h>
88#include <sys/stat.h>
89#include <sys/sysctl.h>
90#include <sys/wait.h>
91
92#include <err.h>
93#include <errno.h>
94#include <fcntl.h>
95#include <stdatomic.h>
96#include <stdio.h>
97#include <stdlib.h>
98#include <time.h>
99#include <unistd.h>
100
101static size_t mx;
102static _Atomic(int) *share;
103static int parallel;
104static char *bp;
105
106#define PARALLEL 40000   /* Arbitrary cap */
107#define SYNC 0
108
109static void
110test(void)
111{
112	int i;
113
114	alarm(180);
115	(void)atomic_fetch_add(&share[SYNC], 1);
116	while (atomic_load(&share[SYNC]) != parallel)
117		usleep(200000);
118	for (i = 0; i < 10; i++)
119		getrandom(bp, mx, 0);
120//		close(66);
121
122	_exit(0);
123}
124
125int
126main(void)
127{
128	pid_t *pids;
129	struct rlimit rlp;
130	size_t len;
131        size_t f, vsz;
132        u_int pages;
133	int e, i, status;
134
135	e = 0;
136	len = PAGE_SIZE;
137	if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
138	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
139		err(1, "mmap");
140
141	if (getrlimit(RLIMIT_NPROC, &rlp) < 0)
142		err(1, "getrlimit");
143	parallel = rlp.rlim_cur / 100 * 80;
144	if (parallel > PARALLEL)
145		parallel = PARALLEL;
146	pids = calloc(parallel, sizeof(pid_t));
147
148        vsz = sizeof(pages);
149        if (sysctlbyname("vm.stats.vm.v_free_count", &pages, &vsz, NULL, 0) != 0)
150                err(1, "sysctl(vm.stats.vm.v_free_count)");
151	f = pages;
152	f *= PAGE_SIZE;
153
154	if (getrlimit(RLIMIT_DATA, &rlp) < 0)
155		err(1,"getrlimit");
156	mx = rlp.rlim_cur;
157	if (mx > f / parallel)
158		mx = f / parallel;
159	if ((bp = mmap(NULL, mx, PROT_READ | PROT_WRITE, MAP_ANON, -1,
160	    0)) == MAP_FAILED)
161		err(1, "mmap");
162	for (;;) {
163		if (getrandom(bp, mx, 0) != -1)
164			break;
165		mx = mx / 2;
166	}
167	printf("Max getrandom() buffer size is %zu, %d threads\n", mx,
168	    parallel);
169	for (i = 0; i < parallel; i++) {
170		if ((pids[i] = fork()) == 0)
171			test();
172		if (pids[i] == -1)
173			err(1, "fork()");
174	}
175	for (i = 0; i < parallel; i++) {
176		if (waitpid(pids[i], &status, 0) == -1)
177			err(1, "waitpid(%d)", pids[i]);
178		if (status != 0) {
179			if (WIFSIGNALED(status))
180				fprintf(stderr,
181				    "pid %d exit signal %d\n",
182				    pids[i], WTERMSIG(status));
183		}
184		e += status == 0 ? 0 : 1;
185	}
186
187	return (e);
188}
189