|
16 | 16 | #include <linux/hid_bpf.h> |
17 | 17 | #include <linux/init.h> |
18 | 18 | #include <linux/module.h> |
| 19 | +#include <linux/stddef.h> |
19 | 20 | #include <linux/workqueue.h> |
20 | 21 | #include "hid_bpf_dispatch.h" |
21 | 22 |
|
@@ -52,40 +53,86 @@ static int hid_bpf_ops_check_member(const struct btf_type *t, |
52 | 53 | return 0; |
53 | 54 | } |
54 | 55 |
|
| 56 | +struct hid_bpf_offset_write_range { |
| 57 | + const char *struct_name; |
| 58 | + u32 struct_length; |
| 59 | + u32 start; |
| 60 | + u32 end; |
| 61 | +}; |
| 62 | + |
55 | 63 | static int hid_bpf_ops_btf_struct_access(struct bpf_verifier_log *log, |
56 | 64 | const struct bpf_reg_state *reg, |
57 | 65 | int off, int size) |
58 | 66 | { |
59 | | - const struct btf_type *state; |
60 | | - const struct btf_type *t; |
61 | | - s32 type_id; |
| 67 | +#define WRITE_RANGE(_name, _field, _is_string) \ |
| 68 | + { \ |
| 69 | + .struct_name = #_name, \ |
| 70 | + .struct_length = sizeof(struct _name), \ |
| 71 | + .start = offsetof(struct _name, _field), \ |
| 72 | + .end = offsetofend(struct _name, _field) - !!(_is_string), \ |
| 73 | + } |
62 | 74 |
|
63 | | - type_id = btf_find_by_name_kind(reg->btf, "hid_bpf_ctx", |
64 | | - BTF_KIND_STRUCT); |
65 | | - if (type_id < 0) |
66 | | - return -EINVAL; |
| 75 | + const struct hid_bpf_offset_write_range write_ranges[] = { |
| 76 | + WRITE_RANGE(hid_bpf_ctx, retval, false), |
| 77 | + }; |
| 78 | +#undef WRITE_RANGE |
| 79 | + const struct btf_type *state = NULL; |
| 80 | + const struct btf_type *t; |
| 81 | + const char *cur = NULL; |
| 82 | + int i; |
67 | 83 |
|
68 | 84 | t = btf_type_by_id(reg->btf, reg->btf_id); |
69 | | - state = btf_type_by_id(reg->btf, type_id); |
70 | | - if (t != state) { |
71 | | - bpf_log(log, "only access to hid_bpf_ctx is supported\n"); |
72 | | - return -EACCES; |
73 | | - } |
74 | 85 |
|
75 | | - /* out-of-bound access in hid_bpf_ctx */ |
76 | | - if (off + size > sizeof(struct hid_bpf_ctx)) { |
77 | | - bpf_log(log, "write access at off %d with size %d\n", off, size); |
78 | | - return -EACCES; |
| 86 | + for (i = 0; i < ARRAY_SIZE(write_ranges); i++) { |
| 87 | + const struct hid_bpf_offset_write_range *write_range = &write_ranges[i]; |
| 88 | + s32 type_id; |
| 89 | + |
| 90 | + /* we already found a writeable struct, but there is a |
| 91 | + * new one, let's break the loop. |
| 92 | + */ |
| 93 | + if (t == state && write_range->struct_name != cur) |
| 94 | + break; |
| 95 | + |
| 96 | + /* new struct to look for */ |
| 97 | + if (write_range->struct_name != cur) { |
| 98 | + type_id = btf_find_by_name_kind(reg->btf, write_range->struct_name, |
| 99 | + BTF_KIND_STRUCT); |
| 100 | + if (type_id < 0) |
| 101 | + return -EINVAL; |
| 102 | + |
| 103 | + state = btf_type_by_id(reg->btf, type_id); |
| 104 | + } |
| 105 | + |
| 106 | + /* this is not the struct we are looking for */ |
| 107 | + if (t != state) { |
| 108 | + cur = write_range->struct_name; |
| 109 | + continue; |
| 110 | + } |
| 111 | + |
| 112 | + /* first time we see this struct, check for out of bounds */ |
| 113 | + if (cur != write_range->struct_name && |
| 114 | + off + size > write_range->struct_length) { |
| 115 | + bpf_log(log, "write access for struct %s at off %d with size %d\n", |
| 116 | + write_range->struct_name, off, size); |
| 117 | + return -EACCES; |
| 118 | + } |
| 119 | + |
| 120 | + /* now check if we are in our boundaries */ |
| 121 | + if (off >= write_range->start && off + size <= write_range->end) |
| 122 | + return NOT_INIT; |
| 123 | + |
| 124 | + cur = write_range->struct_name; |
79 | 125 | } |
80 | 126 |
|
81 | | - if (off < offsetof(struct hid_bpf_ctx, retval)) { |
| 127 | + |
| 128 | + if (t != state) |
| 129 | + bpf_log(log, "write access to this struct is not supported\n"); |
| 130 | + else |
82 | 131 | bpf_log(log, |
83 | | - "write access at off %d with size %d on read-only part of hid_bpf_ctx\n", |
84 | | - off, size); |
85 | | - return -EACCES; |
86 | | - } |
| 132 | + "write access at off %d with size %d on read-only part of %s\n", |
| 133 | + off, size, cur); |
87 | 134 |
|
88 | | - return NOT_INIT; |
| 135 | + return -EACCES; |
89 | 136 | } |
90 | 137 |
|
91 | 138 | static const struct bpf_verifier_ops hid_bpf_verifier_ops = { |
|
0 commit comments