1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
4 * Author: Ulrich Drepper / Nate Straz , Red Hat
5 * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
6 */
7
8 /*\
9 * [Description]
10 *
11 * This test verifies that LDT is propagated correctly from parent process to
12 * the child process.
13 *
14 * On Friday, May 2, 2003 at 09:47:00AM MST, Ulrich Drepper wrote:
15 *
16 * Robert Williamson wrote:
17 *
18 * I'm getting a SIGSEGV with one of our tests, fork05.c, that apparently
19 * you wrote (attached below). The test passes on my 2.5.68 machine running
20 * SuSE 8.0 (glibc 2.2.5 and Linuxthreads), however it segmentation faults on
21 * RedHat 9 running 2.5.68. The test seems to "break" when it attempts to run
22 * the assembly code....could you take a look at it?
23 *
24 * There is no need to look at it, I know it cannot work anymore on recent
25 * systems. Either change all uses of %gs to %fs or skip the entire patch
26 * if %gs has a nonzero value.
27 *
28 * On Sat, Aug 12, 2000 at 12:47:31PM -0700, Ulrich Drepper wrote:
29 *
30 * Ever since the %gs handling was fixed in the 2.3.99 series the
31 * appended test program worked. Now with 2.4.0-test6 it's not working
32 * again. Looking briefly over the patch from test5 to test6 I haven't
33 * seen an immediate candidate for the breakage. It could be missing
34 * propagation of the LDT to the new process (and therefore an invalid
35 * segment descriptor) or simply clearing %gs.
36 *
37 * Anyway, this is what you should see and what you get with test5:
38 *
39 * a = 42
40 * %gs = 0x0007
41 * %gs = 0x0007
42 * a = 99
43 *
44 * This is what you get with test6:
45 *
46 * a = 42
47 * %gs = 0x0007
48 * %gs = 0x0000
49 * <SEGFAULT>
50 *
51 * If somebody is actually creating a test suite for the kernel, please
52 * add this program. It's mostly self-contained. The correct handling
53 * of %gs is really important since glibc 2.2 will make heavy use of it.
54 */
55
56 #include "tst_test.h"
57
58 #if defined(__i386__)
59
60 #include "lapi/syscalls.h"
61 #include <asm/ldt.h>
62
run(void)63 static void run(void)
64 {
65 struct user_desc ldt0;
66 int base_addr = 42;
67 int status;
68 pid_t pid;
69 int lo;
70
71 ldt0.entry_number = 0;
72 ldt0.base_addr = (long)&base_addr;
73 ldt0.limit = 4;
74 ldt0.seg_32bit = 1;
75 ldt0.contents = 0;
76 ldt0.read_exec_only = 0;
77 ldt0.limit_in_pages = 0;
78 ldt0.seg_not_present = 0;
79 ldt0.useable = 1;
80
81 tst_syscall(__NR_modify_ldt, 1, &ldt0, sizeof(ldt0));
82
83 asm volatile ("movw %w0, %%fs"::"q" (7));
84 asm volatile ("movl %%fs:0, %0":"=r" (lo));
85 tst_res(TINFO, "a = %d", lo);
86
87 asm volatile ("pushl %%fs; popl %0":"=q" (lo));
88 tst_res(TINFO, "%%fs = %#06hx", lo);
89
90 asm volatile ("movl %0, %%fs:0"::"r" (99));
91
92 pid = SAFE_FORK();
93 if (!pid) {
94 asm volatile ("pushl %%fs; popl %0":"=q" (lo));
95 tst_res(TINFO, "%%fs = %#06hx", lo);
96
97 asm volatile ("movl %%fs:0, %0":"=r" (lo));
98 tst_res(TINFO, "a = %d", lo);
99
100 TST_EXP_EQ_LI(lo, 99);
101
102 exit(0);
103 }
104
105 SAFE_WAITPID(pid, &status, 0);
106
107 if (WIFEXITED(status) && !WEXITSTATUS(status))
108 tst_res(TPASS, "Child did exit with 0");
109 else
110 tst_res(TFAIL, "Child %s", tst_strstatus(status));
111 }
112
113 static struct tst_test test = {
114 .test_all = run,
115 .forks_child = 1,
116 };
117
118 #else
119 TST_TEST_TCONF("Test only supports Intel 32 bits");
120 #endif
121