Translate

Image of Advanced Programming in the UNIX Environment, Second Edition (Addison-Wesley Professional Computing Series)
Image of Modern Operating Systems (3rd Edition)
Image of Operating System Concepts
Image of Android Wireless Application Development

Lenovo T430, T530 Now Support UEFI Secure Boot

A recent firmware update (version 2.05, dated 9/12/2012) for the Lenovo T430 (and T430i) provided support for UEFI (Unified Extensible Firmware Interface) Secure Boot. The previous firmware version for the Lenovo T430 was 1.20 dated 8/7/2012. A similar firmware update is available for the Lenovo T530 and T530i. This support was added in order to enable the soon-to-be-released Windows 8 to run on these laptops.

As you all probably know by now, devices conforming to the Windows Certification Program (previously known as the Windows Logo Program), and running a client version of Windows 8, must ship with Secure Boot enabled by default. The basic idea behind Secure Boot is to enhance protection against malware by preventing PCs from loading unauthorized binaries when booting. X86 and X86_64 devices must provide an option to disable Secure Boot whilst ARM-based devices must not provide the option. Secure Boot requires devices to use UEFI instead of the traditional BIOS.

This was the only UEFI related screen on the T430 prior to the firmware update:

Here are screenshots of the additional UEFI security screens and menu options available on the T430 after the firmware update:






Apologies for the poor photography!

With this firmware version, if you choose to enable OS Optimized Defaults, Secure Boot and Secure Rollback Prevention are enabled, CSM (Compatibility Support Module) is disabled, UEFI/Legacy Boot Priority is not displayed and only UEFI booting is supported. When you upgrade to this firmware version, Secure Boot is not enabled by default, you have to specifically enable Secure Boot and restore the Factory Keys. I am not sure what Lenovo means by Factory Keys. I assume that this means the PK, KEK and db and maybe dbx NVRAM variables are appropriately set. I will have to investigate further.

Interestingly, the Lenovo Update tool does not install this firmware update automatically. You have to download and install it yourself. The release notes for this firmware upgrade also include memory map information for UEFI (E0000-FFFFF), graphics cards (C0000-CFFFF or C0000-CE1FF) and Ethernet NIC option ROM (D0000-D0FFF or CE200-CF1FF). I have not noticed that information in previous Lenovo BIOS upgrade release notes. See the release notes for more information.

Here is a small UEFI utility for Lenovo firmware which will print out the current values of the SecureBoot and SetupMode NVRAM variables along with other useful information from the NVRAM. The full source code and makefile are available at GitHub.

//
//  Copyright (c) 2012  Finnbarr P. Murphy.   All rights reserved.
//
//  Display Lenovo UEFI Secure Boot variables and some other information.
//
//  License: BSD License
//

#include <efi.h>
#include <efilib.h>

#define BUFSIZE 64

#define LENOVO_FIRMWARE_GUID \
   (EFI_GUID) {0xe5bbf7be, 0x2417, 0x499b, {0x97,0xdb,0x39,0xf4,0x89,0x63,0x91,0xbc}}

#define EFI_SHELL_INTERFACE_GUID \
   (EFI_GUID) {0x47c7b223, 0xc42a, 0x11d2, {0x8e,0x57,0x00,0xa0,0xc9,0x69,0x72,0x3b}}

typedef enum {
    ARG_NO_ATTRIB         = 0x0,
    ARG_IS_QUOTED         = 0x1,
    ARG_PARTIALLY_QUOTED  = 0x2,
    ARG_FIRST_HALF_QUOTED = 0x4,
    ARG_FIRST_CHAR_IS_ESC = 0x8
} EFI_SHELL_ARG_INFO_TYPES;

struct _EFI_SHELL_ARG_INFO {
    UINT32 Attributes;
} __attribute__((packed)) __attribute__((aligned (1)));
typedef struct _EFI_SHELL_ARG_INFO EFI_SHELL_ARG_INFO;

struct _EFI_SHELL_INTERFACE {
    EFI_HANDLE           ImageHandle;
    EFI_LOADED_IMAGE    *Info;
    CHAR16             **Argv;
    UINTN                Argc;
    CHAR16             **RedirArgv;
    UINTN                RedirArgc;
    EFI_FILE            *StdIn;
    EFI_FILE            *StdOut;
    EFI_FILE            *StdErr;
    EFI_SHELL_ARG_INFO  *ArgInfo;
    BOOLEAN              EchoOn;
} __attribute__((packed)) __attribute__((aligned (1)));
typedef struct _EFI_SHELL_INTERFACE EFI_SHELL_INTERFACE;


CHAR16 *
ASCII_to_UCS2(const char *s, int len)
{
    CHAR16 *ret = NULL;
    int i;

    ret = AllocateZeroPool(len*2 + 2);
    if (!ret)
        return NULL;

    for (i = 0; i < len; i++)
        ret[i] = s[i];

    return ret;
}


static EFI_STATUS
get_args(EFI_HANDLE image, UINTN *argc, CHAR16 ***argv)
{
    EFI_STATUS status;
    EFI_SHELL_INTERFACE *shell;
    EFI_GUID gEfiShellInterfaceGuid = EFI_SHELL_INTERFACE_GUID;

    status = uefi_call_wrapper(BS->OpenProtocol, 6,
                               image, &gEfiShellInterfaceGuid,
                               (VOID **)&shell, image, NULL,
                               EFI_OPEN_PROTOCOL_GET_PROTOCOL);
    if (EFI_ERROR(status))
        return status;

    *argc = shell->Argc;
    *argv = shell->Argv;

    status = uefi_call_wrapper(BS->CloseProtocol, 4, image,
                               &gEfiShellInterfaceGuid, image, NULL);
    return status;
}


static void
usage(void)
{
    Print(L"Usage: showlenovo [-v|--verbose]\n");
}


EFI_STATUS
efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
    EFI_STATUS status = EFI_SUCCESS;
    EFI_GUID Guid = EFI_GLOBAL_VARIABLE;
    EFI_GUID LenovoGuid = LENOVO_FIRMWARE_GUID;
    UINT8 IntData;
    UINTN DataSize;
    char Data[BUFSIZE];
    BOOLEAN Verbose = FALSE;
    UINTN argc;
    CHAR16 **argv;
    CHAR16 *ptr;

    InitializeLib(image, systab);

    status = get_args(image, &argc, &argv);
    if (EFI_ERROR(status)) {
        Print(L"ERROR: Parsing command line arguments: %d\n", status);
       return status;
    }

    if (argc > 2) {
        usage();
        return EFI_INVALID_PARAMETER;
    } else if (argc == 2 ) {
        if (!StrCmp(argv[1], L"--help") ||
            !StrCmp(argv[1], L"-h") ||
            !StrCmp(argv[1], L"-?")) {
            usage();
            return EFI_SUCCESS;
        } else if (!StrCmp(argv[1], L"--verbose") ||
                   !StrCmp(argv[1], L"-v")) {
             Verbose = TRUE; 
        } else {
            usage();
            return EFI_INVALID_PARAMETER;
        }
    }

    ZeroMem(Data, BUFSIZE);
    DataSize = BUFSIZE;
    status = uefi_call_wrapper(RT->GetVariable, 5,
             L"BuildDate", &LenovoGuid, NULL, &DataSize, &Data);
    if (status != EFI_SUCCESS) {
        Print(L"ERROR: BuildDate variable not found.\n");
        return status;
    }
    ptr = ASCII_to_UCS2(Data, DataSize);
    Print(L"Build Date: %s\n", ptr);
    FreePool(ptr);

    ZeroMem(Data, BUFSIZE);
    DataSize = BUFSIZE;
    status = uefi_call_wrapper(RT->GetVariable, 5,
             L"BuildTime", &LenovoGuid, NULL, &DataSize, &Data);
    if (status != EFI_SUCCESS) {
        Print(L"ERROR: BuildTime variable not found.\n");
        return status;
    }
    ptr = ASCII_to_UCS2(Data, DataSize);
    Print(L"Build Time: %s\n", ptr);
    FreePool(ptr);

    status = uefi_call_wrapper(RT->GetVariable, 5, 
                               L"SimpleBootFlag", &Guid, NULL, &DataSize, &IntData);
    if (status != EFI_SUCCESS) {
        Print(L"ERROR: SimpleBootFlag variable not found.\n");
        return status;
    }
    Print(L"SimpleBootFlag: %d\n", IntData);

    status = uefi_call_wrapper(RT->GetVariable, 5, 
                               L"SecureBoot", &Guid, NULL, &DataSize, &IntData);
    if (status != EFI_SUCCESS) {
        Print(L"ERROR: SecureBoot variable not found.\n");
        return status;
    }
    if (Verbose) {
       if (IntData) {
           Print(L"Secure Boot: Enabled\n");
       } else {
           Print(L"Secure Boot: Disabled\n");
       }
    } else {
        Print(L"SecureBoot: %d\n", IntData);
    }

    status = uefi_call_wrapper(RT->GetVariable, 5, 
                               L"SetupMode", &Guid, NULL, &DataSize, &IntData);
    if (status != EFI_SUCCESS) {
        Print(L"ERROR: SetupMode variable not found.\n");
        return status;
    }
    if (Verbose) {
        if (IntData) {
            Print(L"Secure Boot Setup Mode: Enabled\n");
        } else {
            Print(L"Secure Boot Setup Mode: Disabled\n");
        }
    } else {
        Print(L"SetupMode: %d\n", IntData);
    }

    return status;
}


To compile, you need the gnu_efi package installed. The ASCII_TO_UCS2 routine is required because Lenovo store the strings the utility wants, i.e build date and build time, as ASCII strings but these strings can only be displayed on your console as UCS2.

Here is what the utility outputs on a Lenovo T430 laptop:

Build Date: 09/12/12
Build Time: 13:13:11
SimpleBootFlag: 0
SecureBoot: 0
SetupMode: 1


By the way, Linus Torvalds doesn’t think Microsoft’s decision to require UEFI secure boot in Windows 8 is going to make any significant change to the security of their operating system.

“The real problem, I feel, is that clever hackers will bypass the whole key issue either by getting a key of their own (how many of those private keys have stayed really private again? Oh, that’s right, pretty much none of them) or they’ll just take advantage of security bugs in signed software to bypass it without a key at all.”

I tend to agree.

I like to boot Linux directly from the UEFI boot manager using the EFI STUB mechanism and dispense with GRUB altogether. With Secure Boot enabled, this is no longer possible at present without a shim layer. Hopefully this limitation will be overcome in the future.

Comments are closed.