|
@@ -2067,56 +2067,47 @@ static int btf_check_sec_info(struct btf_verifier_env *env,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int btf_parse_hdr(struct btf_verifier_env *env, void __user *btf_data,
|
|
|
- u32 btf_data_size)
|
|
|
+static int btf_parse_hdr(struct btf_verifier_env *env)
|
|
|
{
|
|
|
+ u32 hdr_len, hdr_copy, btf_data_size;
|
|
|
const struct btf_header *hdr;
|
|
|
- u32 hdr_len, hdr_copy;
|
|
|
- /*
|
|
|
- * Minimal part of the "struct btf_header" that
|
|
|
- * contains the hdr_len.
|
|
|
- */
|
|
|
- struct btf_min_header {
|
|
|
- u16 magic;
|
|
|
- u8 version;
|
|
|
- u8 flags;
|
|
|
- u32 hdr_len;
|
|
|
- } __user *min_hdr;
|
|
|
struct btf *btf;
|
|
|
int err;
|
|
|
|
|
|
btf = env->btf;
|
|
|
- min_hdr = btf_data;
|
|
|
+ btf_data_size = btf->data_size;
|
|
|
|
|
|
- if (btf_data_size < sizeof(*min_hdr)) {
|
|
|
+ if (btf_data_size <
|
|
|
+ offsetof(struct btf_header, hdr_len) + sizeof(hdr->hdr_len)) {
|
|
|
btf_verifier_log(env, "hdr_len not found");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- if (get_user(hdr_len, &min_hdr->hdr_len))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
+ hdr = btf->data;
|
|
|
+ hdr_len = hdr->hdr_len;
|
|
|
if (btf_data_size < hdr_len) {
|
|
|
btf_verifier_log(env, "btf_header not found");
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
- err = bpf_check_uarg_tail_zero(btf_data, sizeof(btf->hdr), hdr_len);
|
|
|
- if (err) {
|
|
|
- if (err == -E2BIG)
|
|
|
- btf_verifier_log(env, "Unsupported btf_header");
|
|
|
- return err;
|
|
|
+ /* Ensure the unsupported header fields are zero */
|
|
|
+ if (hdr_len > sizeof(btf->hdr)) {
|
|
|
+ u8 *expected_zero = btf->data + sizeof(btf->hdr);
|
|
|
+ u8 *end = btf->data + hdr_len;
|
|
|
+
|
|
|
+ for (; expected_zero < end; expected_zero++) {
|
|
|
+ if (*expected_zero) {
|
|
|
+ btf_verifier_log(env, "Unsupported btf_header");
|
|
|
+ return -E2BIG;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
hdr_copy = min_t(u32, hdr_len, sizeof(btf->hdr));
|
|
|
- if (copy_from_user(&btf->hdr, btf_data, hdr_copy))
|
|
|
- return -EFAULT;
|
|
|
+ memcpy(&btf->hdr, btf->data, hdr_copy);
|
|
|
|
|
|
hdr = &btf->hdr;
|
|
|
|
|
|
- if (hdr->hdr_len != hdr_len)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
btf_verifier_log_hdr(env, btf_data_size);
|
|
|
|
|
|
if (hdr->magic != BTF_MAGIC) {
|
|
@@ -2186,10 +2177,6 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
|
|
|
}
|
|
|
env->btf = btf;
|
|
|
|
|
|
- err = btf_parse_hdr(env, btf_data, btf_data_size);
|
|
|
- if (err)
|
|
|
- goto errout;
|
|
|
-
|
|
|
data = kvmalloc(btf_data_size, GFP_KERNEL | __GFP_NOWARN);
|
|
|
if (!data) {
|
|
|
err = -ENOMEM;
|
|
@@ -2198,13 +2185,18 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size,
|
|
|
|
|
|
btf->data = data;
|
|
|
btf->data_size = btf_data_size;
|
|
|
- btf->nohdr_data = btf->data + btf->hdr.hdr_len;
|
|
|
|
|
|
if (copy_from_user(data, btf_data, btf_data_size)) {
|
|
|
err = -EFAULT;
|
|
|
goto errout;
|
|
|
}
|
|
|
|
|
|
+ err = btf_parse_hdr(env);
|
|
|
+ if (err)
|
|
|
+ goto errout;
|
|
|
+
|
|
|
+ btf->nohdr_data = btf->data + btf->hdr.hdr_len;
|
|
|
+
|
|
|
err = btf_parse_str_sec(env);
|
|
|
if (err)
|
|
|
goto errout;
|