]> granicus.if.org Git - strace/blob - prctl.c
Improve prctl decoding
[strace] / prctl.c
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> */
27 enum {
28 #include "caps0.h"
29 #include "caps1.h"
30 };
31
32 #include "xlat/cap.h"
33
34 static int
35 prctl_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
175 static int
176 prctl_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
284 int
285 sys_prctl(struct tcb *tcp)
286 {
287         return entering(tcp) ? prctl_enter(tcp) : prctl_exit(tcp);
288 }
289
290 #if defined X86_64 || defined X32
291 # include <asm/prctl.h>
292 # include "xlat/archvals.h"
293
294 int
295 sys_arch_prctl(struct tcb *tcp)
296 {
297         if (entering(tcp))
298                 printxval(archvals, tcp->u_arg[0], "ARCH_???");
299
300         switch (tcp->u_arg[0]) {
301         case ARCH_GET_GS:
302         case ARCH_GET_FS:
303                 if (exiting(tcp)) {
304                         if (syserror(tcp))
305                                 break;
306                         tprints(", ");
307                         printnum_long(tcp, tcp->u_arg[1], "%#lx");
308                 }
309                 return 0;
310         default:
311                 if (exiting(tcp))
312                         return 0;
313         }
314
315         tprintf(", %#lx", tcp->u_arg[1]);
316         return 0;
317 }
318 #endif /* X86_64 || X32 */