File: prctl-fp-mode.c

package info (click to toggle)
strace 6.1-0.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 64,424 kB
  • sloc: ansic: 160,349; sh: 9,223; makefile: 3,817; cpp: 944; awk: 353; perl: 267; exp: 62; sed: 9
file content (119 lines) | stat: -rw-r--r-- 2,784 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
 * Check decoding of prctl PR_GET_FP_MODE/PR_SET_FP_MODE operations.
 *
 * Copyright (c) 2021 The strace developers.
 * All rights reserved.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "tests.h"
#include "scno.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/prctl.h>

static long injected_val;

static long
do_prctl(kernel_ulong_t cmd, kernel_ulong_t arg2, kernel_ulong_t arg3)
{
	long rc = syscall(__NR_prctl, cmd, arg2, arg3);

	if (rc != injected_val)
		error_msg_and_fail("Return value (%ld) differs from expected "
						   "injected value (%ld)",
						   rc, injected_val);

	return rc;
}

int
main(int argc, char **argv)
{
	static const kernel_ulong_t bogus_arg2 =
			(kernel_ulong_t) 0xdecafeedbeefda7eULL;
	static const kernel_ulong_t bogus_arg3 =
			(kernel_ulong_t) 0xdecafeedbeefda7eULL;

	static const struct {
		long arg;
		const char *str;
	} get_strs[] = {
			{-1,       ""},
			{0,        ""},
			{1,        " (PR_FP_MODE_FR)"},
			{2,        " (PR_FP_MODE_FRE)"},
			{3,        " (PR_FP_MODE_FR|PR_FP_MODE_FRE)"},
			{0x20,     ""},
			{0x20 | 3, " (PR_FP_MODE_FR|PR_FP_MODE_FRE|0x20)"}
	};
	static const struct {
		kernel_ulong_t arg;
		const char *str;
	} set_strs[] = {
			{0,        "0"},
			{1,        "PR_FP_MODE_FR"},
			{2,        "PR_FP_MODE_FRE"},
			{3,        "PR_FP_MODE_FR|PR_FP_MODE_FRE"},
			{0x20,     "0x20 /* PR_FP_MODE_??? */"},
			{0x20 | 3, "PR_FP_MODE_FR|PR_FP_MODE_FRE|0x20"}
	};

	long rc;
	unsigned long num_skip;
	const char *str = NULL;
	bool locked = false;

	if (argc < 3)
		error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);

	num_skip = strtoul(argv[1], NULL, 0);
	injected_val = strtol(argv[2], NULL, 0);

	for (size_t i = 0; i < num_skip; i++) {
		if ((prctl_marker() != injected_val) ||
		    ((injected_val == -1) && (errno != ENOTTY)))
			continue;

		locked = true;
		break;
	}

	if (!locked)
		error_msg_and_fail("Have not locked on prctl(-1, -2, -3, -4"
				   ", -5) returning %ld", injected_val);

	/* PR_GET_FP_MODE */
	rc = do_prctl(PR_GET_FP_MODE, bogus_arg2, bogus_arg3);

	for (size_t i = 0; i < ARRAY_SIZE(get_strs); i++) {
		if (get_strs[i].arg == rc) {
			str = get_strs[i].str;
			break;
		}
	}
	if (!str)
		error_msg_and_fail("Unknown return value: %ld", rc);

	if (rc < 0) {
		printf("prctl(PR_GET_FP_MODE) = %s%s (INJECTED)\n",
		       sprintrc(rc), str);
	} else {
		printf("prctl(PR_GET_FP_MODE) = %#lx%s (INJECTED)\n",
		       rc, str);
	}

	/* PR_SET_FP_MODE */
	for (size_t i = 0; i < ARRAY_SIZE(set_strs); i++) {
		rc = do_prctl(PR_SET_FP_MODE, set_strs[i].arg, bogus_arg3);

		printf("prctl(PR_SET_FP_MODE, %s) = %s (INJECTED)\n", set_strs[i].str,
			   sprintrc(rc));
	}

	puts("+++ exited with 0 +++");
	return 0;
}