1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2017 Pavel Boldin <pboldin@cloudlinux.com>
4f08c3bdfSopenharmony_ci * Copyright (c) 2023 Rick Edgecombe <rick.p.edgecombe@intel.com>
5f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2017-2023
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci/*\
9f08c3bdfSopenharmony_ci * [Description]
10f08c3bdfSopenharmony_ci *
11f08c3bdfSopenharmony_ci * This is a regression test of the Stack Clash [1] vulnerability. This tests
12f08c3bdfSopenharmony_ci * that there is at least 256 PAGE_SIZE of stack guard gap which is considered
13f08c3bdfSopenharmony_ci * hard to hop above. Code adapted from the Novell's bugzilla [2].
14f08c3bdfSopenharmony_ci *
15f08c3bdfSopenharmony_ci * The code `mmap(2)`s region close to the stack end. The code then allocates
16f08c3bdfSopenharmony_ci * memory on stack until it hits guard page and SIGSEGV or SIGBUS is generated
17f08c3bdfSopenharmony_ci * by the kernel. The signal handler checks that fault address is further than
18f08c3bdfSopenharmony_ci * THRESHOLD from the mmapped area.
19f08c3bdfSopenharmony_ci *
20f08c3bdfSopenharmony_ci * We read /proc/self/maps to examine exact top of the stack and `mmap(2)`
21f08c3bdfSopenharmony_ci * our region exactly GAP_PAGES * PAGE_SIZE away. We read /proc/cmdline to
22f08c3bdfSopenharmony_ci * see if a different stack_guard_gap size is configured. We set stack limit
23f08c3bdfSopenharmony_ci * to infinity and preallocate REQ_STACK_SIZE bytes of stack so that no calls
24f08c3bdfSopenharmony_ci * after `mmap` are moving stack further.
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci * If the architecture meets certain requirements (only x86_64 is verified)
27f08c3bdfSopenharmony_ci * then the test also tests that new mmap()s can't be placed in the stack's
28f08c3bdfSopenharmony_ci * guard gap. This part of the test works by forcing a bottom up search. The
29f08c3bdfSopenharmony_ci * assumptions are that the stack grows down (start gap) and either:
30f08c3bdfSopenharmony_ci *
31f08c3bdfSopenharmony_ci * 1. The default search is top down, and will switch to bottom up if
32f08c3bdfSopenharmony_ci *      space is exhausted.
33f08c3bdfSopenharmony_ci * 2. The default search is bottom up and the stack is above mmap base.
34f08c3bdfSopenharmony_ci *
35f08c3bdfSopenharmony_ci * [1] https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash
36f08c3bdfSopenharmony_ci * [2] https://bugzilla.novell.com/show_bug.cgi?id=CVE-2017-1000364
37f08c3bdfSopenharmony_ci */
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_ci#include <sys/wait.h>
40f08c3bdfSopenharmony_ci#include <stdio.h>
41f08c3bdfSopenharmony_ci#include <unistd.h>
42f08c3bdfSopenharmony_ci#include <alloca.h>
43f08c3bdfSopenharmony_ci#include <signal.h>
44f08c3bdfSopenharmony_ci#include <stdlib.h>
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_ci#include "tst_test.h"
47f08c3bdfSopenharmony_ci#include "tst_safe_stdio.h"
48f08c3bdfSopenharmony_ci#include "lapi/mmap.h"
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_cistatic unsigned long page_size;
51f08c3bdfSopenharmony_cistatic unsigned long page_mask;
52f08c3bdfSopenharmony_cistatic unsigned long GAP_PAGES = 256;
53f08c3bdfSopenharmony_cistatic unsigned long THRESHOLD;
54f08c3bdfSopenharmony_cistatic int STACK_GROWSDOWN;
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci#define SIGNAL_STACK_SIZE	(1UL<<20)
57f08c3bdfSopenharmony_ci#define FRAME_SIZE		1024
58f08c3bdfSopenharmony_ci#define REQ_STACK_SIZE		(1024 * 1024)
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci#define EXIT_TESTBROKE		TBROK
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_civoid exhaust_stack_into_sigsegv(void)
63f08c3bdfSopenharmony_ci{
64f08c3bdfSopenharmony_ci	volatile char * ptr = alloca(FRAME_SIZE - sizeof(long));
65f08c3bdfSopenharmony_ci	*ptr = '\0';
66f08c3bdfSopenharmony_ci	exhaust_stack_into_sigsegv();
67f08c3bdfSopenharmony_ci}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci#define MAPPED_LEN page_size
70f08c3bdfSopenharmony_cistatic unsigned long mapped_addr;
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_civoid segv_handler(int sig, siginfo_t *info, void *data LTP_ATTRIBUTE_UNUSED)
73f08c3bdfSopenharmony_ci{
74f08c3bdfSopenharmony_ci	unsigned long fault_addr = (unsigned long)info->si_addr;
75f08c3bdfSopenharmony_ci	unsigned long mmap_end = mapped_addr + MAPPED_LEN;
76f08c3bdfSopenharmony_ci	ssize_t diff;
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci	if (sig != SIGSEGV && sig != SIGBUS)
79f08c3bdfSopenharmony_ci		return;
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	if (STACK_GROWSDOWN)
82f08c3bdfSopenharmony_ci		diff = fault_addr - mmap_end;
83f08c3bdfSopenharmony_ci	else
84f08c3bdfSopenharmony_ci		diff = mapped_addr - fault_addr;
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	tst_res(TINFO,
87f08c3bdfSopenharmony_ci		"mmap = [%lx, %lx), addr = %lx, diff = %zx, THRESHOLD = %lx",
88f08c3bdfSopenharmony_ci		mapped_addr, mmap_end, fault_addr, diff, THRESHOLD);
89f08c3bdfSopenharmony_ci	if (diff < 0 || (unsigned long)diff < THRESHOLD)
90f08c3bdfSopenharmony_ci		_exit(EXIT_FAILURE);
91f08c3bdfSopenharmony_ci	else
92f08c3bdfSopenharmony_ci		_exit(EXIT_SUCCESS);
93f08c3bdfSopenharmony_ci}
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_cistatic void force_bottom_up(void)
96f08c3bdfSopenharmony_ci{
97f08c3bdfSopenharmony_ci	FILE *fh;
98f08c3bdfSopenharmony_ci	char buf[1024];
99f08c3bdfSopenharmony_ci	unsigned long start, end, size, lastend = 0;
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	/* start filling from mmap_min_addr */
102f08c3bdfSopenharmony_ci	SAFE_FILE_SCANF("/proc/sys/vm/mmap_min_addr", "%lu", &lastend);
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	fh = SAFE_FOPEN("/proc/self/maps", "r");
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci	while (!feof(fh)) {
107f08c3bdfSopenharmony_ci		if (fgets(buf, sizeof(buf), fh) == NULL)
108f08c3bdfSopenharmony_ci			goto out;
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci		if (sscanf(buf, "%lx-%lx", &start, &end) != 2) {
111f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "sscanf");
112f08c3bdfSopenharmony_ci			goto out;
113f08c3bdfSopenharmony_ci		}
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_ci		size = start - lastend;
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci		/* Skip the PROT_NONE that was just added (!size). */
118f08c3bdfSopenharmony_ci		if (!size) {
119f08c3bdfSopenharmony_ci			lastend = end;
120f08c3bdfSopenharmony_ci			continue;
121f08c3bdfSopenharmony_ci		}
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_ci		/* If the next area is the stack, quit. */
124f08c3bdfSopenharmony_ci		if (!!strstr(buf, "[stack]"))
125f08c3bdfSopenharmony_ci			break;
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci		/* This is not cleaned up. */
128f08c3bdfSopenharmony_ci		SAFE_MMAP((void *)lastend, size, PROT_NONE,
129f08c3bdfSopenharmony_ci			  MAP_ANON|MAP_PRIVATE|MAP_FIXED_NOREPLACE, -1, 0);
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ci		lastend = end;
132f08c3bdfSopenharmony_ci	}
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_ciout:
135f08c3bdfSopenharmony_ci	SAFE_FCLOSE(fh);
136f08c3bdfSopenharmony_ci}
137f08c3bdfSopenharmony_ci
138f08c3bdfSopenharmony_ciunsigned long read_stack_addr_from_proc(unsigned long *stack_size)
139f08c3bdfSopenharmony_ci{
140f08c3bdfSopenharmony_ci	FILE *fh;
141f08c3bdfSopenharmony_ci	char buf[1024];
142f08c3bdfSopenharmony_ci	unsigned long stack_top = -1UL, start, end;
143f08c3bdfSopenharmony_ci
144f08c3bdfSopenharmony_ci	fh = SAFE_FOPEN("/proc/self/maps", "r");
145f08c3bdfSopenharmony_ci
146f08c3bdfSopenharmony_ci	while (!feof(fh)) {
147f08c3bdfSopenharmony_ci		if (fgets(buf, sizeof(buf), fh) == NULL) {
148f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "fgets");
149f08c3bdfSopenharmony_ci			goto out;
150f08c3bdfSopenharmony_ci		}
151f08c3bdfSopenharmony_ci
152f08c3bdfSopenharmony_ci		if (!strstr(buf, "[stack"))
153f08c3bdfSopenharmony_ci			continue;
154f08c3bdfSopenharmony_ci
155f08c3bdfSopenharmony_ci		if (sscanf(buf, "%lx-%lx", &start, &end) != 2) {
156f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "sscanf");
157f08c3bdfSopenharmony_ci			goto out;
158f08c3bdfSopenharmony_ci		}
159f08c3bdfSopenharmony_ci
160f08c3bdfSopenharmony_ci		*stack_size = end - start;
161f08c3bdfSopenharmony_ci
162f08c3bdfSopenharmony_ci		if (STACK_GROWSDOWN)
163f08c3bdfSopenharmony_ci			stack_top = start;
164f08c3bdfSopenharmony_ci		else
165f08c3bdfSopenharmony_ci			stack_top = end;
166f08c3bdfSopenharmony_ci		break;
167f08c3bdfSopenharmony_ci	}
168f08c3bdfSopenharmony_ci
169f08c3bdfSopenharmony_ciout:
170f08c3bdfSopenharmony_ci	SAFE_FCLOSE(fh);
171f08c3bdfSopenharmony_ci	return stack_top;
172f08c3bdfSopenharmony_ci}
173f08c3bdfSopenharmony_ci
174f08c3bdfSopenharmony_civoid dump_proc_self_maps(void)
175f08c3bdfSopenharmony_ci{
176f08c3bdfSopenharmony_ci	static char buf[64];
177f08c3bdfSopenharmony_ci	static const char *cmd[] = {"cat", buf, NULL};
178f08c3bdfSopenharmony_ci	sprintf(buf, "/proc/%d/maps", getpid());
179f08c3bdfSopenharmony_ci	tst_cmd(cmd, NULL, NULL, 0);
180f08c3bdfSopenharmony_ci}
181f08c3bdfSopenharmony_ci
182f08c3bdfSopenharmony_civoid __attribute__((noinline)) preallocate_stack(unsigned long required)
183f08c3bdfSopenharmony_ci{
184f08c3bdfSopenharmony_ci	volatile char *garbage;
185f08c3bdfSopenharmony_ci
186f08c3bdfSopenharmony_ci	garbage = alloca(required);
187f08c3bdfSopenharmony_ci	garbage[0] = garbage[required - 1] = '\0';
188f08c3bdfSopenharmony_ci}
189f08c3bdfSopenharmony_ci
190f08c3bdfSopenharmony_cistatic void do_mmap_placement_test(unsigned long stack_addr, unsigned long gap)
191f08c3bdfSopenharmony_ci{
192f08c3bdfSopenharmony_ci	void *map_test_gap;
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_ci	force_bottom_up();
195f08c3bdfSopenharmony_ci
196f08c3bdfSopenharmony_ci	/*
197f08c3bdfSopenharmony_ci	 * force_bottom_up() used up all the spaces below the stack. The search down
198f08c3bdfSopenharmony_ci	 * path should fail, and search up might take a look at the guard gap
199f08c3bdfSopenharmony_ci	 * region. If it avoids it, the allocation will be above the stack. If it
200f08c3bdfSopenharmony_ci	 * uses it, the allocation will be in the gap and the test should fail.
201f08c3bdfSopenharmony_ci	 */
202f08c3bdfSopenharmony_ci	map_test_gap = SAFE_MMAP(0, MAPPED_LEN,
203f08c3bdfSopenharmony_ci				 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
204f08c3bdfSopenharmony_ci
205f08c3bdfSopenharmony_ci	if (stack_addr - gap <= (unsigned long)map_test_gap &&
206f08c3bdfSopenharmony_ci		(unsigned long)map_test_gap <= stack_addr) {
207f08c3bdfSopenharmony_ci		tst_res(TFAIL, "New mmap was placed in the guard gap.");
208f08c3bdfSopenharmony_ci		SAFE_MUNMAP(map_test_gap, MAPPED_LEN);
209f08c3bdfSopenharmony_ci	}
210f08c3bdfSopenharmony_ci}
211f08c3bdfSopenharmony_ci
212f08c3bdfSopenharmony_civoid do_child(void)
213f08c3bdfSopenharmony_ci{
214f08c3bdfSopenharmony_ci	unsigned long stack_addr, stack_size;
215f08c3bdfSopenharmony_ci	stack_t signal_stack;
216f08c3bdfSopenharmony_ci	struct sigaction segv_sig = {.sa_sigaction = segv_handler, .sa_flags = SA_ONSTACK|SA_SIGINFO};
217f08c3bdfSopenharmony_ci	void *map;
218f08c3bdfSopenharmony_ci	unsigned long gap = GAP_PAGES * page_size;
219f08c3bdfSopenharmony_ci	struct rlimit rlimit;
220f08c3bdfSopenharmony_ci
221f08c3bdfSopenharmony_ci	rlimit.rlim_cur = rlimit.rlim_max = RLIM_INFINITY;
222f08c3bdfSopenharmony_ci	SAFE_SETRLIMIT(RLIMIT_STACK, &rlimit);
223f08c3bdfSopenharmony_ci
224f08c3bdfSopenharmony_ci	preallocate_stack(REQ_STACK_SIZE);
225f08c3bdfSopenharmony_ci
226f08c3bdfSopenharmony_ci	stack_addr = read_stack_addr_from_proc(&stack_size);
227f08c3bdfSopenharmony_ci	if (stack_addr == -1UL) {
228f08c3bdfSopenharmony_ci		tst_brk(TBROK, "can't read stack top from /proc/self/maps");
229f08c3bdfSopenharmony_ci		return;
230f08c3bdfSopenharmony_ci	}
231f08c3bdfSopenharmony_ci
232f08c3bdfSopenharmony_ci	if (STACK_GROWSDOWN)
233f08c3bdfSopenharmony_ci		mapped_addr = stack_addr - gap - MAPPED_LEN;
234f08c3bdfSopenharmony_ci	else
235f08c3bdfSopenharmony_ci		mapped_addr = stack_addr + gap;
236f08c3bdfSopenharmony_ci
237f08c3bdfSopenharmony_ci	mapped_addr &= page_mask;
238f08c3bdfSopenharmony_ci	map = SAFE_MMAP((void *)mapped_addr, MAPPED_LEN,
239f08c3bdfSopenharmony_ci			PROT_READ|PROT_WRITE,
240f08c3bdfSopenharmony_ci			MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
241f08c3bdfSopenharmony_ci	tst_res(TINFO, "Stack:0x%lx+0x%lx mmap:%p+0x%lx",
242f08c3bdfSopenharmony_ci		stack_addr, stack_size, map, MAPPED_LEN);
243f08c3bdfSopenharmony_ci
244f08c3bdfSopenharmony_ci	signal_stack.ss_sp = SAFE_MALLOC(SIGNAL_STACK_SIZE);
245f08c3bdfSopenharmony_ci	signal_stack.ss_size = SIGNAL_STACK_SIZE;
246f08c3bdfSopenharmony_ci	signal_stack.ss_flags = 0;
247f08c3bdfSopenharmony_ci	if (sigaltstack(&signal_stack, NULL) == -1) {
248f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sigaltstack");
249f08c3bdfSopenharmony_ci		return;
250f08c3bdfSopenharmony_ci	}
251f08c3bdfSopenharmony_ci	if (sigaction(SIGSEGV, &segv_sig, NULL) == -1 ||
252f08c3bdfSopenharmony_ci	    sigaction(SIGBUS,  &segv_sig, NULL) == -1) {
253f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sigaction");
254f08c3bdfSopenharmony_ci		return;
255f08c3bdfSopenharmony_ci	}
256f08c3bdfSopenharmony_ci
257f08c3bdfSopenharmony_ci#ifdef DEBUG
258f08c3bdfSopenharmony_ci	dump_proc_self_maps();
259f08c3bdfSopenharmony_ci#endif
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_ci#ifdef __x86_64__
262f08c3bdfSopenharmony_ci	do_mmap_placement_test(stack_addr, gap);
263f08c3bdfSopenharmony_ci#endif
264f08c3bdfSopenharmony_ci
265f08c3bdfSopenharmony_ci	/* Now see if it can grow too close to an adjacent region. */
266f08c3bdfSopenharmony_ci	exhaust_stack_into_sigsegv();
267f08c3bdfSopenharmony_ci}
268f08c3bdfSopenharmony_ci
269f08c3bdfSopenharmony_civoid setup(void)
270f08c3bdfSopenharmony_ci{
271f08c3bdfSopenharmony_ci	char buf[4096], *p;
272f08c3bdfSopenharmony_ci
273f08c3bdfSopenharmony_ci	page_size = sysconf(_SC_PAGESIZE);
274f08c3bdfSopenharmony_ci	page_mask = ~(page_size - 1);
275f08c3bdfSopenharmony_ci
276f08c3bdfSopenharmony_ci	buf[4095] = '\0';
277f08c3bdfSopenharmony_ci	SAFE_FILE_SCANF("/proc/cmdline", "%4095[^\n]", buf);
278f08c3bdfSopenharmony_ci
279f08c3bdfSopenharmony_ci	if ((p = strstr(buf, "stack_guard_gap=")) != NULL) {
280f08c3bdfSopenharmony_ci		if (sscanf(p, "stack_guard_gap=%ld", &GAP_PAGES) != 1) {
281f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "sscanf");
282f08c3bdfSopenharmony_ci			return;
283f08c3bdfSopenharmony_ci		}
284f08c3bdfSopenharmony_ci		tst_res(TINFO, "stack_guard_gap = %ld", GAP_PAGES);
285f08c3bdfSopenharmony_ci	}
286f08c3bdfSopenharmony_ci
287f08c3bdfSopenharmony_ci	THRESHOLD = (GAP_PAGES - 1) * page_size;
288f08c3bdfSopenharmony_ci
289f08c3bdfSopenharmony_ci	{
290f08c3bdfSopenharmony_ci		volatile int *a = alloca(128);
291f08c3bdfSopenharmony_ci
292f08c3bdfSopenharmony_ci		{
293f08c3bdfSopenharmony_ci			volatile int *b = alloca(128);
294f08c3bdfSopenharmony_ci
295f08c3bdfSopenharmony_ci			STACK_GROWSDOWN = a > b;
296f08c3bdfSopenharmony_ci			tst_res(TINFO, "STACK_GROWSDOWN = %d == %p > %p", STACK_GROWSDOWN, a, b);
297f08c3bdfSopenharmony_ci		}
298f08c3bdfSopenharmony_ci	}
299f08c3bdfSopenharmony_ci}
300f08c3bdfSopenharmony_ci
301f08c3bdfSopenharmony_civoid stack_clash_test(void)
302f08c3bdfSopenharmony_ci{
303f08c3bdfSopenharmony_ci	int status;
304f08c3bdfSopenharmony_ci	pid_t pid;
305f08c3bdfSopenharmony_ci
306f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
307f08c3bdfSopenharmony_ci	if (!pid) {
308f08c3bdfSopenharmony_ci		do_child();
309f08c3bdfSopenharmony_ci		exit(EXIT_TESTBROKE);
310f08c3bdfSopenharmony_ci		return;
311f08c3bdfSopenharmony_ci	}
312f08c3bdfSopenharmony_ci
313f08c3bdfSopenharmony_ci	SAFE_WAITPID(pid, &status, 0);
314f08c3bdfSopenharmony_ci
315f08c3bdfSopenharmony_ci	if (WIFEXITED(status)) {
316f08c3bdfSopenharmony_ci		switch (WEXITSTATUS(status)) {
317f08c3bdfSopenharmony_ci		case EXIT_FAILURE:
318f08c3bdfSopenharmony_ci			tst_res(TFAIL, "stack is too close to the mmaped area");
319f08c3bdfSopenharmony_ci			return;
320f08c3bdfSopenharmony_ci		case EXIT_SUCCESS:
321f08c3bdfSopenharmony_ci			tst_res(TPASS, "stack is far enough from mmaped area");
322f08c3bdfSopenharmony_ci			return;
323f08c3bdfSopenharmony_ci		default:
324f08c3bdfSopenharmony_ci		case EXIT_TESTBROKE:
325f08c3bdfSopenharmony_ci			break;
326f08c3bdfSopenharmony_ci		}
327f08c3bdfSopenharmony_ci	}
328f08c3bdfSopenharmony_ci
329f08c3bdfSopenharmony_ci	tst_brk(TBROK, "Child %s", tst_strstatus(status));
330f08c3bdfSopenharmony_ci}
331f08c3bdfSopenharmony_ci
332f08c3bdfSopenharmony_cistatic struct tst_test test = {
333f08c3bdfSopenharmony_ci	.forks_child = 1,
334f08c3bdfSopenharmony_ci	.needs_root = 1,
335f08c3bdfSopenharmony_ci	.setup = setup,
336f08c3bdfSopenharmony_ci	.test_all = stack_clash_test,
337f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
338f08c3bdfSopenharmony_ci		{"CVE", "2017-1000364"},
339f08c3bdfSopenharmony_ci		{"linux-git", "58c5d0d6d522"},
340f08c3bdfSopenharmony_ci		{}
341f08c3bdfSopenharmony_ci	}
342f08c3bdfSopenharmony_ci};
343