1#include "defs.h"
2
3#include <sys/prctl.h>
4
5#include "xlat/prctl_options.h"
6#include "xlat/pr_unalign_flags.h"
7#include "xlat/pr_mce_kill.h"
8#include "xlat/pr_mce_kill_policy.h"
9#include "xlat/pr_set_mm.h"
10#include "xlat/pr_tsc.h"
11
12#ifndef TASK_COMM_LEN
13# define TASK_COMM_LEN 16
14#endif
15
16#ifdef HAVE_LINUX_SECCOMP_H
17# include <linux/seccomp.h>
18#endif
19#include "xlat/seccomp_mode.h"
20
21#ifdef HAVE_LINUX_SECUREBITS_H
22# include <linux/securebits.h>
23#endif
24#include "xlat/secbits.h"
25
26/* these constants are the same as in <linux/capability.h> */
27enum {
28#include "caps0.h"
29#include "caps1.h"
30};
31
32#include "xlat/cap.h"
33
34static int
35prctl_enter(struct tcb *tcp)
36{
37	unsigned int i;
38
39	printxval(prctl_options, tcp->u_arg[0], "PR_???");
40
41	switch (tcp->u_arg[0]) {
42	/* PR_GET_* are decoded on exit. */
43	case PR_GET_CHILD_SUBREAPER:
44	case PR_GET_DUMPABLE:
45	case PR_GET_ENDIAN:
46	case PR_GET_FPEMU:
47	case PR_GET_FPEXC:
48	case PR_GET_KEEPCAPS:
49	case PR_GET_NAME:
50	case PR_GET_PDEATHSIG:
51	case PR_GET_SECCOMP:
52	case PR_GET_SECUREBITS:
53	case PR_GET_TID_ADDRESS:
54	case PR_GET_TIMERSLACK:
55	case PR_GET_TIMING:
56	case PR_GET_TSC:
57	case PR_GET_UNALIGN:
58	/* PR_TASK_PERF_EVENTS_* have nothing to decode on enter. */
59	case PR_TASK_PERF_EVENTS_DISABLE:
60	case PR_TASK_PERF_EVENTS_ENABLE:
61		break;
62
63	case PR_SET_CHILD_SUBREAPER:
64	case PR_SET_DUMPABLE:
65	case PR_SET_ENDIAN:
66	case PR_SET_FPEMU:
67	case PR_SET_FPEXC:
68	case PR_SET_KEEPCAPS:
69	case PR_SET_TIMING:
70		tprintf(", %lu", tcp->u_arg[1]);
71		break;
72
73	case PR_CAPBSET_DROP:
74	case PR_CAPBSET_READ:
75		tprints(", ");
76		printxval(cap, tcp->u_arg[1], "CAP_???");
77		break;
78
79	case PR_MCE_KILL:
80		tprints(", ");
81		printxval(pr_mce_kill, tcp->u_arg[1], "PR_MCE_KILL_???");
82		tprints(", ");
83		if (PR_MCE_KILL_SET == tcp->u_arg[1])
84			printxval(pr_mce_kill_policy, tcp->u_arg[2],
85				   "PR_MCE_KILL_???");
86		else
87			tprintf("%#lx", tcp->u_arg[2]);
88		for (i = 3; i < tcp->s_ent->nargs; i++)
89			tprintf(", %#lx", tcp->u_arg[i]);
90		break;
91
92	case PR_SET_NAME:
93		tprints(", ");
94		printstr(tcp, tcp->u_arg[1], TASK_COMM_LEN);
95		break;
96
97	case PR_SET_MM:
98		tprints(", ");
99		printxval(pr_set_mm, tcp->u_arg[1], "PR_SET_MM_???");
100		for (i = 2; i < tcp->s_ent->nargs; i++)
101			tprintf(", %#lx", tcp->u_arg[i]);
102		break;
103
104	case PR_SET_PDEATHSIG:
105		tprints(", ");
106		if ((unsigned long) tcp->u_arg[1] > 128)
107			tprintf("%lu", tcp->u_arg[1]);
108		else
109			tprints(signame(tcp->u_arg[1]));
110		break;
111
112	case PR_SET_PTRACER:
113		tprints(", ");
114		if (tcp->u_arg[1] == -1)
115			tprints("PR_SET_PTRACER_ANY");
116		else
117			tprintf("%lu", tcp->u_arg[1]);
118		break;
119
120	case PR_SET_SECCOMP:
121		tprints(", ");
122		printxval(seccomp_mode, tcp->u_arg[1],
123			  "SECCOMP_MODE_???");
124		if (SECCOMP_MODE_STRICT == tcp->u_arg[1])
125			break;
126		if (SECCOMP_MODE_FILTER == tcp->u_arg[1]) {
127			tprints(", ");
128			print_seccomp_filter(tcp, tcp->u_arg[2]);
129			break;
130		}
131		for (i = 2; i < tcp->s_ent->nargs; i++)
132			tprintf(", %#lx", tcp->u_arg[i]);
133		break;
134
135	case PR_SET_SECUREBITS:
136		tprints(", ");
137		printflags(secbits, tcp->u_arg[1], "SECBIT_???");
138		break;
139
140	case PR_SET_TIMERSLACK:
141		tprintf(", %ld", tcp->u_arg[1]);
142		break;
143
144	case PR_SET_TSC:
145		tprints(", ");
146		printxval(pr_tsc, tcp->u_arg[1], "PR_TSC_???");
147		break;
148
149	case PR_SET_UNALIGN:
150		tprints(", ");
151		printflags(pr_unalign_flags, tcp->u_arg[1], "PR_UNALIGN_???");
152		break;
153
154	case PR_SET_NO_NEW_PRIVS:
155	case PR_SET_THP_DISABLE:
156		tprintf(", %lu", tcp->u_arg[1]);
157		for (i = 2; i < tcp->s_ent->nargs; i++)
158			tprintf(", %#lx", tcp->u_arg[i]);
159		break;
160
161	case PR_GET_NO_NEW_PRIVS:
162	case PR_GET_THP_DISABLE:
163	case PR_MCE_KILL_GET:
164	/* Return code of "GET" commands will be decoded on exit */
165	case PR_MPX_DISABLE_MANAGEMENT:
166	case PR_MPX_ENABLE_MANAGEMENT:
167	default:
168		for (i = 1; i < tcp->s_ent->nargs; i++)
169			tprintf(", %#lx", tcp->u_arg[i]);
170		break;
171	}
172	return 0;
173}
174
175static int
176prctl_exit(struct tcb *tcp)
177{
178	unsigned long addr;
179	unsigned int i;
180
181	switch (tcp->u_arg[0]) {
182	case PR_CAPBSET_READ:
183	case PR_GET_DUMPABLE:
184	case PR_GET_KEEPCAPS:
185	case PR_GET_NO_NEW_PRIVS:
186	case PR_GET_SECCOMP:
187	case PR_GET_THP_DISABLE:
188	case PR_GET_TIMERSLACK:
189	case PR_GET_TIMING:
190		return syserror(tcp) ? 0 : RVAL_UDECIMAL;
191
192	case PR_GET_CHILD_SUBREAPER:
193	case PR_GET_ENDIAN:
194	case PR_GET_FPEMU:
195	case PR_GET_FPEXC:
196		tprints(", ");
197		/* cannot use printnum_int() because of syserror() */
198		if (!tcp->u_arg[1])
199			tprints("NULL");
200		else if (syserror(tcp) || umove(tcp, tcp->u_arg[1], &i) < 0)
201			tprintf("%#lx", tcp->u_arg[1]);
202		else
203			tprintf("[%u]", i);
204		break;
205
206	case PR_GET_NAME:
207		tprints(", ");
208		if (!tcp->u_arg[1])
209			tprints("NULL");
210		else if (syserror(tcp))
211			tprintf("%#lx", tcp->u_arg[1]);
212		else
213			printstr(tcp, tcp->u_arg[1], -1);
214		break;
215
216	case PR_GET_PDEATHSIG:
217		tprints(", ");
218		if (!tcp->u_arg[1])
219			tprints("NULL");
220		else if (syserror(tcp) || umove(tcp, tcp->u_arg[1], &i) < 0)
221			tprintf("%#lx", tcp->u_arg[1]);
222		else {
223			tprints("[");
224			tprints(signame(i));
225			tprints("]");
226		}
227		break;
228
229	case PR_GET_SECUREBITS:
230		if (syserror(tcp) || tcp->u_rval == 0)
231			return 0;
232		tcp->auxstr = sprintflags("", secbits, tcp->u_rval);
233		return RVAL_STR;
234
235	case PR_GET_TID_ADDRESS:
236		tprints(", ");
237		/* cannot use printnum_long() because of syserror() */
238		if (!tcp->u_arg[1])
239			tprints("NULL");
240		else if (syserror(tcp) || umove(tcp, tcp->u_arg[1], &addr) < 0)
241			tprintf("%#lx", tcp->u_arg[1]);
242		else
243			tprintf("[%#lx]", addr);
244		break;
245
246	case PR_GET_TSC:
247		tprints(", ");
248		if (!tcp->u_arg[1])
249			tprints("NULL");
250		else if (syserror(tcp) || umove(tcp, tcp->u_arg[1], &i) < 0)
251			tprintf("%#lx", tcp->u_arg[1]);
252		else {
253			tprints("[");
254			printxval(pr_tsc, i, "PR_TSC_???");
255			tprints("]");
256		}
257		break;
258
259	case PR_GET_UNALIGN:
260		tprints(", ");
261		if (!tcp->u_arg[1])
262			tprints("NULL");
263		else if (syserror(tcp) || umove(tcp, tcp->u_arg[1], &i) < 0)
264			tprintf("%#lx", tcp->u_arg[1]);
265		else {
266			tprints("[");
267			printflags(pr_unalign_flags, i, "PR_UNALIGN_???");
268			tprints("]");
269		}
270		break;
271
272	case PR_MCE_KILL_GET:
273		if (syserror(tcp))
274			return 0;
275		tcp->auxstr = xlookup(pr_mce_kill_policy, tcp->u_rval);
276		return tcp->auxstr ? RVAL_STR : RVAL_UDECIMAL;
277
278	default:
279		break;
280	}
281	return 0;
282}
283
284SYS_FUNC(prctl)
285{
286	return entering(tcp) ? prctl_enter(tcp) : prctl_exit(tcp);
287}
288
289#if defined X86_64 || defined X32
290# include <asm/prctl.h>
291# include "xlat/archvals.h"
292
293SYS_FUNC(arch_prctl)
294{
295	if (entering(tcp))
296		printxval(archvals, tcp->u_arg[0], "ARCH_???");
297
298	switch (tcp->u_arg[0]) {
299	case ARCH_GET_GS:
300	case ARCH_GET_FS:
301		if (exiting(tcp)) {
302			if (syserror(tcp))
303				break;
304			tprints(", ");
305			printnum_long(tcp, tcp->u_arg[1], "%#lx");
306		}
307		return 0;
308	default:
309		if (exiting(tcp))
310			return 0;
311	}
312
313	tprintf(", %#lx", tcp->u_arg[1]);
314	return 0;
315}
316#endif /* X86_64 || X32 */
317