diff options
Diffstat (limited to 'arch/x86/kernel/cpu/microcode/intel_lib.c')
| -rw-r--r-- | arch/x86/kernel/cpu/microcode/intel_lib.c | 58 | 
1 files changed, 37 insertions, 21 deletions
diff --git a/arch/x86/kernel/cpu/microcode/intel_lib.c b/arch/x86/kernel/cpu/microcode/intel_lib.c index b96896bcbdaf..2ce1a7dc45b7 100644 --- a/arch/x86/kernel/cpu/microcode/intel_lib.c +++ b/arch/x86/kernel/cpu/microcode/intel_lib.c @@ -49,7 +49,7 @@ int microcode_sanity_check(void *mc, int print_err)  	unsigned long total_size, data_size, ext_table_size;  	struct microcode_header_intel *mc_header = mc;  	struct extended_sigtable *ext_header = NULL; -	int sum, orig_sum, ext_sigcount = 0, i; +	u32 sum, orig_sum, ext_sigcount = 0, i;  	struct extended_signature *ext_sig;  	total_size = get_totalsize(mc_header); @@ -57,69 +57,85 @@ int microcode_sanity_check(void *mc, int print_err)  	if (data_size + MC_HEADER_SIZE > total_size) {  		if (print_err) -			pr_err("error! Bad data size in microcode data file\n"); +			pr_err("Error: bad microcode data file size.\n");  		return -EINVAL;  	}  	if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {  		if (print_err) -			pr_err("error! Unknown microcode update format\n"); +			pr_err("Error: invalid/unknown microcode update format.\n");  		return -EINVAL;  	} +  	ext_table_size = total_size - (MC_HEADER_SIZE + data_size);  	if (ext_table_size) { +		u32 ext_table_sum = 0; +		u32 *ext_tablep; +  		if ((ext_table_size < EXT_HEADER_SIZE)  		 || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {  			if (print_err) -				pr_err("error! Small exttable size in microcode data file\n"); +				pr_err("Error: truncated extended signature table.\n");  			return -EINVAL;  		} +  		ext_header = mc + MC_HEADER_SIZE + data_size;  		if (ext_table_size != exttable_size(ext_header)) {  			if (print_err) -				pr_err("error! Bad exttable size in microcode data file\n"); +				pr_err("Error: extended signature table size mismatch.\n");  			return -EFAULT;  		} +  		ext_sigcount = ext_header->count; -	} -	/* check extended table checksum */ -	if (ext_table_size) { -		int ext_table_sum = 0; -		int *ext_tablep = (int *)ext_header; +		/* +		 * Check extended table checksum: the sum of all dwords that +		 * comprise a valid table must be 0. +		 */ +		ext_tablep = (u32 *)ext_header; -		i = ext_table_size / DWSIZE; +		i = ext_table_size / sizeof(u32);  		while (i--)  			ext_table_sum += ext_tablep[i]; +  		if (ext_table_sum) {  			if (print_err) -				pr_warn("aborting, bad extended signature table checksum\n"); +				pr_warn("Bad extended signature table checksum, aborting.\n");  			return -EINVAL;  		}  	} -	/* calculate the checksum */ +	/* +	 * Calculate the checksum of update data and header. The checksum of +	 * valid update data and header including the extended signature table +	 * must be 0. +	 */  	orig_sum = 0; -	i = (MC_HEADER_SIZE + data_size) / DWSIZE; +	i = (MC_HEADER_SIZE + data_size) / sizeof(u32);  	while (i--) -		orig_sum += ((int *)mc)[i]; +		orig_sum += ((u32 *)mc)[i]; +  	if (orig_sum) {  		if (print_err) -			pr_err("aborting, bad checksum\n"); +			pr_err("Bad microcode data checksum, aborting.\n");  		return -EINVAL;  	} +  	if (!ext_table_size)  		return 0; -	/* check extended signature checksum */ + +	/* +	 * Check extended signature checksum: 0 => valid. +	 */  	for (i = 0; i < ext_sigcount; i++) {  		ext_sig = (void *)ext_header + EXT_HEADER_SIZE +  			  EXT_SIGNATURE_SIZE * i; -		sum = orig_sum -			- (mc_header->sig + mc_header->pf + mc_header->cksum) -			+ (ext_sig->sig + ext_sig->pf + ext_sig->cksum); + +		sum = (mc_header->sig + mc_header->pf + mc_header->cksum) - +		      (ext_sig->sig + ext_sig->pf + ext_sig->cksum);  		if (sum) {  			if (print_err) -				pr_err("aborting, bad checksum\n"); +				pr_err("Bad extended signature checksum, aborting.\n");  			return -EINVAL;  		}  	}  |