Skip to content

Commit ca285d1

Browse files
captain5050Leo-Yan
authored andcommitted
perf bpf-utils: Harden get_bpf_prog_info_linear
In get_bpf_prog_info_linear two calls to bpf_obj_get_info_by_fd are made, the first to compute memory requirements for a struct perf_bpil and the second to fill it in. Previously the code would warn when the second call didn't match the first. Such races can be common place in things like perf test, whose perf trace tests will frequently load BPF programs. Rather than a debug message, return actual errors for this case. Out of paranoia also validate the read bpf_prog_info array value. Change the type of ptr to avoid mismatched pointer type compiler warnings. Add some additional debug print outs and sanity asserts. Closes: https://lore.kernel.org/lkml/CAP-5=fWJQcmUOP7MuCA2ihKnDAHUCOBLkQFEkQES-1ZZTrgf8Q@mail.gmail.com/ Fixes: 6ac22d0 ("perf bpf: Pull in bpf_program__get_prog_info_linear()") Reviewed-by: Namhyung Kim <[email protected]> Signed-off-by: Ian Rogers <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Namhyung Kim <[email protected]>
1 parent 6350a4e commit ca285d1

File tree

1 file changed

+33
-10
lines changed

1 file changed

+33
-10
lines changed

tools/perf/util/bpf-utils.c

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
115115
__u32 info_len = sizeof(info);
116116
__u32 data_len = 0;
117117
int i, err;
118-
void *ptr;
118+
__u8 *ptr;
119119

120120
if (arrays >> PERF_BPIL_LAST_ARRAY)
121121
return ERR_PTR(-EINVAL);
@@ -126,6 +126,8 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
126126
pr_debug("can't get prog info: %s", strerror(errno));
127127
return ERR_PTR(-EFAULT);
128128
}
129+
if (info.type >= __MAX_BPF_PROG_TYPE)
130+
pr_debug("%s:%d: unexpected program type %u\n", __func__, __LINE__, info.type);
129131

130132
/* step 2: calculate total size of all arrays */
131133
for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
@@ -173,6 +175,8 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
173175
desc->count_offset, count);
174176
bpf_prog_info_set_offset_u32(&info_linear->info,
175177
desc->size_offset, size);
178+
assert(ptr >= info_linear->data);
179+
assert(ptr < &info_linear->data[data_len]);
176180
bpf_prog_info_set_offset_u64(&info_linear->info,
177181
desc->array_offset,
178182
ptr_to_u64(ptr));
@@ -186,26 +190,45 @@ get_bpf_prog_info_linear(int fd, __u64 arrays)
186190
free(info_linear);
187191
return ERR_PTR(-EFAULT);
188192
}
193+
if (info_linear->info.type >= __MAX_BPF_PROG_TYPE) {
194+
pr_debug("%s:%d: unexpected program type %u\n",
195+
__func__, __LINE__, info_linear->info.type);
196+
}
189197

190198
/* step 6: verify the data */
199+
ptr = info_linear->data;
191200
for (i = PERF_BPIL_FIRST_ARRAY; i < PERF_BPIL_LAST_ARRAY; ++i) {
192201
const struct bpil_array_desc *desc = &bpil_array_desc[i];
193-
__u32 v1, v2;
202+
__u32 count1, count2, size1, size2;
203+
__u64 ptr2;
194204

195205
if ((arrays & (1UL << i)) == 0)
196206
continue;
197207

198-
v1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
199-
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
208+
count1 = bpf_prog_info_read_offset_u32(&info, desc->count_offset);
209+
count2 = bpf_prog_info_read_offset_u32(&info_linear->info,
200210
desc->count_offset);
201-
if (v1 != v2)
202-
pr_warning("%s: mismatch in element count\n", __func__);
211+
if (count1 != count2) {
212+
pr_warning("%s: mismatch in element count %u vs %u\n", __func__, count1, count2);
213+
free(info_linear);
214+
return ERR_PTR(-ERANGE);
215+
}
203216

204-
v1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
205-
v2 = bpf_prog_info_read_offset_u32(&info_linear->info,
217+
size1 = bpf_prog_info_read_offset_u32(&info, desc->size_offset);
218+
size2 = bpf_prog_info_read_offset_u32(&info_linear->info,
206219
desc->size_offset);
207-
if (v1 != v2)
208-
pr_warning("%s: mismatch in rec size\n", __func__);
220+
if (size1 != size2) {
221+
pr_warning("%s: mismatch in rec size %u vs %u\n", __func__, size1, size2);
222+
free(info_linear);
223+
return ERR_PTR(-ERANGE);
224+
}
225+
ptr2 = bpf_prog_info_read_offset_u64(&info_linear->info, desc->array_offset);
226+
if (ptr_to_u64(ptr) != ptr2) {
227+
pr_warning("%s: mismatch in array %p vs %llx\n", __func__, ptr, ptr2);
228+
free(info_linear);
229+
return ERR_PTR(-ERANGE);
230+
}
231+
ptr += roundup(count1 * size1, sizeof(__u64));
209232
}
210233

211234
/* step 7: update info_len and data_len */

0 commit comments

Comments
 (0)