aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/microcode_amd.c60
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
157static 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
158static struct microcode_header_amd * 188static struct microcode_header_amd *
159get_next_ucode(const u8 *buf, unsigned int size, unsigned int *mc_size) 189get_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
210out:
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