/* The code in this file serves the sole purpose of executing test cases * specified in the test_cases array. Each test case specifies a program * type, context field offset, and disassembly patterns that correspond * to read and write instructions generated by * verifier.c:convert_ctx_access() for accessing that field. * * For each test case, up to three programs are created: * - One that uses BPF_LDX_MEM to read the context field. * - One that uses BPF_STX_MEM to write to the context field. * - One that uses BPF_ST_MEM to write to the context field. * * The disassembly of each program is then compared with the pattern * specified in the test case.
*/ struct test_case { char *name; enum bpf_prog_type prog_type; enum bpf_attach_type expected_attach_type; int field_offset; int field_sz; /* Program generated for BPF_ST_MEM uses value 42 by default, * this field allows to specify custom value.
*/ struct { bool use; int value;
} st_value; /* Pattern for BPF_LDX_MEM(field_sz, dst, ctx, field_offset) */ char *read; /* Pattern for BPF_STX_MEM(field_sz, ctx, src, field_offset) and * BPF_ST_MEM (field_sz, ctx, src, field_offset)
*/ char *write; /* Pattern for BPF_ST_MEM(field_sz, ctx, src, field_offset), * takes priority over `write`.
*/ char *write_st; /* Pattern for BPF_STX_MEM (field_sz, ctx, src, field_offset), * takes priority over `write`.
*/ char *write_stx;
};
while (next) {
next = strchr(str, '\n'); if (next) {
max_line = max_t(u32, max_line, (next - str));
str = next + 1;
} else {
max_line = max_t(u32, max_line, strlen(str));
}
}
return min(max_line, 60u);
}
/* Print strings `pattern_origin` and `text_origin` side by side, * assume `pattern_pos` and `text_pos` designate location within * corresponding origin string where match diverges. * The output should look like: * * Can't match disassembly(left) with pattern(right): * r2 = *(u64 *)(r1 +0) ; $dst = *(u64 *)($ctx + bpf_sockopt_kern::sk1) * ^ ^ * r0 = 0 ; * exit ;
*/ staticvoid print_match_error(FILE *out, char *pattern_origin, char *text_origin, char *pattern_pos, char *text_pos)
{ char *pattern = pattern_origin; char *text = text_origin; int middle = max_line_len(text) + 2;
fprintf(out, "Can't match disassembly(left) with pattern(right):\n"); while (*pattern || *text) { int column = 0; int mark1 = -1; int mark2 = -1;
/* Print one line from text */ while (*text && *text != '\n') { if (text == text_pos)
mark1 = column;
fputc(*text, out);
++text;
++column;
} if (text == text_pos)
mark1 = column;
/* Pad to the middle */ while (column < middle) {
fputc(' ', out);
++column;
}
fputs("; ", out);
column += 3;
/* Print one line from pattern, pattern lines are terminated by ';' */ while (*pattern && *pattern != ';') { if (pattern == pattern_pos)
mark2 = column;
fputc(*pattern, out);
++pattern;
++column;
} if (pattern == pattern_pos)
mark2 = column;
fputc('\n', out); if (*pattern)
++pattern; if (*text)
++text;
/* If pattern and text diverge at this line, print an * additional line with '^' marks, highlighting * positions where match fails.
*/ if (mark1 > 0 || mark2 > 0) { for (column = 0; column <= max(mark1, mark2); ++column) { if (column == mark1 || column == mark2)
fputc('^', out); else
fputc(' ', out);
}
fputc('\n', out);
}
}
}
/* Test if `text` matches `pattern`. Pattern consists of the following elements: * * - Field offset references: * * <type>::<field> * * When such reference is encountered BTF is used to compute numerical * value for the offset of <field> in <type>. The `text` is expected to * contain matching numerical value. * * - Field groups: * * $(<type>::<field> [+ <type>::<field>]*) * * Allows to specify an offset that is a sum of multiple field offsets. * The `text` is expected to contain matching numerical value. * * - Variable references, e.g. `$src`, `$dst`, `$ctx`. * These are substitutions specified in `reg_map` array. * If a substring of pattern is equal to `reg_map[i][0]` the `text` is * expected to contain `reg_map[i][1]` in the matching position. * * - Whitespace is ignored, ';' counts as whitespace for `pattern`. * * - Any other characters, `pattern` and `text` should match one-to-one. * * Example of a pattern: * * __________ fields group ________________ * ' ' * *(u16 *)($ctx + $(sk_buff::cb + qdisc_skb_cb::tc_classid)) = $src; * ^^^^ '______________________' * variable reference field offset reference
*/ staticbool match_pattern(struct btf *btf, char *pattern, char *text, char *reg_map[][2])
{ char *pattern_origin = pattern; char *text_origin = text;
regmatch_t matches[3];
_continue: while (*pattern) { if (!*text) goto err;
/* Skip whitespace */ if (isspace(*pattern) || *pattern == ';') { if (!isspace(*text) && text != text_origin && isalnum(text[-1])) goto err;
pattern = skip_space_and_semi(pattern);
text = skip_space(text); continue;
}
/* Check for variable references */ for (int i = 0; reg_map[i][0]; ++i) { char *pattern_next, *text_next;
pattern_next = match_str(pattern, reg_map[i][0]); if (!pattern_next) continue;
text_next = match_str(text, reg_map[i][1]); if (!text_next) goto err;
pattern = pattern_next;
text = text_next; goto _continue;
}
/* Match field group: * $(sk_buff::cb + qdisc_skb_cb::tc_classid)
*/ if (strncmp(pattern, "$(", 2) == 0) { char *group_start = pattern, *text_next; int acc_offset = 0;
pattern += 2;
for (;;) { int field_offset;
pattern = skip_space(pattern); if (!*pattern) {
PRINT_FAIL("Unexpected end of pattern\n"); goto err;
}
text_next = match_number(text, field_offset); if (!text_next) {
PRINT_FAIL("No match for field offset %.*s (%d)\n",
(int)matches[0].rm_eo, pattern, field_offset); goto err;
}
pattern += matches[0].rm_eo;
text = text_next; continue;
}
/* If pattern points to identifier not followed by '::' * skip the identifier to avoid n^2 application of the * field reference rule.
*/ if (regexec(ident_regex, pattern, 1, matches, 0) == 0) { if (strncmp(pattern, text, matches[0].rm_eo) != 0) goto err;
pattern += matches[0].rm_eo;
text += matches[0].rm_eo; continue;
}
/* Match literally */ if (*pattern != *text) goto err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.