Fix: update writeback instrumentation for kernel 4.14
[lttng-modules.git] / lttng-filter-validator.c
CommitLineData
07dfc1d0
MD
1/*
2 * lttng-filter-validator.c
3 *
4 * LTTng modules filter bytecode validator.
5 *
bbf3aef5 6 * Copyright (C) 2010-2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
07dfc1d0 7 *
bbf3aef5
MD
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
07dfc1d0 14 *
bbf3aef5
MD
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
07dfc1d0 17 *
bbf3aef5
MD
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
07dfc1d0
MD
25 */
26
499cc3f7 27#include <linux/types.h>
07dfc1d0
MD
28#include <linux/jhash.h>
29#include <linux/slab.h>
30
241ae9a8
MD
31#include <wrapper/list.h>
32#include <lttng-filter.h>
07dfc1d0
MD
33
34#define MERGE_POINT_TABLE_BITS 7
35#define MERGE_POINT_TABLE_SIZE (1U << MERGE_POINT_TABLE_BITS)
36
37/* merge point table node */
38struct mp_node {
39 struct hlist_node node;
40
41 /* Context at merge point */
42 struct vstack stack;
43 unsigned long target_pc;
44};
45
46struct mp_table {
47 struct hlist_head mp_head[MERGE_POINT_TABLE_SIZE];
48};
49
50static
51int lttng_hash_match(struct mp_node *mp_node, unsigned long key_pc)
52{
53 if (mp_node->target_pc == key_pc)
54 return 1;
55 else
56 return 0;
57}
58
59static
60int merge_points_compare(const struct vstack *stacka,
61 const struct vstack *stackb)
62{
63 int i, len;
64
65 if (stacka->top != stackb->top)
66 return 1;
67 len = stacka->top + 1;
68 WARN_ON_ONCE(len < 0);
69 for (i = 0; i < len; i++) {
70 if (stacka->e[i].type != stackb->e[i].type)
71 return 1;
72 }
73 return 0;
74}
75
76static
77int merge_point_add_check(struct mp_table *mp_table, unsigned long target_pc,
78 const struct vstack *stack)
79{
80 struct mp_node *mp_node;
81 unsigned long hash = jhash_1word(target_pc, 0);
82 struct hlist_head *head;
83 struct mp_node *lookup_node;
84 int found = 0;
85
86 dbg_printk("Filter: adding merge point at offset %lu, hash %lu\n",
87 target_pc, hash);
88 mp_node = kzalloc(sizeof(struct mp_node), GFP_KERNEL);
89 if (!mp_node)
90 return -ENOMEM;
91 mp_node->target_pc = target_pc;
92 memcpy(&mp_node->stack, stack, sizeof(mp_node->stack));
93
94 head = &mp_table->mp_head[hash & (MERGE_POINT_TABLE_SIZE - 1)];
d216ecae 95 lttng_hlist_for_each_entry(lookup_node, head, node) {
07dfc1d0
MD
96 if (lttng_hash_match(lookup_node, target_pc)) {
97 found = 1;
98 break;
99 }
100 }
101 if (found) {
102 /* Key already present */
103 dbg_printk("Filter: compare merge points for offset %lu, hash %lu\n",
104 target_pc, hash);
105 kfree(mp_node);
106 if (merge_points_compare(stack, &lookup_node->stack)) {
107 printk(KERN_WARNING "Merge points differ for offset %lu\n",
108 target_pc);
109 return -EINVAL;
110 }
5e13eb3c
MD
111 } else {
112 hlist_add_head(&mp_node->node, head);
07dfc1d0 113 }
07dfc1d0
MD
114 return 0;
115}
116
117/*
118 * Binary comparators use top of stack and top of stack -1.
119 */
120static
02aca193
PP
121int bin_op_compare_check(struct vstack *stack, const filter_opcode_t opcode,
122 const char *str)
07dfc1d0
MD
123{
124 if (unlikely(!vstack_ax(stack) || !vstack_bx(stack)))
125 goto error_unknown;
126
127 switch (vstack_ax(stack)->type) {
128 default:
129 case REG_DOUBLE:
130 goto error_unknown;
131
132 case REG_STRING:
133 switch (vstack_bx(stack)->type) {
134 default:
135 case REG_DOUBLE:
136 goto error_unknown;
137
138 case REG_STRING:
139 break;
02aca193
PP
140 case REG_STAR_GLOB_STRING:
141 if (opcode != FILTER_OP_EQ && opcode != FILTER_OP_NE) {
142 goto error_mismatch;
143 }
144 break;
145 case REG_S64:
146 goto error_mismatch;
147 }
148 break;
149 case REG_STAR_GLOB_STRING:
150 switch (vstack_bx(stack)->type) {
151 default:
152 case REG_DOUBLE:
153 goto error_unknown;
154
155 case REG_STRING:
156 if (opcode != FILTER_OP_EQ && opcode != FILTER_OP_NE) {
157 goto error_mismatch;
158 }
159 break;
160 case REG_STAR_GLOB_STRING:
07dfc1d0
MD
161 case REG_S64:
162 goto error_mismatch;
163 }
164 break;
165 case REG_S64:
166 switch (vstack_bx(stack)->type) {
167 default:
168 case REG_DOUBLE:
169 goto error_unknown;
170
171 case REG_STRING:
02aca193 172 case REG_STAR_GLOB_STRING:
07dfc1d0
MD
173 goto error_mismatch;
174
175 case REG_S64:
176 break;
177 }
178 break;
179 }
180 return 0;
181
182error_unknown:
183 return -EINVAL;
184
185error_mismatch:
186 printk(KERN_WARNING "type mismatch for '%s' binary operator\n", str);
187 return -EINVAL;
188}
189
190/*
191 * Validate bytecode range overflow within the validation pass.
192 * Called for each instruction encountered.
193 */
194static
195int bytecode_validate_overflow(struct bytecode_runtime *bytecode,
7962cb86 196 char *start_pc, char *pc)
07dfc1d0
MD
197{
198 int ret = 0;
199
200 switch (*(filter_opcode_t *) pc) {
201 case FILTER_OP_UNKNOWN:
202 default:
203 {
204 printk(KERN_WARNING "unknown bytecode op %u\n",
205 (unsigned int) *(filter_opcode_t *) pc);
206 ret = -EINVAL;
207 break;
208 }
209
210 case FILTER_OP_RETURN:
211 {
212 if (unlikely(pc + sizeof(struct return_op)
213 > start_pc + bytecode->len)) {
214 ret = -ERANGE;
215 }
216 break;
217 }
218
219 /* binary */
220 case FILTER_OP_MUL:
221 case FILTER_OP_DIV:
222 case FILTER_OP_MOD:
223 case FILTER_OP_PLUS:
224 case FILTER_OP_MINUS:
225 case FILTER_OP_RSHIFT:
226 case FILTER_OP_LSHIFT:
227 case FILTER_OP_BIN_AND:
228 case FILTER_OP_BIN_OR:
229 case FILTER_OP_BIN_XOR:
230 case FILTER_OP_EQ_DOUBLE:
231 case FILTER_OP_NE_DOUBLE:
232 case FILTER_OP_GT_DOUBLE:
233 case FILTER_OP_LT_DOUBLE:
234 case FILTER_OP_GE_DOUBLE:
235 case FILTER_OP_LE_DOUBLE:
236 /* Floating point */
237 case FILTER_OP_EQ_DOUBLE_S64:
238 case FILTER_OP_NE_DOUBLE_S64:
239 case FILTER_OP_GT_DOUBLE_S64:
240 case FILTER_OP_LT_DOUBLE_S64:
241 case FILTER_OP_GE_DOUBLE_S64:
242 case FILTER_OP_LE_DOUBLE_S64:
243 case FILTER_OP_EQ_S64_DOUBLE:
244 case FILTER_OP_NE_S64_DOUBLE:
245 case FILTER_OP_GT_S64_DOUBLE:
246 case FILTER_OP_LT_S64_DOUBLE:
247 case FILTER_OP_GE_S64_DOUBLE:
248 case FILTER_OP_LE_S64_DOUBLE:
249 case FILTER_OP_LOAD_FIELD_REF_DOUBLE:
250 case FILTER_OP_GET_CONTEXT_REF_DOUBLE:
251 case FILTER_OP_LOAD_DOUBLE:
252 case FILTER_OP_CAST_DOUBLE_TO_S64:
253 case FILTER_OP_UNARY_PLUS_DOUBLE:
254 case FILTER_OP_UNARY_MINUS_DOUBLE:
255 case FILTER_OP_UNARY_NOT_DOUBLE:
256 {
257 printk(KERN_WARNING "unsupported bytecode op %u\n",
258 (unsigned int) *(filter_opcode_t *) pc);
259 ret = -EINVAL;
260 break;
261 }
262
263 case FILTER_OP_EQ:
264 case FILTER_OP_NE:
265 case FILTER_OP_GT:
266 case FILTER_OP_LT:
267 case FILTER_OP_GE:
268 case FILTER_OP_LE:
269 case FILTER_OP_EQ_STRING:
270 case FILTER_OP_NE_STRING:
271 case FILTER_OP_GT_STRING:
272 case FILTER_OP_LT_STRING:
273 case FILTER_OP_GE_STRING:
274 case FILTER_OP_LE_STRING:
02aca193
PP
275 case FILTER_OP_EQ_STAR_GLOB_STRING:
276 case FILTER_OP_NE_STAR_GLOB_STRING:
07dfc1d0
MD
277 case FILTER_OP_EQ_S64:
278 case FILTER_OP_NE_S64:
279 case FILTER_OP_GT_S64:
280 case FILTER_OP_LT_S64:
281 case FILTER_OP_GE_S64:
282 case FILTER_OP_LE_S64:
283 {
284 if (unlikely(pc + sizeof(struct binary_op)
285 > start_pc + bytecode->len)) {
286 ret = -ERANGE;
287 }
288 break;
289 }
290
291 /* unary */
292 case FILTER_OP_UNARY_PLUS:
293 case FILTER_OP_UNARY_MINUS:
294 case FILTER_OP_UNARY_NOT:
295 case FILTER_OP_UNARY_PLUS_S64:
296 case FILTER_OP_UNARY_MINUS_S64:
297 case FILTER_OP_UNARY_NOT_S64:
298 {
299 if (unlikely(pc + sizeof(struct unary_op)
300 > start_pc + bytecode->len)) {
301 ret = -ERANGE;
302 }
303 break;
304 }
305
306 /* logical */
307 case FILTER_OP_AND:
308 case FILTER_OP_OR:
309 {
310 if (unlikely(pc + sizeof(struct logical_op)
311 > start_pc + bytecode->len)) {
312 ret = -ERANGE;
313 }
314 break;
315 }
316
317 /* load field ref */
318 case FILTER_OP_LOAD_FIELD_REF:
319 {
320 printk(KERN_WARNING "Unknown field ref type\n");
321 ret = -EINVAL;
322 break;
323 }
324 /* get context ref */
325 case FILTER_OP_GET_CONTEXT_REF:
326 {
327 printk(KERN_WARNING "Unknown field ref type\n");
328 ret = -EINVAL;
329 break;
330 }
331 case FILTER_OP_LOAD_FIELD_REF_STRING:
332 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
f127e61e
MD
333 case FILTER_OP_LOAD_FIELD_REF_USER_STRING:
334 case FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE:
07dfc1d0
MD
335 case FILTER_OP_LOAD_FIELD_REF_S64:
336 case FILTER_OP_GET_CONTEXT_REF_STRING:
337 case FILTER_OP_GET_CONTEXT_REF_S64:
338 {
339 if (unlikely(pc + sizeof(struct load_op) + sizeof(struct field_ref)
340 > start_pc + bytecode->len)) {
341 ret = -ERANGE;
342 }
343 break;
344 }
345
346 /* load from immediate operand */
347 case FILTER_OP_LOAD_STRING:
02aca193 348 case FILTER_OP_LOAD_STAR_GLOB_STRING:
07dfc1d0
MD
349 {
350 struct load_op *insn = (struct load_op *) pc;
351 uint32_t str_len, maxlen;
352
353 if (unlikely(pc + sizeof(struct load_op)
354 > start_pc + bytecode->len)) {
355 ret = -ERANGE;
356 break;
357 }
358
359 maxlen = start_pc + bytecode->len - pc - sizeof(struct load_op);
360 str_len = strnlen(insn->data, maxlen);
361 if (unlikely(str_len >= maxlen)) {
362 /* Final '\0' not found within range */
363 ret = -ERANGE;
364 }
365 break;
366 }
367
368 case FILTER_OP_LOAD_S64:
369 {
370 if (unlikely(pc + sizeof(struct load_op) + sizeof(struct literal_numeric)
371 > start_pc + bytecode->len)) {
372 ret = -ERANGE;
373 }
374 break;
375 }
376
377 case FILTER_OP_CAST_TO_S64:
378 case FILTER_OP_CAST_NOP:
379 {
380 if (unlikely(pc + sizeof(struct cast_op)
381 > start_pc + bytecode->len)) {
382 ret = -ERANGE;
383 }
384 break;
385 }
386
387 }
388
389 return ret;
390}
391
392static
393unsigned long delete_all_nodes(struct mp_table *mp_table)
394{
395 struct mp_node *mp_node;
396 struct hlist_node *tmp;
397 unsigned long nr_nodes = 0;
398 int i;
399
400 for (i = 0; i < MERGE_POINT_TABLE_SIZE; i++) {
401 struct hlist_head *head;
402
403 head = &mp_table->mp_head[i];
d216ecae 404 lttng_hlist_for_each_entry_safe(mp_node, tmp, head, node) {
07dfc1d0
MD
405 kfree(mp_node);
406 nr_nodes++;
407 }
408 }
409 return nr_nodes;
410}
411
412/*
413 * Return value:
414 * 0: success
415 * <0: error
416 */
417static
418int validate_instruction_context(struct bytecode_runtime *bytecode,
419 struct vstack *stack,
7962cb86
MD
420 char *start_pc,
421 char *pc)
07dfc1d0
MD
422{
423 int ret = 0;
02aca193 424 const filter_opcode_t opcode = *(filter_opcode_t *) pc;
07dfc1d0 425
02aca193 426 switch (opcode) {
07dfc1d0
MD
427 case FILTER_OP_UNKNOWN:
428 default:
429 {
430 printk(KERN_WARNING "unknown bytecode op %u\n",
431 (unsigned int) *(filter_opcode_t *) pc);
432 ret = -EINVAL;
433 goto end;
434 }
435
436 case FILTER_OP_RETURN:
437 {
438 goto end;
439 }
440
441 /* binary */
442 case FILTER_OP_MUL:
443 case FILTER_OP_DIV:
444 case FILTER_OP_MOD:
445 case FILTER_OP_PLUS:
446 case FILTER_OP_MINUS:
447 case FILTER_OP_RSHIFT:
448 case FILTER_OP_LSHIFT:
449 case FILTER_OP_BIN_AND:
450 case FILTER_OP_BIN_OR:
451 case FILTER_OP_BIN_XOR:
452 /* Floating point */
453 case FILTER_OP_EQ_DOUBLE:
454 case FILTER_OP_NE_DOUBLE:
455 case FILTER_OP_GT_DOUBLE:
456 case FILTER_OP_LT_DOUBLE:
457 case FILTER_OP_GE_DOUBLE:
458 case FILTER_OP_LE_DOUBLE:
459 case FILTER_OP_EQ_DOUBLE_S64:
460 case FILTER_OP_NE_DOUBLE_S64:
461 case FILTER_OP_GT_DOUBLE_S64:
462 case FILTER_OP_LT_DOUBLE_S64:
463 case FILTER_OP_GE_DOUBLE_S64:
464 case FILTER_OP_LE_DOUBLE_S64:
465 case FILTER_OP_EQ_S64_DOUBLE:
466 case FILTER_OP_NE_S64_DOUBLE:
467 case FILTER_OP_GT_S64_DOUBLE:
468 case FILTER_OP_LT_S64_DOUBLE:
469 case FILTER_OP_GE_S64_DOUBLE:
470 case FILTER_OP_LE_S64_DOUBLE:
471 case FILTER_OP_UNARY_PLUS_DOUBLE:
472 case FILTER_OP_UNARY_MINUS_DOUBLE:
473 case FILTER_OP_UNARY_NOT_DOUBLE:
474 case FILTER_OP_LOAD_FIELD_REF_DOUBLE:
475 case FILTER_OP_LOAD_DOUBLE:
476 case FILTER_OP_CAST_DOUBLE_TO_S64:
477 case FILTER_OP_GET_CONTEXT_REF_DOUBLE:
478 {
479 printk(KERN_WARNING "unsupported bytecode op %u\n",
480 (unsigned int) *(filter_opcode_t *) pc);
481 ret = -EINVAL;
482 goto end;
483 }
484
485 case FILTER_OP_EQ:
486 {
02aca193 487 ret = bin_op_compare_check(stack, opcode, "==");
07dfc1d0
MD
488 if (ret)
489 goto end;
490 break;
491 }
492 case FILTER_OP_NE:
493 {
02aca193 494 ret = bin_op_compare_check(stack, opcode, "!=");
07dfc1d0
MD
495 if (ret)
496 goto end;
497 break;
498 }
499 case FILTER_OP_GT:
500 {
02aca193 501 ret = bin_op_compare_check(stack, opcode, ">");
07dfc1d0
MD
502 if (ret)
503 goto end;
504 break;
505 }
506 case FILTER_OP_LT:
507 {
02aca193 508 ret = bin_op_compare_check(stack, opcode, "<");
07dfc1d0
MD
509 if (ret)
510 goto end;
511 break;
512 }
513 case FILTER_OP_GE:
514 {
02aca193 515 ret = bin_op_compare_check(stack, opcode, ">=");
07dfc1d0
MD
516 if (ret)
517 goto end;
518 break;
519 }
520 case FILTER_OP_LE:
521 {
02aca193 522 ret = bin_op_compare_check(stack, opcode, "<=");
07dfc1d0
MD
523 if (ret)
524 goto end;
525 break;
526 }
527
528 case FILTER_OP_EQ_STRING:
529 case FILTER_OP_NE_STRING:
530 case FILTER_OP_GT_STRING:
531 case FILTER_OP_LT_STRING:
532 case FILTER_OP_GE_STRING:
533 case FILTER_OP_LE_STRING:
534 {
535 if (!vstack_ax(stack) || !vstack_bx(stack)) {
536 printk(KERN_WARNING "Empty stack\n");
537 ret = -EINVAL;
538 goto end;
539 }
540 if (vstack_ax(stack)->type != REG_STRING
541 || vstack_bx(stack)->type != REG_STRING) {
542 printk(KERN_WARNING "Unexpected register type for string comparator\n");
543 ret = -EINVAL;
544 goto end;
545 }
546 break;
547 }
548
02aca193
PP
549
550 case FILTER_OP_EQ_STAR_GLOB_STRING:
551 case FILTER_OP_NE_STAR_GLOB_STRING:
552 {
553 if (!vstack_ax(stack) || !vstack_bx(stack)) {
554 printk(KERN_WARNING "Empty stack\n");
555 ret = -EINVAL;
556 goto end;
557 }
558 if (vstack_ax(stack)->type != REG_STAR_GLOB_STRING
559 && vstack_bx(stack)->type != REG_STAR_GLOB_STRING) {
560 printk(KERN_WARNING "Unexpected register type for globbing pattern comparator\n");
561 ret = -EINVAL;
562 goto end;
563 }
564 break;
565 }
566
07dfc1d0
MD
567 case FILTER_OP_EQ_S64:
568 case FILTER_OP_NE_S64:
569 case FILTER_OP_GT_S64:
570 case FILTER_OP_LT_S64:
571 case FILTER_OP_GE_S64:
572 case FILTER_OP_LE_S64:
573 {
574 if (!vstack_ax(stack) || !vstack_bx(stack)) {
575 printk(KERN_WARNING "Empty stack\n");
576 ret = -EINVAL;
577 goto end;
578 }
579 if (vstack_ax(stack)->type != REG_S64
580 || vstack_bx(stack)->type != REG_S64) {
581 printk(KERN_WARNING "Unexpected register type for s64 comparator\n");
582 ret = -EINVAL;
583 goto end;
584 }
585 break;
586 }
587
588 /* unary */
589 case FILTER_OP_UNARY_PLUS:
590 case FILTER_OP_UNARY_MINUS:
591 case FILTER_OP_UNARY_NOT:
592 {
593 if (!vstack_ax(stack)) {
594 printk(KERN_WARNING "Empty stack\n");
595 ret = -EINVAL;
596 goto end;
597 }
598 switch (vstack_ax(stack)->type) {
599 default:
600 case REG_DOUBLE:
601 printk(KERN_WARNING "unknown register type\n");
602 ret = -EINVAL;
603 goto end;
604
605 case REG_STRING:
02aca193 606 case REG_STAR_GLOB_STRING:
07dfc1d0
MD
607 printk(KERN_WARNING "Unary op can only be applied to numeric or floating point registers\n");
608 ret = -EINVAL;
609 goto end;
610 case REG_S64:
611 break;
612 }
613 break;
614 }
615
616 case FILTER_OP_UNARY_PLUS_S64:
617 case FILTER_OP_UNARY_MINUS_S64:
618 case FILTER_OP_UNARY_NOT_S64:
619 {
620 if (!vstack_ax(stack)) {
621 printk(KERN_WARNING "Empty stack\n");
622 ret = -EINVAL;
623 goto end;
624 }
625 if (vstack_ax(stack)->type != REG_S64) {
626 printk(KERN_WARNING "Invalid register type\n");
627 ret = -EINVAL;
628 goto end;
629 }
630 break;
631 }
632
633 /* logical */
634 case FILTER_OP_AND:
635 case FILTER_OP_OR:
636 {
637 struct logical_op *insn = (struct logical_op *) pc;
638
639 if (!vstack_ax(stack)) {
640 printk(KERN_WARNING "Empty stack\n");
641 ret = -EINVAL;
642 goto end;
643 }
644 if (vstack_ax(stack)->type != REG_S64) {
645 printk(KERN_WARNING "Logical comparator expects S64 register\n");
646 ret = -EINVAL;
647 goto end;
648 }
649
650 dbg_printk("Validate jumping to bytecode offset %u\n",
651 (unsigned int) insn->skip_offset);
652 if (unlikely(start_pc + insn->skip_offset <= pc)) {
653 printk(KERN_WARNING "Loops are not allowed in bytecode\n");
654 ret = -EINVAL;
655 goto end;
656 }
657 break;
658 }
659
660 /* load field ref */
661 case FILTER_OP_LOAD_FIELD_REF:
662 {
663 printk(KERN_WARNING "Unknown field ref type\n");
664 ret = -EINVAL;
665 goto end;
666 }
667 case FILTER_OP_LOAD_FIELD_REF_STRING:
668 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
f127e61e
MD
669 case FILTER_OP_LOAD_FIELD_REF_USER_STRING:
670 case FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE:
07dfc1d0
MD
671 {
672 struct load_op *insn = (struct load_op *) pc;
673 struct field_ref *ref = (struct field_ref *) insn->data;
674
675 dbg_printk("Validate load field ref offset %u type string\n",
676 ref->offset);
677 break;
678 }
679 case FILTER_OP_LOAD_FIELD_REF_S64:
680 {
681 struct load_op *insn = (struct load_op *) pc;
682 struct field_ref *ref = (struct field_ref *) insn->data;
683
684 dbg_printk("Validate load field ref offset %u type s64\n",
685 ref->offset);
686 break;
687 }
688
689 /* load from immediate operand */
690 case FILTER_OP_LOAD_STRING:
02aca193 691 case FILTER_OP_LOAD_STAR_GLOB_STRING:
07dfc1d0
MD
692 {
693 break;
694 }
695
696 case FILTER_OP_LOAD_S64:
697 {
698 break;
699 }
700
701 case FILTER_OP_CAST_TO_S64:
702 {
703 struct cast_op *insn = (struct cast_op *) pc;
704
705 if (!vstack_ax(stack)) {
706 printk(KERN_WARNING "Empty stack\n");
707 ret = -EINVAL;
708 goto end;
709 }
710 switch (vstack_ax(stack)->type) {
711 default:
712 case REG_DOUBLE:
713 printk(KERN_WARNING "unknown register type\n");
714 ret = -EINVAL;
715 goto end;
716
717 case REG_STRING:
02aca193 718 case REG_STAR_GLOB_STRING:
07dfc1d0
MD
719 printk(KERN_WARNING "Cast op can only be applied to numeric or floating point registers\n");
720 ret = -EINVAL;
721 goto end;
722 case REG_S64:
723 break;
724 }
725 if (insn->op == FILTER_OP_CAST_DOUBLE_TO_S64) {
726 if (vstack_ax(stack)->type != REG_DOUBLE) {
727 printk(KERN_WARNING "Cast expects double\n");
728 ret = -EINVAL;
729 goto end;
730 }
731 }
732 break;
733 }
734 case FILTER_OP_CAST_NOP:
735 {
736 break;
737 }
738
739 /* get context ref */
740 case FILTER_OP_GET_CONTEXT_REF:
741 {
742 printk(KERN_WARNING "Unknown get context ref type\n");
743 ret = -EINVAL;
744 goto end;
745 }
746 case FILTER_OP_GET_CONTEXT_REF_STRING:
747 {
748 struct load_op *insn = (struct load_op *) pc;
749 struct field_ref *ref = (struct field_ref *) insn->data;
750
751 dbg_printk("Validate get context ref offset %u type string\n",
752 ref->offset);
753 break;
754 }
755 case FILTER_OP_GET_CONTEXT_REF_S64:
756 {
757 struct load_op *insn = (struct load_op *) pc;
758 struct field_ref *ref = (struct field_ref *) insn->data;
759
760 dbg_printk("Validate get context ref offset %u type s64\n",
761 ref->offset);
762 break;
763 }
764
765 }
766end:
767 return ret;
768}
769
770/*
771 * Return value:
772 * 0: success
773 * <0: error
774 */
775static
776int validate_instruction_all_contexts(struct bytecode_runtime *bytecode,
777 struct mp_table *mp_table,
778 struct vstack *stack,
7962cb86
MD
779 char *start_pc,
780 char *pc)
07dfc1d0
MD
781{
782 int ret, found = 0;
783 unsigned long target_pc = pc - start_pc;
784 unsigned long hash;
785 struct hlist_head *head;
786 struct mp_node *mp_node;
787
788 /* Validate the context resulting from the previous instruction */
789 ret = validate_instruction_context(bytecode, stack, start_pc, pc);
790 if (ret)
791 return ret;
792
793 /* Validate merge points */
794 hash = jhash_1word(target_pc, 0);
795 head = &mp_table->mp_head[hash & (MERGE_POINT_TABLE_SIZE - 1)];
d216ecae 796 lttng_hlist_for_each_entry(mp_node, head, node) {
07dfc1d0
MD
797 if (lttng_hash_match(mp_node, target_pc)) {
798 found = 1;
799 break;
800 }
801 }
802 if (found) {
803 dbg_printk("Filter: validate merge point at offset %lu\n",
804 target_pc);
805 if (merge_points_compare(stack, &mp_node->stack)) {
806 printk(KERN_WARNING "Merge points differ for offset %lu\n",
807 target_pc);
808 return -EINVAL;
809 }
810 /* Once validated, we can remove the merge point */
811 dbg_printk("Filter: remove merge point at offset %lu\n",
812 target_pc);
813 hlist_del(&mp_node->node);
814 }
815 return 0;
816}
817
818/*
819 * Return value:
820 * >0: going to next insn.
821 * 0: success, stop iteration.
822 * <0: error
823 */
824static
825int exec_insn(struct bytecode_runtime *bytecode,
826 struct mp_table *mp_table,
827 struct vstack *stack,
7962cb86
MD
828 char **_next_pc,
829 char *pc)
07dfc1d0
MD
830{
831 int ret = 1;
7962cb86 832 char *next_pc = *_next_pc;
07dfc1d0
MD
833
834 switch (*(filter_opcode_t *) pc) {
835 case FILTER_OP_UNKNOWN:
836 default:
837 {
838 printk(KERN_WARNING "unknown bytecode op %u\n",
839 (unsigned int) *(filter_opcode_t *) pc);
840 ret = -EINVAL;
841 goto end;
842 }
843
844 case FILTER_OP_RETURN:
845 {
846 if (!vstack_ax(stack)) {
847 printk(KERN_WARNING "Empty stack\n");
848 ret = -EINVAL;
849 goto end;
850 }
851 ret = 0;
852 goto end;
853 }
854
855 /* binary */
856 case FILTER_OP_MUL:
857 case FILTER_OP_DIV:
858 case FILTER_OP_MOD:
859 case FILTER_OP_PLUS:
860 case FILTER_OP_MINUS:
861 case FILTER_OP_RSHIFT:
862 case FILTER_OP_LSHIFT:
863 case FILTER_OP_BIN_AND:
864 case FILTER_OP_BIN_OR:
865 case FILTER_OP_BIN_XOR:
866 /* Floating point */
867 case FILTER_OP_EQ_DOUBLE:
868 case FILTER_OP_NE_DOUBLE:
869 case FILTER_OP_GT_DOUBLE:
870 case FILTER_OP_LT_DOUBLE:
871 case FILTER_OP_GE_DOUBLE:
872 case FILTER_OP_LE_DOUBLE:
873 case FILTER_OP_EQ_DOUBLE_S64:
874 case FILTER_OP_NE_DOUBLE_S64:
875 case FILTER_OP_GT_DOUBLE_S64:
876 case FILTER_OP_LT_DOUBLE_S64:
877 case FILTER_OP_GE_DOUBLE_S64:
878 case FILTER_OP_LE_DOUBLE_S64:
879 case FILTER_OP_EQ_S64_DOUBLE:
880 case FILTER_OP_NE_S64_DOUBLE:
881 case FILTER_OP_GT_S64_DOUBLE:
882 case FILTER_OP_LT_S64_DOUBLE:
883 case FILTER_OP_GE_S64_DOUBLE:
884 case FILTER_OP_LE_S64_DOUBLE:
885 case FILTER_OP_UNARY_PLUS_DOUBLE:
886 case FILTER_OP_UNARY_MINUS_DOUBLE:
887 case FILTER_OP_UNARY_NOT_DOUBLE:
888 case FILTER_OP_LOAD_FIELD_REF_DOUBLE:
889 case FILTER_OP_GET_CONTEXT_REF_DOUBLE:
890 case FILTER_OP_LOAD_DOUBLE:
891 case FILTER_OP_CAST_DOUBLE_TO_S64:
892 {
893 printk(KERN_WARNING "unsupported bytecode op %u\n",
894 (unsigned int) *(filter_opcode_t *) pc);
895 ret = -EINVAL;
896 goto end;
897 }
898
899 case FILTER_OP_EQ:
900 case FILTER_OP_NE:
901 case FILTER_OP_GT:
902 case FILTER_OP_LT:
903 case FILTER_OP_GE:
904 case FILTER_OP_LE:
905 case FILTER_OP_EQ_STRING:
906 case FILTER_OP_NE_STRING:
907 case FILTER_OP_GT_STRING:
908 case FILTER_OP_LT_STRING:
909 case FILTER_OP_GE_STRING:
910 case FILTER_OP_LE_STRING:
02aca193
PP
911 case FILTER_OP_EQ_STAR_GLOB_STRING:
912 case FILTER_OP_NE_STAR_GLOB_STRING:
07dfc1d0
MD
913 case FILTER_OP_EQ_S64:
914 case FILTER_OP_NE_S64:
915 case FILTER_OP_GT_S64:
916 case FILTER_OP_LT_S64:
917 case FILTER_OP_GE_S64:
918 case FILTER_OP_LE_S64:
919 {
920 /* Pop 2, push 1 */
921 if (vstack_pop(stack)) {
922 ret = -EINVAL;
923 goto end;
924 }
925 if (!vstack_ax(stack)) {
926 printk(KERN_WARNING "Empty stack\n");
927 ret = -EINVAL;
928 goto end;
929 }
930 vstack_ax(stack)->type = REG_S64;
931 next_pc += sizeof(struct binary_op);
932 break;
933 }
934
935 /* unary */
936 case FILTER_OP_UNARY_PLUS:
937 case FILTER_OP_UNARY_MINUS:
938 case FILTER_OP_UNARY_NOT:
939 case FILTER_OP_UNARY_PLUS_S64:
940 case FILTER_OP_UNARY_MINUS_S64:
941 case FILTER_OP_UNARY_NOT_S64:
942 {
943 /* Pop 1, push 1 */
944 if (!vstack_ax(stack)) {
945 printk(KERN_WARNING "Empty stack\n");
946 ret = -EINVAL;
947 goto end;
948 }
949 vstack_ax(stack)->type = REG_S64;
950 next_pc += sizeof(struct unary_op);
951 break;
952 }
953
954 /* logical */
955 case FILTER_OP_AND:
956 case FILTER_OP_OR:
957 {
958 struct logical_op *insn = (struct logical_op *) pc;
959 int merge_ret;
960
961 /* Add merge point to table */
962 merge_ret = merge_point_add_check(mp_table,
963 insn->skip_offset, stack);
964 if (merge_ret) {
965 ret = merge_ret;
966 goto end;
967 }
968 /* Continue to next instruction */
969 /* Pop 1 when jump not taken */
970 if (vstack_pop(stack)) {
971 ret = -EINVAL;
972 goto end;
973 }
974 next_pc += sizeof(struct logical_op);
975 break;
976 }
977
978 /* load field ref */
979 case FILTER_OP_LOAD_FIELD_REF:
980 {
981 printk(KERN_WARNING "Unknown field ref type\n");
982 ret = -EINVAL;
983 goto end;
984 }
985 /* get context ref */
986 case FILTER_OP_GET_CONTEXT_REF:
987 {
988 printk(KERN_WARNING "Unknown get context ref type\n");
989 ret = -EINVAL;
990 goto end;
991 }
992 case FILTER_OP_LOAD_FIELD_REF_STRING:
993 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
994 case FILTER_OP_GET_CONTEXT_REF_STRING:
f127e61e
MD
995 case FILTER_OP_LOAD_FIELD_REF_USER_STRING:
996 case FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE:
07dfc1d0
MD
997 {
998 if (vstack_push(stack)) {
999 ret = -EINVAL;
1000 goto end;
1001 }
1002 vstack_ax(stack)->type = REG_STRING;
1003 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
1004 break;
1005 }
1006 case FILTER_OP_LOAD_FIELD_REF_S64:
1007 case FILTER_OP_GET_CONTEXT_REF_S64:
1008 {
1009 if (vstack_push(stack)) {
1010 ret = -EINVAL;
1011 goto end;
1012 }
1013 vstack_ax(stack)->type = REG_S64;
1014 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
1015 break;
1016 }
1017
1018 /* load from immediate operand */
1019 case FILTER_OP_LOAD_STRING:
1020 {
1021 struct load_op *insn = (struct load_op *) pc;
1022
1023 if (vstack_push(stack)) {
1024 ret = -EINVAL;
1025 goto end;
1026 }
1027 vstack_ax(stack)->type = REG_STRING;
1028 next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
02aca193
PP
1029 break;
1030 }
1031
1032 case FILTER_OP_LOAD_STAR_GLOB_STRING:
1033 {
1034 struct load_op *insn = (struct load_op *) pc;
1035
1036 if (vstack_push(stack)) {
1037 ret = -EINVAL;
1038 goto end;
1039 }
1040 vstack_ax(stack)->type = REG_STAR_GLOB_STRING;
1041 next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
07dfc1d0
MD
1042 break;
1043 }
1044
1045 case FILTER_OP_LOAD_S64:
1046 {
1047 if (vstack_push(stack)) {
1048 ret = -EINVAL;
1049 goto end;
1050 }
1051 vstack_ax(stack)->type = REG_S64;
1052 next_pc += sizeof(struct load_op)
1053 + sizeof(struct literal_numeric);
1054 break;
1055 }
1056
1057 case FILTER_OP_CAST_TO_S64:
1058 {
1059 /* Pop 1, push 1 */
1060 if (!vstack_ax(stack)) {
1061 printk(KERN_WARNING "Empty stack\n");
1062 ret = -EINVAL;
1063 goto end;
1064 }
1065 vstack_ax(stack)->type = REG_S64;
1066 next_pc += sizeof(struct cast_op);
1067 break;
1068 }
1069 case FILTER_OP_CAST_NOP:
1070 {
1071 next_pc += sizeof(struct cast_op);
1072 break;
1073 }
1074
1075 }
1076end:
1077 *_next_pc = next_pc;
1078 return ret;
1079}
1080
1081/*
1082 * Never called concurrently (hash seed is shared).
1083 */
1084int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode)
1085{
1086 struct mp_table *mp_table;
7962cb86 1087 char *pc, *next_pc, *start_pc;
07dfc1d0
MD
1088 int ret = -EINVAL;
1089 struct vstack stack;
1090
1091 vstack_init(&stack);
1092
1093 mp_table = kzalloc(sizeof(*mp_table), GFP_KERNEL);
1094 if (!mp_table) {
1095 printk(KERN_WARNING "Error allocating hash table for bytecode validation\n");
1096 return -ENOMEM;
1097 }
1098 start_pc = &bytecode->data[0];
1099 for (pc = next_pc = start_pc; pc - start_pc < bytecode->len;
1100 pc = next_pc) {
1101 ret = bytecode_validate_overflow(bytecode, start_pc, pc);
1102 if (ret != 0) {
1103 if (ret == -ERANGE)
1104 printk(KERN_WARNING "filter bytecode overflow\n");
1105 goto end;
1106 }
1107 dbg_printk("Validating op %s (%u)\n",
1108 lttng_filter_print_op((unsigned int) *(filter_opcode_t *) pc),
1109 (unsigned int) *(filter_opcode_t *) pc);
1110
1111 /*
1112 * For each instruction, validate the current context
1113 * (traversal of entire execution flow), and validate
1114 * all merge points targeting this instruction.
1115 */
1116 ret = validate_instruction_all_contexts(bytecode, mp_table,
1117 &stack, start_pc, pc);
1118 if (ret)
1119 goto end;
1120 ret = exec_insn(bytecode, mp_table, &stack, &next_pc, pc);
1121 if (ret <= 0)
1122 goto end;
1123 }
1124end:
1125 if (delete_all_nodes(mp_table)) {
1126 if (!ret) {
1127 printk(KERN_WARNING "Unexpected merge points\n");
1128 ret = -EINVAL;
1129 }
1130 }
1131 kfree(mp_table);
1132 return ret;
1133}
This page took 0.069688 seconds and 4 git commands to generate.