[REVS] Opteron Exposed: Reverse Engineering AMD K8 Microcode Updates

From: SecuriTeam (support_at_securiteam.com)
Date: 07/26/04

  • Next message: SecuriTeam: "[NT] FTP Glide Stores Login Information in Cleartext"
    To: list@securiteam.com
    Date: 26 Jul 2004 10:54:16 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      Opteron Exposed: Reverse Engineering AMD K8 Microcode Updates
    ------------------------------------------------------------------------

    SUMMARY

    This document details the procedure for performing microcode updates on
    the AMD K8 processors. It also gives background information on the K8
    microcode design and provides information on altering the microcode and
    loading the altered update for those who are interested in microcode
    hacking.

    Source code is included for a simple Linux microcode update driver for
    those who want to update their K8's microcode without waiting for the
    motherboard vendor to add it to the BIOS. The latest microcode update
    blocks are included in the driver.

    DETAILS

    Background:
    Modern x86 microprocessors from Intel and AMD contain a feature known as
    "microcode update", or as the vendors prefer to call it, "BIOS update".
    Essentially the processor can reconfigure parts of its own hardware to fix
    bugs ("errata") in the silicon that would normally require a recall.

    This is done by loading a block of "patch data" created by the CPU vendor
    into the processor using special control registers. Microcode updates
    essentially override hardware features with sequences of the internal
    RISC-like micro-ops (uops) actually executed by the processor. They can
    also replace the implementations of microcoded instructions already
    handled by hard-wired sequences in an on-die microcode ROM.

    AMD's U.S. Patent 6438664 ("Microcode patch device and method for patching
    microcode using match registers and patch routines") goes into substantial
    detail on this.

    Typically microcode update blocks are stored in the BIOS flash ROM and
    loaded into the processor as the system boots. They can also be loaded by
    the operating system; for instance, Linux contains a microcode device
    driver for Intel chips.

    AMD recently released a "BIOS fix" to motherboard makers to address Errata
    109, in which REP MOVS instructions caused subsequent instructions to be
    skipped under specific pipeline conditions.

    Previously it was not clear if and how AMD even supported microcode
    updates in the K8 family until this announcement. After analyzing a number
    of BIOS images, it appears that AMD has secretly used the microcode update
    facility on several occasions over the past few years, but obviously
    avoided publicly disclosing that it actually had bugs patchable in this
    manner.

    Early K7 (Athlon) cores initially supported microcode updates as well,
    until ironically the microcode update mechanism itself was found to be
    broken and subsequently listed as an erratum.

    The following sections describe the microcode update procedure, obtained
    by clean room reverse engineering various vendors' BIOS code. The actual
    microcode update blocks are embedded in the BIOS image; the most recent
    updates (created June 2004) have been included in the Linux driver source
    code attached to this description.

    Microcode Update Procedure:
    The update procedure expects the 64-bit virtual address of the update
    data, including the 64 byte header, to be in edx:eax:

    edx = high 32 bits of 64-bit virtual address
    eax = low 32 bits of 64-bit virtual address
    ecx = 0xc0010020 (MSR to trigger update)

    Execute wrmsr with these register values. If the address and update block
    data are valid, wrmsr completes successfully. Otherwise, a GP fault is
    taken.

    The microcode does not appear to update MSR 0x8B with the new update
    signature as it does on Intel processors, despite the fact that some BIOS
    code that was analyzed does seem to check this field. It is possible the
    MSR is only updated under certain conditions, for instance when microcode
    is loaded before initializing the cache controller. Nonetheless, as we
    shall see below, the processor is clearly doing something internally when
    it claims to accept an update in this manner.

    The update generally takes around 5500 clock cycles. This was tested on an
    Athlon 64 with CPUID 0x0F48. It was not tested on any other K8 cores,
    although the driver source code includes updates for CPUIDs 0x0F4A and
    0x0F50.

    Microcode Block Format:
    The microcode block consists of a 64-byte header and an 896-byte data
    area. The processor consumes both the header and data area during an
    update. The header consists of various fields. The most important ones
    are:

    - Offset 0: 32-bit word for update creation date (e.g. 0x20040602)
    - Offset 12: 32-bit checksum: sum of all 32-bit words in the data area
    - Offset 24: Low 8 bits of the cpuid (e.g. 0xf48 -> 0x48).
    - Offset 28: 4 bytes: 0x01 0xaa 0xaa 0xaa (evidently a reference to
    (A)MD.)

    The microcode blocks are typically padded out to 2048 bytes, just as the
    Intel format blocks are.

    Microcode Format:
    Surprisingly, the microcode itself is in no way encrypted as it is in
    Intel microcode updates; the raw data loaded into the microcode patch
    array is directly exposed. The repetitive structure of the data, bit
    patterns and fields characteristic of microcode indicate that apparently
    no encryption was performed.

    U.S. Patent 6438664 describes the most probable structure of this data;
    the bit patterns in the update blocks show the outline of the uop triads
    and control fields known to exist in K8 microcode. Further analysis of the
    microcode format is in progress.

    Even more surprising is the total lack of strong authentication that the
    update block has not been damaged or altered. The processor's sole means
    of validating an update is to take the sum of all 32-bit words in the 896
    byte update block and compare it to the 32-bit checksum at offset 12; this
    verification is done by microcode already stored in the microcode ROM.

    Modifying random bits within the update block was tested, regenerating a
    correct checksum, and loading the block into the processor. In many cases
    the processor accepts the block with no visible effects; other cases cause
    a spontaneous reboot.

    Most alarming is the way in which certain bit modifications cause the
    processor to perform very bizarrely, for instance raising segfaults and
    performing incorrect computations on certain microcoded instructions.

    The processor also apparently does not check the header to see if the
    loaded update matches its exact model and stepping; it is possible to load
    updates intended for an Opteron onto an Athlon 64 CPU, although this will
    crash the machine or cause bizarre behavior.

    Depending on which data block bits are modified, loading an invalid update
    apparently causes an internal fault and the CPU spontaneously reboots.

    Implications:
    The ability to fundamentally alter instruction decoding and execution on
    AMD K8 processors is sure to interest hardware hackers everywhere.

    Unfortunately, it is not clear if this has much practical use. The updates
    are structured to patch specific microcode lines, and there are a very
    limited number of patch slots available (around 64 if the patented
    technique was actually implemented as described). Adding useful new
    instructions to the ISA is therefore unlikely; at best we could enable a
    previously undefined opcode to execute a few lines of uops and return. The
    primary purpose of microcode patching is to modify or disable defective
    functionality, rather than add new features.

    Interestingly, this does have serious implications for system security. If
    one is able to get root access on a machine even once, it is
    hypothetically possible to install a microcode update specifically to help
    compromise security from userspace at a later time. Such an update could
    be flashed into the BIOS to make it persistent across reboots.

    For instance, by patching the appropriate microcode lines, it may be
    possible to catch an opcode that would normally be illegal, and instead
    handle it by tricking the TLB into thinking we're in kernel mode when in
    fact the attacker has only compromised a userspace process. From there,
    the attacker could control the entire machine, all without altering a
    single bit of "software".

    Imagine the fiasco that would ensue if a system were compromised by
    altering the CPU itself. This would be the hardware equivalent of Ken
    Thompson's legendary self-replicating compiler (
    <http://www.acm.org/classics/sep95> http://www.acm.org/classics/sep95). A
    few years ago, Intel had to answer to public scrutiny over the
    exploitability of their own microcode update feature; their solution was
    security through obscurity and layers of encryption and authentication
    (see <http://www.eetimes.com/news/97/963news/hole.html>
    http://www.eetimes.com/news/97/963news/hole.html). Evidently AMD was not
    as wise by assuming their microcode was uncrackable.

    There may also be a hidden danger to altering K8 microcode without
    complete information. It is possible (though very unlikely) that the
    microcode could electrically reconfigure signal routing in a fashion
    similar to FPGAs, for instance to cut off defective logic and reroute
    signals to redundant arrays. This approach has been used in the past and
    the AMD patents even suggest it.

    If this were the case, there is a very remote chance the CPU itself could
    be permanently damaged, for instance, by tri-stating pass
    transistors into a high current draw state or adjusting the K8's voltage
    and frequency scaling controls out of spec. This is not meant to
    discourage potential hackers.

    Nonetheless, it is suspected that with sufficient analysis or maybe a bit
    of inside information, one could do some interesting things with microcode
    hacking.

    At the very least, the information here should be useful for adding AMD
    support to the Linux microcode update driver, which already supports
    Intel's update mechanism.

    Proof of Concept:
    /*
    * AMD K8 (Athlon 64 / Opteron) Microcode Update Driver
    *
    * This code has been tested on a 64-bit Linux 2.6 kernel
    * running on an Athlon 64. It has not been tested on
    * other K8 cores. It may or may not work on 32-bit
    * Linux kernels (but it should).
    *
    * This program is free software; it is licensed under
    * the GNU General Public License, version 2.
    *
    * Version: 2004 Jul 20
    */
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #include
    #include
    #include
    #include

    MODULE_DESCRIPTION("AMD K8 microcode update driver");
    MODULE_LICENSE("GPL");

    typedef unsigned int W32;
    typedef unsigned long long W64;

    // Actual update data starts at offset 64 (0x40):
    unsigned char k8_ucode_0f48[]={
    0x04,0x20,0x06,0x02,0x39,0x00,0x00,0x00,
    0x00,0x80,0x20,0x00,0xfd,0x1c,0x33,0x3e,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x48,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,
    0x44,0x06,0x00,0x00,0x40,0x01,0x00,0x00,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xfb,0xff,0x00,0xc3,0x35,0x90,0xfd,
    0xf8,0x7b,0xfe,0xa9,0x0f,0xff,0x00,0x3f,
    0xfe,0xdf,0xff,0xc7,0x1e,0xbc,0x03,0x3c,
    0x80,0x7a,0xd5,0x00,0x14,0xfe,0xff,0xff,
    0xfe,0xe1,0x1f,0xeb,0x4c,0xf6,0x3c,0xff,
    0x9f,0x87,0x7f,0x80,0x27,0x60,0x26,0xf0,
    0x74,0x1d,0xfe,0x18,0x00,0x20,0xbd,0x6a,
    0xcf,0xfb,0xff,0xe7,0xf0,0xf3,0xf0,0x0f,
    0x3f,0xee,0xff,0x9f,0x40,0xe4,0xc3,0x1b,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0x35,0x00,0xe0,0xeb,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x30,0x1a,0x00,0x78,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0x81,0x7f,0x00,0xc3,0x3f,0x80,0x7f,
    0xfc,0x7f,0x0f,0x00,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xc0,0x3f,
    0xbf,0xe1,0x1f,0xc0,0x00,0xfe,0xbf,0x07,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x1f,0xc0,0x7f,0xe0,0xe0,0xdf,0xf0,0x0f,
    0x03,0x00,0xff,0xdf,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xef,0x01,0x80,0xff,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0xff,0xf7,0x00,0xc0,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0xff,0x7b,0x00,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x00,0xf0,0xff,0x3d,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0x1e,0x00,0xf8,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x7f,0x0f,0x00,0xfc,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0xbf,0x07,0x00,
    0xfc,0x07,0xfe,0x01,0x0d,0xff,0x00,0xfe,
    0xf0,0x1f,0xf8,0x07,0x37,0xfc,0x03,0xf8,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0xdf,0x03,0x00,0xfe,0x03,0xff,
    0xff,0x86,0x7f,0x00,0x03,0xf8,0x0f,0xfc,
    0xfc,0x1b,0xfe,0x01,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x01,0x80,0xff,0xef,
    0x7f,0x00,0xff,0x81,0x80,0x7f,0xc3,0x3f,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xf7,0x00,0xc0,0xff,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0xff,0x7b,0x00,0xe0,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0x81,0x7f,0x00,0xc3,0x3f,0x80,0x7f,
    0xfc,0x07,0xfe,0x01,0x0d,0xff,0x00,0xfe,
    0xf0,0xff,0x3d,0x00,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xc0,0x3f,
    0xbf,0xe1,0x1f,0xc0,0x00,0xfe,0x03,0xff,
    0xff,0x86,0x7f,0x00,0x00,0xf8,0xff,0x1e,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x1f,0xc0,0x7f,0xe0,0xe0,0xdf,0xf0,0x0f,
    0x7f,0x00,0xff,0x81,0x80,0x7f,0xc3,0x3f,
    0x0f,0x00,0xfc,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0xbf,0x07,0x00,0xfe,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0xdf,0x03,0x00,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xef,0x01,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x00,0xc0,0xff,0xf7,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0x7b,0x00,0xe0,0xff,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0xff,0x3d,0x00,0xf0,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0xff,0x1e,0x00,
    0xf0,0x1f,0xf8,0x07,0x37,0xfc,0x03,0xf8,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x00,0xfc,0x7f,0x0f,0x03,0xf8,0x0f,0xfc,
    0xfc,0x1b,0xfe,0x01,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0x07,0x00,0xfe,0xbf,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0xdf,0x03,0x00,0xff,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xef,0x01,0x80,
    };

    unsigned char k8_ucode_0f4a[]={
    0x04,0x20,0x06,0x02,0x3a,0x00,0x00,0x00,
    0x00,0x80,0x20,0x00,0xfd,0xc6,0x88,0x3e,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x4a,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,
    0x44,0x06,0x00,0x00,0x40,0x01,0x00,0x00,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xfb,0xff,0x00,0xc3,0x35,0x90,0xfd,
    0xf8,0x7b,0xfe,0xa9,0x0f,0xff,0x00,0x3f,
    0xfe,0xdf,0xff,0xc7,0x1e,0xbc,0x03,0x3c,
    0x80,0x24,0xd6,0x00,0x14,0xfe,0xff,0xff,
    0xfe,0xe1,0x1f,0xeb,0x4c,0xf6,0x3c,0xff,
    0x9f,0x87,0x7f,0x80,0x27,0x60,0x26,0xf0,
    0x74,0x1d,0xfe,0x18,0x00,0x20,0x12,0x6b,
    0xcf,0xfb,0xff,0xe7,0xf0,0xf3,0xf0,0x0f,
    0x3f,0xee,0xff,0x9f,0x40,0xe4,0xc3,0x1b,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0x35,0x00,0xe0,0xeb,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x30,0x1a,0x00,0x78,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0x81,0x7f,0x00,0xc3,0x3f,0x80,0x7f,
    0xfc,0x7f,0x0f,0x00,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xc0,0x3f,
    0xbf,0xe1,0x1f,0xc0,0x00,0xfe,0xbf,0x07,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x1f,0xc0,0x7f,0xe0,0xe0,0xdf,0xf0,0x0f,
    0x03,0x00,0xff,0xdf,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xef,0x01,0x80,0xff,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0xff,0xf7,0x00,0xc0,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0xff,0x7b,0x00,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x00,0xf0,0xff,0x3d,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0x1e,0x00,0xf8,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x7f,0x0f,0x00,0xfc,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0xbf,0x07,0x00,
    0xfc,0x07,0xfe,0x01,0x0d,0xff,0x00,0xfe,
    0xf0,0x1f,0xf8,0x07,0x37,0xfc,0x03,0xf8,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0xdf,0x03,0x00,0xfe,0x03,0xff,
    0xff,0x86,0x7f,0x00,0x03,0xf8,0x0f,0xfc,
    0xfc,0x1b,0xfe,0x01,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x01,0x80,0xff,0xef,
    0x7f,0x00,0xff,0x81,0x80,0x7f,0xc3,0x3f,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xf7,0x00,0xc0,0xff,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0xff,0x7b,0x00,0xe0,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0x81,0x7f,0x00,0xc3,0x3f,0x80,0x7f,
    0xfc,0x07,0xfe,0x01,0x0d,0xff,0x00,0xfe,
    0xf0,0xff,0x3d,0x00,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xc0,0x3f,
    0xbf,0xe1,0x1f,0xc0,0x00,0xfe,0x03,0xff,
    0xff,0x86,0x7f,0x00,0x00,0xf8,0xff,0x1e,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x1f,0xc0,0x7f,0xe0,0xe0,0xdf,0xf0,0x0f,
    0x7f,0x00,0xff,0x81,0x80,0x7f,0xc3,0x3f,
    0x0f,0x00,0xfc,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0xbf,0x07,0x00,0xfe,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0xdf,0x03,0x00,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xef,0x01,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x00,0xc0,0xff,0xf7,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0x7b,0x00,0xe0,0xff,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0xff,0x3d,0x00,0xf0,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0xff,0x1e,0x00,
    0xf0,0x1f,0xf8,0x07,0x37,0xfc,0x03,0xf8,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x00,0xfc,0x7f,0x0f,0x03,0xf8,0x0f,0xfc,
    0xfc,0x1b,0xfe,0x01,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0x07,0x00,0xfe,0xbf,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0xdf,0x03,0x00,0xff,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xef,0x01,0x80,
    };

    unsigned char k8_ucode_0f50[] = {
    0x04,0x20,0x25,0x02,0x41,0x00,0x00,0x00,
    0x00,0x80,0x20,0x00,0xfd,0x6a,0x5a,0x3e,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x50,0x01,0x00,0x00,0x00,0xaa,0xaa,0xaa,
    0x44,0x06,0x00,0x00,0x40,0x01,0x00,0x00,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xfb,0xff,0x00,0xc3,0x35,0x90,0xfd,
    0xf8,0x7b,0xfe,0xa9,0x0f,0xff,0x00,0x3f,
    0xfe,0xdf,0xff,0xc7,0x1e,0xbc,0x03,0x3c,
    0x80,0xc8,0xd5,0x00,0x14,0xfe,0xff,0xff,
    0xfe,0xe1,0x1f,0xeb,0x4c,0xf6,0x3c,0xff,
    0x9f,0x87,0x7f,0x80,0x27,0x60,0x26,0xf0,
    0x74,0x1d,0xfe,0x18,0x00,0x20,0xe4,0x6a,
    0xcf,0xfb,0xff,0xe7,0xf0,0xf3,0xf0,0x0f,
    0x3f,0xee,0xff,0x9f,0x40,0xe4,0xc3,0x1b,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0x35,0x00,0xe0,0xeb,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x30,0x1a,0x00,0x78,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0x81,0x7f,0x00,0xc3,0x3f,0x80,0x7f,
    0xfc,0x7f,0x0f,0x00,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xc0,0x3f,
    0xbf,0xe1,0x1f,0xc0,0x00,0xfe,0xbf,0x07,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x1f,0xc0,0x7f,0xe0,0xe0,0xdf,0xf0,0x0f,
    0x03,0x00,0xff,0xdf,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xef,0x01,0x80,0xff,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0xff,0xf7,0x00,0xc0,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0xff,0x7b,0x00,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x00,0xf0,0xff,0x3d,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0x1e,0x00,0xf8,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x7f,0x0f,0x00,0xfc,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0xbf,0x07,0x00,
    0xfc,0x07,0xfe,0x01,0x0d,0xff,0x00,0xfe,
    0xf0,0x1f,0xf8,0x07,0x37,0xfc,0x03,0xf8,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0xdf,0x03,0x00,0xfe,0x03,0xff,
    0xff,0x86,0x7f,0x00,0x03,0xf8,0x0f,0xfc,
    0xfc,0x1b,0xfe,0x01,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x01,0x80,0xff,0xef,
    0x7f,0x00,0xff,0x81,0x80,0x7f,0xc3,0x3f,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xf7,0x00,0xc0,0xff,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0xff,0x7b,0x00,0xe0,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0x81,0x7f,0x00,0xc3,0x3f,0x80,0x7f,
    0xfc,0x07,0xfe,0x01,0x0d,0xff,0x00,0xfe,
    0xf0,0xff,0x3d,0x00,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xc0,0x3f,
    0xbf,0xe1,0x1f,0xc0,0x00,0xfe,0x03,0xff,
    0xff,0x86,0x7f,0x00,0x00,0xf8,0xff,0x1e,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x1f,0xc0,0x7f,0xe0,0xe0,0xdf,0xf0,0x0f,
    0x7f,0x00,0xff,0x81,0x80,0x7f,0xc3,0x3f,
    0x0f,0x00,0xfc,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0xf0,0x0f,0xe0,0x3f,
    0x07,0xf0,0x6f,0xf8,0xc0,0x3f,0x80,0xff,
    0x1f,0xc0,0xbf,0xe1,0xbf,0x07,0x00,0xfe,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0x1f,0xf8,0x07,0xf0,0xfc,0x03,0xf8,0x37,
    0x7f,0xe0,0x1f,0xc0,0xf0,0x0f,0xe0,0xdf,
    0xff,0xdf,0x03,0x00,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0x0f,0xfc,0x03,
    0x1b,0xfe,0x01,0xfc,0xe0,0x3f,0xf0,0x0f,
    0x6f,0xf8,0x07,0xf0,0x80,0xff,0xef,0x01,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x01,0xfc,0x07,0xfe,0xfe,0x0d,0xff,0x00,
    0x07,0xf0,0x1f,0xf8,0xf8,0x37,0xfc,0x03,
    0x00,0xc0,0xff,0xf7,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0xff,0x00,0xfe,0x03,
    0x00,0xff,0x86,0x7f,0xfc,0x03,0xf8,0x0f,
    0x01,0xfc,0x1b,0xfe,0x7b,0x00,0xe0,0xff,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0x81,0x7f,0x00,0xff,0x3f,0x80,0x7f,0xc3,
    0x07,0xfe,0x01,0xfc,0xff,0x00,0xfe,0x0d,
    0xff,0x3d,0x00,0xf0,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xc0,0x3f,0x80,
    0xe1,0x1f,0xc0,0xbf,0xfe,0x03,0xff,0x00,
    0x86,0x7f,0x00,0xff,0xf8,0xff,0x1e,0x00,
    0xf0,0x1f,0xf8,0x07,0x37,0xfc,0x03,0xf8,
    0xc0,0x7f,0xe0,0x1f,0xdf,0xf0,0x0f,0xe0,
    0x00,0xff,0x81,0x7f,0x7f,0xc3,0x3f,0x80,
    0x00,0xfc,0x7f,0x0f,0x03,0xf8,0x0f,0xfc,
    0xfc,0x1b,0xfe,0x01,0x0f,0xe0,0x3f,0xf0,
    0xf0,0x6f,0xf8,0x07,0x3f,0x80,0xff,0xc0,
    0xc0,0xbf,0xe1,0x1f,0x07,0x00,0xfe,0xbf,
    0xfe,0x01,0xfc,0x07,0x00,0xfe,0x0d,0xff,
    0xf8,0x07,0xf0,0x1f,0x03,0xf8,0x37,0xfc,
    0xe0,0x1f,0xc0,0x7f,0x0f,0xe0,0xdf,0xf0,
    0xdf,0x03,0x00,0xff,0x03,0xff,0x00,0xfe,
    0x7f,0x00,0xff,0x86,0x0f,0xfc,0x03,0xf8,
    0xfe,0x01,0xfc,0x1b,0x3f,0xf0,0x0f,0xe0,
    0xf8,0x07,0xf0,0x6f,0xff,0xef,0x01,0x80,
    };

    struct k8_ucode_header {
    W32 creation_date;
    W32 unknown1;
    W32 unknown2;
    W32 checksum;

    W32 unknown3;
    W32 unknown4;
    W32 cpuid;
    W32 signature; // 0xXXaaaaaa

    W32 unknown5;
    W32 unknown6;
    W32 unused[6];

    unsigned char ucode[];
    };

    static W32 print_cpuid(W32 cpuid) {
    int stepping, model, family, extmodel, extfam;

    stepping = (cpuid >> 0) & 0xf;
    model = (cpuid >> 4) & 0xf;
    family = (cpuid >> 8) & 0xf;
    extmodel = (cpuid >> 16) & 0xf;
    extfam = (cpuid >> 20) & 0xff;

    printk("k8-ucode: id 0x%08x -> "
             "family=%d model=%d stepping=%d extfam=%d extmodel=%d\n",
             cpuid, family, model, stepping, extfam, extmodel);

    return cpuid;
    }

    struct k8_ucode_set {
    W32 cpuid;
    unsigned char* ucode;
    };

    #define k8_ucode_set_count 3
    struct k8_ucode_set ucodeset[k8_ucode_set_count] = {
    {0x0f48, k8_ucode_0f48},
    {0x0f4a, k8_ucode_0f4a},
    {0x0f50, k8_ucode_0f50}
    };

    static unsigned char* find_ucode_for_cpu(void) {
    W32 id = cpuid_eax(0x00000001);
    int i = 0;

    for (i = 0; i < k8_ucode_set_count; i++) {
        if (ucodeset[i].cpuid == id)
          return ucodeset[i].ucode;
    }

    return NULL;
    }

    static W32 k8_ucode_checksum(unsigned char* ucode) {
    W32* p = (W32*)(ucode + 64);
    int i;
    W32 c = 0;

    for (i = 0; i < 896/4; i++) {
        c += p[i];
    }

    return c;
    }

    static void print_ucode_header(const struct k8_ucode_header* header) {
    printk("K8 microcode update header:\n");
    printk(" Creation date: %08x\n", header->creation_date);
    printk(" Checksum: %08x\n", header->checksum);
    printk(" CPUID: %08x\n", header->cpuid);
    printk(" Signature: %08x\n", header->signature);
    }

    #define MSR_K8_UCODE_UPDATE 0xc0010020
    #define K8_UCODE_HEADER_SIZE 64

    static int k8_ucode_update(unsigned char* address) {
    W64 tsc1, tsc2;
    int rc;

    printk("k8-ucode: Doing update from virtual address 0x%p\n", address);
    #if 1
    rdtscll(tsc1);
    // Actually perform the update:
    rc = checking_wrmsrl(MSR_K8_UCODE_UPDATE, (unsigned long long)address);
    rdtscll(tsc2);

    if (rc) {
        printk("k8-ucode: Error: update rejected by processor\n");
    } else {
        printk("k8-ucode: OK: update accepted by processor\n");
    }

    // ~5566 cycles with readable addr, (varies) with invalid addr
    printk("k8-ucode: Update took %lld clock cycles\n", tsc2 - tsc1);
    #endif

    print_cpuid(cpuid_eax(1));
    return rc;
    }

    static int __init k8_ucode_init(void) {
    W32 cpuid;
    W32 checksum;
    unsigned char* ucode;

            printk("k8-ucode loaded\n");

    if (cpuid_ebx(0) != 0x68747541) {
        // 0x68747541 = 'Auth'enticAMD
        printk("k8-ucode: this is not an AMD processor;"
              "k8-ucode will not work on it\n");
        return -ENOTSUPP;
    }

    cpuid = print_cpuid(cpuid_eax(1));

    ucode = find_ucode_for_cpu();

    if (!ucode) {
        printk("k8-ucode: no microcode update for cpuid 0x%08x is
    present\n", cpuid);
        return -ENOSYS;
    }

    printk("k8-ucode: Selected microcode update block for cpuid 0x%08x:\n",
    cpuid);
    print_ucode_header((struct k8_ucode_header*)ucode);

    checksum = k8_ucode_checksum(ucode);

    if (checksum != ((struct k8_ucode_header*)ucode)->checksum) {
        printk("k8-ucode: selected update block's expected checksum was
    0x%08x, "
              "but real checksum was %08x\n",
              ((struct k8_ucode_header*)ucode)->checksum, checksum);
        return -EINVAL;
    }

    k8_ucode_update(ucode);

    printk("k8-ucode: update done; unloading module\n");

    //
    // Return a pseudo-error so the module is immediately unloaded;
    // it has done all its work in the initialization phase.
    //
    return -EINPROGRESS;
    }

    static void __exit k8_ucode_exit(void) {
    // (should not get here)
    }

    module_init(k8_ucode_init)
    module_exit(k8_ucode_exit)

    ADDITIONAL INFORMATION

    The information has been provided by Anonymous.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[NT] FTP Glide Stores Login Information in Cleartext"

    Relevant Pages