1 /*
2 * Check decoding of prctl PR_GET_FP_MODE/PR_SET_FP_MODE operations.
3 *
4 * Copyright (c) 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 #include "scno.h"
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <linux/prctl.h>
17
18 static long injected_val;
19
20 static long
21 do_prctl(kernel_ulong_t cmd, kernel_ulong_t arg2, kernel_ulong_t arg3)
22 {
23 long rc = syscall(__NR_prctl, cmd, arg2, arg3);
24
25 if (rc != injected_val)
26 error_msg_and_fail("Return value (%ld) differs from expected "
27 "injected value (%ld)",
28 rc, injected_val);
29
30 return rc;
31 }
32
33 int
34 main(int argc, char **argv)
35 {
36 static const kernel_ulong_t bogus_arg2 =
37 (kernel_ulong_t) 0xdecafeedbeefda7eULL;
38 static const kernel_ulong_t bogus_arg3 =
39 (kernel_ulong_t) 0xdecafeedbeefda7eULL;
40
41 static const struct {
42 long arg;
43 const char *str;
44 } get_strs[] = {
45 {-1, ""},
46 {0, ""},
47 {1, " (PR_FP_MODE_FR)"},
48 {2, " (PR_FP_MODE_FRE)"},
49 {3, " (PR_FP_MODE_FR|PR_FP_MODE_FRE)"},
50 {0x20, ""},
51 {0x20 | 3, " (PR_FP_MODE_FR|PR_FP_MODE_FRE|0x20)"}
52 };
53 static const struct {
54 kernel_ulong_t arg;
55 const char *str;
56 } set_strs[] = {
57 {0, "0"},
58 {1, "PR_FP_MODE_FR"},
59 {2, "PR_FP_MODE_FRE"},
60 {3, "PR_FP_MODE_FR|PR_FP_MODE_FRE"},
61 {0x20, "0x20 /* PR_FP_MODE_??? */"},
62 {0x20 | 3, "PR_FP_MODE_FR|PR_FP_MODE_FRE|0x20"}
63 };
64
65 long rc;
66 unsigned long num_skip;
67 const char *str = NULL;
68 bool locked = false;
69
70 if (argc < 3)
71 error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
72
73 num_skip = strtoul(argv[1], NULL, 0);
74 injected_val = strtol(argv[2], NULL, 0);
75
76 for (size_t i = 0; i < num_skip; i++) {
77 if ((prctl_marker() != injected_val) ||
78 ((injected_val == -1) && (errno != ENOTTY)))
79 continue;
80
81 locked = true;
82 break;
83 }
84
85 if (!locked)
86 error_msg_and_fail("Have not locked on prctl(-1, -2, -3, -4"
87 ", -5) returning %ld", injected_val);
88
89 /* PR_GET_FP_MODE */
90 rc = do_prctl(PR_GET_FP_MODE, bogus_arg2, bogus_arg3);
91
92 for (size_t i = 0; i < ARRAY_SIZE(get_strs); i++) {
93 if (get_strs[i].arg == rc) {
94 str = get_strs[i].str;
95 break;
96 }
97 }
98 if (!str)
99 error_msg_and_fail("Unknown return value: %ld", rc);
100
101 if (rc < 0) {
102 printf("prctl(PR_GET_FP_MODE) = %s%s (INJECTED)\n",
103 sprintrc(rc), str);
104 } else {
105 printf("prctl(PR_GET_FP_MODE) = %#lx%s (INJECTED)\n",
106 rc, str);
107 }
108
109 /* PR_SET_FP_MODE */
110 for (size_t i = 0; i < ARRAY_SIZE(set_strs); i++) {
111 rc = do_prctl(PR_SET_FP_MODE, set_strs[i].arg, bogus_arg3);
112
113 printf("prctl(PR_SET_FP_MODE, %s) = %s (INJECTED)\n", set_strs[i].str,
114 sprintrc(rc));
115 }
116
117 puts("+++ exited with 0 +++");
118 return 0;
119 }