diff options
-rw-r--r-- | arch/x86/kernel/microcode_amd.c | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index adbcef4f6333..9fb8405451c5 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c | |||
@@ -66,7 +66,6 @@ struct microcode_amd { | |||
66 | unsigned int mpb[0]; | 66 | unsigned int mpb[0]; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | #define UCODE_MAX_SIZE 2048 | ||
70 | #define UCODE_CONTAINER_SECTION_HDR 8 | 69 | #define UCODE_CONTAINER_SECTION_HDR 8 |
71 | #define UCODE_CONTAINER_HEADER_SIZE 12 | 70 | #define UCODE_CONTAINER_HEADER_SIZE 12 |
72 | 71 | ||
@@ -155,31 +154,60 @@ static int apply_microcode_amd(int cpu) | |||
155 | return 0; | 154 | return 0; |
156 | } | 155 | } |
157 | 156 | ||
157 | static unsigned int verify_ucode_size(int cpu, const u8 *buf, unsigned int size) | ||
158 | { | ||
159 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
160 | unsigned int max_size, actual_size; | ||
161 | |||
162 | #define F1XH_MPB_MAX_SIZE 2048 | ||
163 | #define F14H_MPB_MAX_SIZE 1824 | ||
164 | #define F15H_MPB_MAX_SIZE 4096 | ||
165 | |||
166 | switch (c->x86) { | ||
167 | case 0x14: | ||
168 | max_size = F14H_MPB_MAX_SIZE; | ||
169 | break; | ||
170 | case 0x15: | ||
171 | max_size = F15H_MPB_MAX_SIZE; | ||
172 | break; | ||
173 | default: | ||
174 | max_size = F1XH_MPB_MAX_SIZE; | ||
175 | break; | ||
176 | } | ||
177 | |||
178 | actual_size = buf[4] + (buf[5] << 8); | ||
179 | |||
180 | if (actual_size > size || actual_size > max_size) { | ||
181 | pr_err("section size mismatch\n"); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | return actual_size; | ||
186 | } | ||
187 | |||
158 | static struct microcode_header_amd * | 188 | static struct microcode_header_amd * |
159 | get_next_ucode(const u8 *buf, unsigned int size, unsigned int *mc_size) | 189 | get_next_ucode(int cpu, const u8 *buf, unsigned int size, unsigned int *mc_size) |
160 | { | 190 | { |
161 | struct microcode_header_amd *mc; | 191 | struct microcode_header_amd *mc = NULL; |
162 | unsigned int total_size; | 192 | unsigned int actual_size = 0; |
163 | 193 | ||
164 | if (buf[0] != UCODE_UCODE_TYPE) { | 194 | if (buf[0] != UCODE_UCODE_TYPE) { |
165 | pr_err("invalid type field in container file section header\n"); | 195 | pr_err("invalid type field in container file section header\n"); |
166 | return NULL; | 196 | goto out; |
167 | } | 197 | } |
168 | 198 | ||
169 | total_size = buf[4] + (buf[5] << 8); | 199 | actual_size = verify_ucode_size(cpu, buf, size); |
170 | 200 | if (!actual_size) | |
171 | if (total_size > size || total_size > UCODE_MAX_SIZE) { | 201 | goto out; |
172 | pr_err("section size mismatch\n"); | ||
173 | return NULL; | ||
174 | } | ||
175 | 202 | ||
176 | mc = vzalloc(UCODE_MAX_SIZE); | 203 | mc = vzalloc(actual_size); |
177 | if (!mc) | 204 | if (!mc) |
178 | return NULL; | 205 | goto out; |
179 | 206 | ||
180 | get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size); | 207 | get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, actual_size); |
181 | *mc_size = total_size + UCODE_CONTAINER_SECTION_HDR; | 208 | *mc_size = actual_size + UCODE_CONTAINER_SECTION_HDR; |
182 | 209 | ||
210 | out: | ||
183 | return mc; | 211 | return mc; |
184 | } | 212 | } |
185 | 213 | ||
@@ -234,7 +262,7 @@ generic_load_microcode(int cpu, const u8 *data, size_t size) | |||
234 | leftover = size - offset; | 262 | leftover = size - offset; |
235 | 263 | ||
236 | while (leftover) { | 264 | while (leftover) { |
237 | mc_hdr = get_next_ucode(ucode_ptr, leftover, &mc_size); | 265 | mc_hdr = get_next_ucode(cpu, ucode_ptr, leftover, &mc_size); |
238 | if (!mc_hdr) | 266 | if (!mc_hdr) |
239 | break; | 267 | break; |
240 | 268 | ||