aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/btf.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/btf.c')
-rw-r--r--kernel/bpf/btf.c58
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
2070static int btf_parse_hdr(struct btf_verifier_env *env, void __user *btf_data, 2070static 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;