]> granicus.if.org Git - strace/blob - filter_qualify.c
mem: decode hugetlb page size in mmap flags
[strace] / filter_qualify.c
1 /*
2  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2016-2017 The strace developers.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "defs.h"
30 #include "nsig.h"
31 #include "number_set.h"
32 #include "filter.h"
33
34 struct number_set *read_set;
35 struct number_set *write_set;
36 struct number_set *signal_set;
37
38 static struct number_set *abbrev_set;
39 static struct number_set *inject_set;
40 static struct number_set *raw_set;
41 static struct number_set *trace_set;
42 static struct number_set *verbose_set;
43
44 static int
45 sigstr_to_uint(const char *s)
46 {
47         int i;
48
49         if (*s >= '0' && *s <= '9')
50                 return string_to_uint_upto(s, 255);
51
52         if (strncasecmp(s, "SIG", 3) == 0)
53                 s += 3;
54
55         for (i = 0; i <= 255; ++i) {
56                 const char *name = signame(i);
57
58                 if (strncasecmp(name, "SIG", 3) != 0)
59                         continue;
60
61                 name += 3;
62
63                 if (strcasecmp(name, s) != 0)
64                         continue;
65
66                 return i;
67         }
68
69         return -1;
70 }
71
72 static int
73 find_errno_by_name(const char *name)
74 {
75         unsigned int i;
76
77         for (i = 1; i < nerrnos; ++i) {
78                 if (errnoent[i] && (strcasecmp(name, errnoent[i]) == 0))
79                         return i;
80         }
81
82         return -1;
83 }
84
85 static bool
86 parse_inject_token(const char *const token, struct inject_opts *const fopts,
87                    const bool fault_tokens_only)
88 {
89         const char *val;
90         int intval;
91
92         if ((val = STR_STRIP_PREFIX(token, "when=")) != token) {
93                 /*
94                  *      == 1+1
95                  * F    == F+0
96                  * F+   == F+1
97                  * F+S
98                  */
99                 char *end;
100                 intval = string_to_uint_ex(val, &end, 0xffff, "+");
101                 if (intval < 1)
102                         return false;
103
104                 fopts->first = intval;
105
106                 if (*end) {
107                         val = end + 1;
108                         if (*val) {
109                                 /* F+S */
110                                 intval = string_to_uint_upto(val, 0xffff);
111                                 if (intval < 1)
112                                         return false;
113                                 fopts->step = intval;
114                         } else {
115                                 /* F+ == F+1 */
116                                 fopts->step = 1;
117                         }
118                 } else {
119                         /* F == F+0 */
120                         fopts->step = 0;
121                 }
122         } else if ((val = STR_STRIP_PREFIX(token, "error=")) != token) {
123                 if (fopts->data.flags & INJECT_F_RETVAL)
124                         return false;
125                 intval = string_to_uint_upto(val, MAX_ERRNO_VALUE);
126                 if (intval < 0)
127                         intval = find_errno_by_name(val);
128                 if (intval < 1)
129                         return false;
130                 fopts->data.rval = -intval;
131                 fopts->data.flags |= INJECT_F_RETVAL;
132         } else if (!fault_tokens_only
133                    && (val = STR_STRIP_PREFIX(token, "retval=")) != token) {
134                 if (fopts->data.flags & INJECT_F_RETVAL)
135                         return false;
136                 intval = string_to_uint(val);
137                 if (intval < 0)
138                         return false;
139                 fopts->data.rval = intval;
140                 fopts->data.flags |= INJECT_F_RETVAL;
141         } else if (!fault_tokens_only
142                    && (val = STR_STRIP_PREFIX(token, "signal=")) != token) {
143                 if (fopts->data.flags & INJECT_F_SIGNAL)
144                         return false;
145                 intval = sigstr_to_uint(val);
146                 if (intval < 1 || intval > NSIG_BYTES * 8)
147                         return false;
148                 fopts->data.signo = intval;
149                 fopts->data.flags |= INJECT_F_SIGNAL;
150         } else {
151                 return false;
152         }
153
154         return true;
155 }
156
157 static char *
158 parse_inject_expression(const char *const s, char **buf,
159                         struct inject_opts *const fopts,
160                         const bool fault_tokens_only)
161 {
162         char *saveptr = NULL;
163         char *name = NULL;
164         char *token;
165
166         *buf = xstrdup(s);
167         for (token = strtok_r(*buf, ":", &saveptr); token;
168              token = strtok_r(NULL, ":", &saveptr)) {
169                 if (!name)
170                         name = token;
171                 else if (!parse_inject_token(token, fopts, fault_tokens_only))
172                         goto parse_error;
173         }
174
175         if (name)
176                 return name;
177
178 parse_error:
179         free(*buf);
180         return *buf = NULL;
181 }
182
183 static void
184 qualify_read(const char *const str)
185 {
186         if (!read_set)
187                 read_set = alloc_number_set_array(1);
188         qualify_tokens(str, read_set, string_to_uint, "descriptor");
189 }
190
191 static void
192 qualify_write(const char *const str)
193 {
194         if (!write_set)
195                 write_set = alloc_number_set_array(1);
196         qualify_tokens(str, write_set, string_to_uint, "descriptor");
197 }
198
199 static void
200 qualify_signals(const char *const str)
201 {
202         if (!signal_set)
203                 signal_set = alloc_number_set_array(1);
204         qualify_tokens(str, signal_set, sigstr_to_uint, "signal");
205 }
206
207 static void
208 qualify_trace(const char *const str)
209 {
210         if (!trace_set)
211                 trace_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
212         qualify_syscall_tokens(str, trace_set, "system call");
213 }
214
215 static void
216 qualify_abbrev(const char *const str)
217 {
218         if (!abbrev_set)
219                 abbrev_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
220         qualify_syscall_tokens(str, abbrev_set, "system call");
221 }
222
223 static void
224 qualify_verbose(const char *const str)
225 {
226         if (!verbose_set)
227                 verbose_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
228         qualify_syscall_tokens(str, verbose_set, "system call");
229 }
230
231 static void
232 qualify_raw(const char *const str)
233 {
234         if (!raw_set)
235                 raw_set = alloc_number_set_array(SUPPORTED_PERSONALITIES);
236         qualify_syscall_tokens(str, raw_set, "system call");
237 }
238
239 static void
240 qualify_inject_common(const char *const str,
241                       const bool fault_tokens_only,
242                       const char *const description)
243 {
244         struct inject_opts opts = {
245                 .first = 1,
246                 .step = 1
247         };
248         char *buf = NULL;
249         char *name = parse_inject_expression(str, &buf, &opts, fault_tokens_only);
250         if (!name) {
251                 error_msg_and_die("invalid %s '%s'", description, str);
252         }
253
254         /* If neither of retval, error, or signal is specified, then ... */
255         if (!opts.data.flags) {
256                 if (fault_tokens_only) {
257                         /* in fault= syntax the default error code is ENOSYS. */
258                         opts.data.rval = -ENOSYS;
259                         opts.data.flags |= INJECT_F_RETVAL;
260                 } else {
261                         /* in inject= syntax this is not allowed. */
262                         error_msg_and_die("invalid %s '%s'", description, str);
263                 }
264         }
265
266         struct number_set *tmp_set =
267                 alloc_number_set_array(SUPPORTED_PERSONALITIES);
268         qualify_syscall_tokens(name, tmp_set, description);
269
270         free(buf);
271
272         /*
273          * Initialize inject_vec accourding to tmp_set.
274          * Merge tmp_set into inject_set.
275          */
276         unsigned int p;
277         for (p = 0; p < SUPPORTED_PERSONALITIES; ++p) {
278                 if (number_set_array_is_empty(tmp_set, p))
279                         continue;
280
281                 if (!inject_set) {
282                         inject_set =
283                                 alloc_number_set_array(SUPPORTED_PERSONALITIES);
284                 }
285                 if (!inject_vec[p]) {
286                         inject_vec[p] = xcalloc(nsyscall_vec[p],
287                                                sizeof(*inject_vec[p]));
288                 }
289
290                 unsigned int i;
291                 for (i = 0; i < nsyscall_vec[p]; ++i) {
292                         if (is_number_in_set_array(i, tmp_set, p)) {
293                                 add_number_to_set_array(i, inject_set, p);
294                                 inject_vec[p][i] = opts;
295                         }
296                 }
297         }
298
299         free_number_set_array(tmp_set, SUPPORTED_PERSONALITIES);
300 }
301
302 static void
303 qualify_fault(const char *const str)
304 {
305         qualify_inject_common(str, true, "fault argument");
306 }
307
308 static void
309 qualify_inject(const char *const str)
310 {
311         qualify_inject_common(str, false, "inject argument");
312 }
313
314 static const struct qual_options {
315         const char *name;
316         void (*qualify)(const char *);
317 } qual_options[] = {
318         { "trace",      qualify_trace   },
319         { "t",          qualify_trace   },
320         { "abbrev",     qualify_abbrev  },
321         { "a",          qualify_abbrev  },
322         { "verbose",    qualify_verbose },
323         { "v",          qualify_verbose },
324         { "raw",        qualify_raw     },
325         { "x",          qualify_raw     },
326         { "signal",     qualify_signals },
327         { "signals",    qualify_signals },
328         { "s",          qualify_signals },
329         { "read",       qualify_read    },
330         { "reads",      qualify_read    },
331         { "r",          qualify_read    },
332         { "write",      qualify_write   },
333         { "writes",     qualify_write   },
334         { "w",          qualify_write   },
335         { "fault",      qualify_fault   },
336         { "inject",     qualify_inject  },
337 };
338
339 void
340 qualify(const char *str)
341 {
342         const struct qual_options *opt = qual_options;
343         unsigned int i;
344
345         for (i = 0; i < ARRAY_SIZE(qual_options); ++i) {
346                 const char *name = qual_options[i].name;
347                 const size_t len = strlen(name);
348                 const char *val = str_strip_prefix_len(str, name, len);
349
350                 if (val == str || *val != '=')
351                         continue;
352                 str = val + 1;
353                 opt = &qual_options[i];
354                 break;
355         }
356
357         opt->qualify(str);
358 }
359
360 unsigned int
361 qual_flags(const unsigned int scno)
362 {
363         return  (is_number_in_set_array(scno, trace_set, current_personality)
364                    ? QUAL_TRACE : 0)
365                 | (is_number_in_set_array(scno, abbrev_set, current_personality)
366                    ? QUAL_ABBREV : 0)
367                 | (is_number_in_set_array(scno, verbose_set, current_personality)
368                    ? QUAL_VERBOSE : 0)
369                 | (is_number_in_set_array(scno, raw_set, current_personality)
370                    ? QUAL_RAW : 0)
371                 | (is_number_in_set_array(scno, inject_set, current_personality)
372                    ? QUAL_INJECT : 0);
373 }