Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp5527913imm; Tue, 19 Jun 2018 11:52:08 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKVvdImRQvAtO2WYdW1kqgK2kAHKZq6qy2JPjJnC4GjH7XCL6LMIs5td2Yi1XVQbm4JcHuK X-Received: by 2002:a17:902:56e:: with SMTP id 101-v6mr19596491plf.25.1529434328588; Tue, 19 Jun 2018 11:52:08 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529434328; cv=none; d=google.com; s=arc-20160816; b=JIGH3n8sqXQlRbgZlkDzr9pUPsO+dhmmmADhFIWN8ZI4z9qIQGs1r1l24+GRz8PsrD BNVdz7W66CIUROAHkxW/wMbWeqWC5uAWtQWRXIeE5zxPnqJ299F1dHc9XQ+raeS8MV3c KvY+pHn99nHGOZdYGXtmdpJDFaEOkaEiZn5v8GACbJZs6KMWlF+F0KdwKYu2xAbBVABE TP3joSh4rlPZ3zhRWX2WX225ukzd30Ys5ATFRbtKSbmmXjLOyzRnyKTvZbYxi8eO6PSN a6ES/OdkhOKaMncQ5szfniSiAUQqX/14xISxM05IVrV9TbKlL1JMxMJyA8kC5IaJnnnI 6e3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Dn1w8IJYsJbFaxpHBfGoFqsKc+oVIPbntpNUZuO/l30=; b=wlUPHAZdu25lLgq1rfPltQs4R2afRDv7rfhFiuH3wl0Df+WWFfqRAjy83Wm0yEFFB2 qrWweDowwW3aR5BPISlDXOY/leB0VHMtrwDbIOJMGlmAt8mscvsunsis9AsqJpnwTsQW xs0VtX1fSKNy0Hvlz0ySrslFJ0YNOj3P+J9aeGa9Saq/wL/I7nL8Szy0I5cHCGhN7YCl 87xsA7O71jj+lqR68LAQnH36abiTNge/CBi7YBSpjZKOEg+NUH12WPCW0KJdBuZ8DPSj C02NWjSJGfd5FnuADHb6EaZXywz10F4xWYGhFUKRtJWaaGJIsg/9XUERZXfjO9V+Yl6T SolA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id b9-v6si308366pgs.139.2018.06.19.11.51.54; Tue, 19 Jun 2018 11:52:08 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1030531AbeFSStw (ORCPT + 99 others); Tue, 19 Jun 2018 14:49:52 -0400 Received: from vps-vb.mhejs.net ([37.28.154.113]:39600 "EHLO vps-vb.mhejs.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030305AbeFSSrv (ORCPT ); Tue, 19 Jun 2018 14:47:51 -0400 Received: by vps-vb.mhejs.net with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1fVLfH-0003Vm-I0; Tue, 19 Jun 2018 20:47:39 +0200 From: "Maciej S. Szmigiero" To: Borislav Petkov Cc: Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , x86@kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v7 0/9] x86/microcode/AMD: Check microcode file sanity before loading it Date: Tue, 19 Jun 2018 20:47:30 +0200 Message-Id: X-Mailer: git-send-email 2.17.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently, it is very easy to make the AMD microcode update driver crash or spin on a malformed microcode container file since it does very little consistency checking on data loaded from such file. This series introduces various checks, mostly on length-type fields, so all corrupted microcode container files are (hopefully) correctly rejected instead. This largely matches what the Intel microcode update driver already does. It also tries to make the behavior consistent between the early and late loaders. Please note that this isn't about verifying the actual microcode update, that is, the blob that gets sent to the CPU as the new microcode. Such verification is (hopefully) done by the CPU itself. It is about verifying a driver-specific container file that includes many microcode updates for different CPUs of a particular CPU family, along with metadata that helps the driver select the right microcode update to actually send to the CPU. There are purposely-corrupted test files available at https://pastebin.com/XkKUSmMp One has to enable KASAN in the kernel config and rename a particular test file to name appropriate to the running CPU family to test its loading. Changes from v1: * Capitalize a comment, * Rename 'eqsize' and 'bufsize' to 'eq_size' and 'buf_size', respectively, * Attach a comment about checking the equivalence table header to its first size check, * Rename 'equiv{_cpu,}_table_size' to 'equiv{_cpu,}_table_entries'. Changes from v2: * Split the patch into separate commits, * Remove explicit CPU equivalence table size limit, * Make install_equiv_cpu_table() return a size_t instead of a (signed) int so no overflow can occur there, * Automatically compute the PATCH_MAX_SIZE macro and use it for checking a patch size, * Make the late loader behavior with respect to late parse failures consistent with what the early loader does. Changes from v3: * Capitalize patch subject names, * Add a comment describing why we subtract SECTION_HDR_SIZE from a file leftover length before calling verify_patch_size(), * Don't break a long line containing the above subtraction, * Move a comment in parse_container() back to where it was in the original patch version, * Add special local vars for container header fields in parse_container(), * Return the remaining blob size from parse_container() if the equivalence table is truncated, * Split the equivalence table size checks into two patches: one for the early loader and one for the late loader, * Rename an equivalence table length variable in install_equiv_cpu_table() for consistency with a similar one in parse_container(), * Rephrase the error messages in install_equiv_cpu_table() to be more descriptive and merge two tests there so they print the same message, * Change install_equiv_cpu_table() to return an unsigned int while moving the job of adding the container header length to this value to its caller, * Drop automatic computation of the PATCH_MAX_SIZE macro and add a comment reminding to do it manually instead, * Add a local variable patch_type for better code readability in verify_and_add_patch() function. Changes from v4: * Update the first patch in series with Borislav's version, * Use u32-type variables for microcode container header fields, * Drop the check for zero-length CPU equivalence table, * Leave size variables in verify_patch_size() as unsigned ints, * Rewrite the series to use common microcode container data checking functions in both the early and the late loader so their code won't get interspersed with a lot of checks and so will be more readable. Changes from v5: * Remove "This commit" or "This patch" prefix from commit messages, * Make sure that every checking function verifies presence of any data it accesses so these functions don't have an implicit call order requirement, * Integrate verify_patch_size() into verify_patch() after the late loader is converted to no longer call verify_patch_size() directly, * Make a patch matching check in the early loader more readable, * Skip just one byte in the early loader when a container cannot be parsed successfully so the parser will correctly skip unknown data of any size, * Move assignment of a pointer to CPU equivalence table header variable past this table check in install_equiv_cpu_table(), * Split returned status value from returned length of data to skip in verify_and_add_patch() so we keep the common convention that a function zero return value means success while a negative value means an error, * Don't introduce a new global variable for holding the CPU equivalence table size, add a terminating zero entry to this table explicitly instead to prevent scanning past its valid data. Changes from v6: * Rewrite comments describing checking functions in the imperative mood and make sure they don't refer to "@buf_size" parameter as "@size", * Remove a call to verify_container() from parse_container() since invoking verify_equivalence_table() is enough as it includes such a call, * Remove a now-unnecessary additional error message in __load_microcode_amd() if install_equiv_cpu_table() fails, * Introduce a check whether the indicated size of a patch makes sense for its declared CPU family - for all CPU families known to the driver so we don't skip over good patches by mistake if the indicated size turns out to be something nonsensically huge, * Make sure we skip just one byte of microcode data in the late loader if a patch section does not have a plausible header so we try harder to not skip good patches in presence of some garbage between patch sections, * Convert pointer to the CPU equivalence table global static variable into a struct descriptor, * Add CPU equivalence table size field to the above descriptor and use it to prevent scanning past this table in both the early and the late loader. arch/x86/include/asm/microcode_amd.h | 1 + arch/x86/kernel/cpu/microcode/amd.c | 458 +++++++++++++++++++-------- 2 files changed, 323 insertions(+), 136 deletions(-)