diff options
Diffstat (limited to 'kernel/bpf/btf.c')
-rw-r--r-- | kernel/bpf/btf.c | 58 |
1 files changed, 25 insertions, 33 deletions
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index 378cef70341c..ee4c82667d65 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c | |||
@@ -2067,56 +2067,47 @@ static int btf_check_sec_info(struct btf_verifier_env *env, | |||
2067 | return 0; | 2067 | return 0; |
2068 | } | 2068 | } |
2069 | 2069 | ||
2070 | static int btf_parse_hdr(struct btf_verifier_env *env, void __user *btf_data, | 2070 | static int btf_parse_hdr(struct btf_verifier_env *env) |
2071 | u32 btf_data_size) | ||
2072 | { | 2071 | { |
2072 | u32 hdr_len, hdr_copy, btf_data_size; | ||
2073 | const struct btf_header *hdr; | 2073 | const struct btf_header *hdr; |
2074 | u32 hdr_len, hdr_copy; | ||
2075 | /* | ||
2076 | * Minimal part of the "struct btf_header" that | ||
2077 | * contains the hdr_len. | ||
2078 | */ | ||
2079 | struct btf_min_header { | ||
2080 | u16 magic; | ||
2081 | u8 version; | ||
2082 | u8 flags; | ||
2083 | u32 hdr_len; | ||
2084 | } __user *min_hdr; | ||
2085 | struct btf *btf; | 2074 | struct btf *btf; |
2086 | int err; | 2075 | int err; |
2087 | 2076 | ||
2088 | btf = env->btf; | 2077 | btf = env->btf; |
2089 | min_hdr = btf_data; | 2078 | btf_data_size = btf->data_size; |
2090 | 2079 | ||
2091 | if (btf_data_size < sizeof(*min_hdr)) { | 2080 | if (btf_data_size < |
2081 | offsetof(struct btf_header, hdr_len) + sizeof(hdr->hdr_len)) { | ||
2092 | btf_verifier_log(env, "hdr_len not found"); | 2082 | btf_verifier_log(env, "hdr_len not found"); |
2093 | return -EINVAL; | 2083 | return -EINVAL; |
2094 | } | 2084 | } |
2095 | 2085 | ||
2096 | if (get_user(hdr_len, &min_hdr->hdr_len)) | 2086 | hdr = btf->data; |
2097 | return -EFAULT; | 2087 | hdr_len = hdr->hdr_len; |
2098 | |||
2099 | if (btf_data_size < hdr_len) { | 2088 | if (btf_data_size < hdr_len) { |
2100 | btf_verifier_log(env, "btf_header not found"); | 2089 | btf_verifier_log(env, "btf_header not found"); |
2101 | return -EINVAL; | 2090 | return -EINVAL; |
2102 | } | 2091 | } |
2103 | 2092 | ||
2104 | err = bpf_check_uarg_tail_zero(btf_data, sizeof(btf->hdr), hdr_len); | 2093 | /* Ensure the unsupported header fields are zero */ |
2105 | if (err) { | 2094 | if (hdr_len > sizeof(btf->hdr)) { |
2106 | if (err == -E2BIG) | 2095 | u8 *expected_zero = btf->data + sizeof(btf->hdr); |
2107 | btf_verifier_log(env, "Unsupported btf_header"); | 2096 | u8 *end = btf->data + hdr_len; |
2108 | return err; | 2097 | |
2098 | for (; expected_zero < end; expected_zero++) { | ||
2099 | if (*expected_zero) { | ||
2100 | btf_verifier_log(env, "Unsupported btf_header"); | ||
2101 | return -E2BIG; | ||
2102 | } | ||
2103 | } | ||
2109 | } | 2104 | } |
2110 | 2105 | ||
2111 | hdr_copy = min_t(u32, hdr_len, sizeof(btf->hdr)); | 2106 | hdr_copy = min_t(u32, hdr_len, sizeof(btf->hdr)); |
2112 | if (copy_from_user(&btf->hdr, btf_data, hdr_copy)) | 2107 | memcpy(&btf->hdr, btf->data, hdr_copy); |
2113 | return -EFAULT; | ||
2114 | 2108 | ||
2115 | hdr = &btf->hdr; | 2109 | hdr = &btf->hdr; |
2116 | 2110 | ||
2117 | if (hdr->hdr_len != hdr_len) | ||
2118 | return -EINVAL; | ||
2119 | |||
2120 | btf_verifier_log_hdr(env, btf_data_size); | 2111 | btf_verifier_log_hdr(env, btf_data_size); |
2121 | 2112 | ||
2122 | if (hdr->magic != BTF_MAGIC) { | 2113 | if (hdr->magic != BTF_MAGIC) { |
@@ -2186,10 +2177,6 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size, | |||
2186 | } | 2177 | } |
2187 | env->btf = btf; | 2178 | env->btf = btf; |
2188 | 2179 | ||
2189 | err = btf_parse_hdr(env, btf_data, btf_data_size); | ||
2190 | if (err) | ||
2191 | goto errout; | ||
2192 | |||
2193 | data = kvmalloc(btf_data_size, GFP_KERNEL | __GFP_NOWARN); | 2180 | data = kvmalloc(btf_data_size, GFP_KERNEL | __GFP_NOWARN); |
2194 | if (!data) { | 2181 | if (!data) { |
2195 | err = -ENOMEM; | 2182 | err = -ENOMEM; |
@@ -2198,13 +2185,18 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size, | |||
2198 | 2185 | ||
2199 | btf->data = data; | 2186 | btf->data = data; |
2200 | btf->data_size = btf_data_size; | 2187 | btf->data_size = btf_data_size; |
2201 | btf->nohdr_data = btf->data + btf->hdr.hdr_len; | ||
2202 | 2188 | ||
2203 | if (copy_from_user(data, btf_data, btf_data_size)) { | 2189 | if (copy_from_user(data, btf_data, btf_data_size)) { |
2204 | err = -EFAULT; | 2190 | err = -EFAULT; |
2205 | goto errout; | 2191 | goto errout; |
2206 | } | 2192 | } |
2207 | 2193 | ||
2194 | err = btf_parse_hdr(env); | ||
2195 | if (err) | ||
2196 | goto errout; | ||
2197 | |||
2198 | btf->nohdr_data = btf->data + btf->hdr.hdr_len; | ||
2199 | |||
2208 | err = btf_parse_str_sec(env); | 2200 | err = btf_parse_str_sec(env); |
2209 | if (err) | 2201 | if (err) |
2210 | goto errout; | 2202 | goto errout; |