1 /*
2 * Check decoding of modify_ldt syscall.
3 *
4 * Copyright (c) 2018-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11
12 #include "scno.h"
13
14 #if defined __NR_modify_ldt && defined HAVE_STRUCT_USER_DESC
15
16 # include <errno.h>
17 # include <stdio.h>
18 # include <unistd.h>
19
20 # include "print_user_desc.c"
21
22 static void
23 printrc(long rc)
24 {
25 # ifdef __x86_64__
26 /*
27 * Hopefully, we don't expect EPERM to be returned,
28 * otherwise we can't distinguish it on x32.
29 */
30 if (rc != -1) {
31 int err = -rc;
32
33 /* Thanks, long return type of syscall(2) */
34 printf("%lld", zero_extend_signed_to_ull(rc));
35
36 if (err > 0 && err < 0x1000) {
37 errno = err;
38 printf(" %s (%m)", errno2name());
39 }
40 }
41 else
42 # endif
43 {
44 printf("%s", sprintrc(rc));
45 }
46
47 puts("");
48 }
49
50 int
51 main(void)
52 {
53 static const kernel_ulong_t bogus_func =
54 (kernel_ulong_t) 0xbadc0dedda7a1057ULL;
55 static const kernel_ulong_t bogus_bytecount =
56 (kernel_ulong_t) 0xdeadfacefa57beefULL;
57
58 TAIL_ALLOC_OBJECT_CONST_PTR(struct user_desc, us);
59 TAIL_ALLOC_OBJECT_CONST_PTR(unsigned int, bogus_int);
60 long rc;
61
62 fill_memory(us, sizeof(*us));
63
64 rc = syscall(__NR_modify_ldt, 0, 0, 0);
65 printf("modify_ldt(0, NULL, 0) = ");
66 printrc(rc);
67
68 rc = syscall(__NR_modify_ldt, bogus_func, (kernel_long_t) -1,
69 bogus_bytecount);
70 printf("modify_ldt(%d, %#llx, %llu) = ",
71 (int) bogus_func,
72 zero_extend_signed_to_ull((kernel_long_t) -1),
73 (unsigned long long) bogus_bytecount);
74 printrc(rc);
75
76 rc = syscall(__NR_modify_ldt, bogus_func, us + 1, 0);
77 printf("modify_ldt(%d, %p, 0) = ", (int) bogus_func, us + 1);
78 printrc(rc);
79
80 rc = syscall(__NR_modify_ldt, bogus_func, us, 42);
81 printf("modify_ldt(%d, %p, 42) = ", (int) bogus_func, us);
82 printrc(rc);
83
84 rc = syscall(__NR_modify_ldt, bogus_func, us + 1, sizeof(*us));
85 printf("modify_ldt(%d, %p, %zu) = ",
86 (int) bogus_func, us + 1, sizeof(*us));
87 printrc(rc);
88
89 /*
90 * print_user_desc handles entry_number field in a special way for
91 * get_thread_area syscall, so let's also check here that we don't
92 * retrieve it accidentally.
93 */
94 rc = syscall(__NR_modify_ldt, bogus_func, bogus_int, sizeof(*us));
95 printf("modify_ldt(%d, %p, %zu) = ",
96 (int) bogus_func, bogus_int, sizeof(*us));
97 printrc(rc);
98
99 rc = syscall(__NR_modify_ldt, bogus_func, us, sizeof(*us));
100 printf("modify_ldt(%d, ", (int) bogus_func);
101 print_user_desc(us, NULL);
102 printf(", %zu) = ", sizeof(*us));
103 printrc(rc);
104
105 fill_memory_ex(us, sizeof(*us), 0x55, 80);
106 us->entry_number = -1;
107 us->base_addr = 0;
108 us->limit = 0;
109
110 rc = syscall(__NR_modify_ldt, bogus_func, us, sizeof(*us));
111 printf("modify_ldt(%d, ", (int) bogus_func);
112 print_user_desc(us, "-1");
113 printf(", %zu) = ", sizeof(*us));
114 printrc(rc);
115
116 puts("+++ exited with 0 +++");
117
118 return 0;
119 }
120
121 #else
122
123 SKIP_MAIN_UNDEFINED("__NR_modify_ldt && HAVE_STRUCT_USER_DESC");
124
125 #endif