diff --git a/Makefile b/Makefile index 8ed9e99..e447274 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,6 @@ DIRS = striplic 3rdparty posix lsvmutils lsvmtool lsvmload policy all: $(foreach i, $(DIRS), $(MAKE) -C $(i) $(NL) ) - $(MAKE) -C lsvmtool autotests ##============================================================================== ## @@ -144,12 +143,13 @@ DISTEXCLUDE = \ dist: + @ rm -rf $(TOP)/$(SRCPKGNAME).tar.gz @ rm -rf $(SRCDIRNAME) @ cp -r $(TOP) $(SRCDIRNAME) @ rm -rf $(DISTEXCLUDE) @ ( cd $(SRCDIRNAME); $(MAKE) -s distclean ) - @ ( cd /tmp; tar zcf $(SRCPKGNAME).tar.gz $(SRCPKGNAME) ) - @ echo "Created /tmp/$(SRCPKGNAME).tar.gz" + @ ( cd /tmp; tar zcf $(TOP)/$(SRCPKGNAME).tar.gz $(SRCPKGNAME) ) + @ echo "Created $(TOP)/$(SRCPKGNAME).tar.gz" ##============================================================================== ## diff --git a/README.md b/README.md index 41961f3..65f852f 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,206 @@ -# vmshield -Linux project for Microsoft Shielded VM project +LSVMTools +========= +Overview +-------- -### How to install LSVMTools: +The LSVMTools project provides tools for shielding Linux VMs operating +in the Microsoft(R) Windows Hyper-V environment. LSVMTools aims to protect +Linux VMs from attack while at rest and in flight. It builds on the following +technologies. -1. Configure the distribution: +- Windows Server 2016 Guarded Fabric +- Hyper-V Shielded VMs +- UEFI +- TPM 2.0 +- Linux Unified Key Setup (LUKS) +- dm-crypt - `./configure` +LSVMTools provides two main tools. -2. Build the distribution: +- **LSVMPREP** - Prepares the image for shielding +- **LSVMLOAD** - The primary boot loader for the image - `make` +### LSVMPREP -3. Install LSVMTools (under /opt/lsvmtools-1.0.0): +**LVSMPREP** prepares the Linux enviroment for shielding. After the image +is prepared, it must be templatized and provisioned as described in the +[LSVM How-To](doc/LSVM_How_To.pdf) document. LSVMPREP performs the following +steps. - `make install` +- Encrypts the boot partition with a well-known passphrase +- Patches the system to automatically mount the encyrpted boot parition +- Installs LSVMLOAD on the EFI System Partition (ESP) +- TPM-seals the passphrases and stores them on the ESP +- Copies the SHIM and GRUB2 to the encrypted boot partition +- Patches the initial ramdisk configuration to get passphrases non-interactively +- Regenerates the initial ramdisks and GRUB2 configuration +- Applies any UEFI dbx updates (for black-listed boot loaders) -4. Prepare an image for shielding: +After these steps are performed, the image is ready to be templatized. See +the [LSVM How-To](doc/LSVM_How_To.pdf) document for details. - `cd /opt/lsvmtools-1.0.0` - `./lsvmprep` +### LSVMLOAD -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +**LSVMLOAD** becomes the primary EFI boot loader for the Linux VM. UEFI loads +LSVMLOAD, assuming it passes certificate verification (**LSVMLOAD** must be +signed by a certificate that Hyper-V trusts). **LSVMLOAD** performs the +following steps. -### Code of Conduct +- Uses TPM to unseal a **keyfile** (containing the disk partition passphrases) +- Maps the ESP onto an **ESP ramdisk** +- Maps the encrypted boot partition onto an unencrypted **boot ramdisk** +- Patches the initial ramdisk with the **keyfile** (on the boot ramdisk) +- Loads the Linux SHIM from the **boot ramdisk** +- Launches the SHIM, which is redirected to the **ESP ramdisk** -This project has adopted the [Microsoft Open Source Code of Conduct] -(https://opensource.microsoft.com/codeofconduct/). For more -information see the [Code of Conduct FAQ] -(https://opensource.microsoft.com/codeofconduct/faq/) or contact -[opencode@microsoft.com](mailto:opencode@microsoft.com) with any -additional questions or comments. +The SHIM finds GRUB2 on the **ESP ramdisk** (copied from the encrypted boot +partition by LSVMLOAD). The SHIM executes GRUB2, which is redirected to the +**boot ramdisk**, where it finds: + +- A patched GRUB2 configuration file +- A patched initial ramdisk (patched by LSVMLOAD with the **keyfile**) +- The Linux kernel + +GRUB2 executes the kernel and the initial ramdisk. The initial ramdisk mounts +the boot and root partitions using the **keyfile** injected by LSVMLOAD. + +LSVMLOAD works using unmodified SHIM and GRUB2 executables, making it +possible to configure a Linux environment for shielding without having +to change any programs along the boot chain. + +Supported Linux distributions +----------------------------- + +LSVMTool current supports the following Linux distributions. + +- Ubuntu 16.04 LTS with the 4.4 kernel +- Red Hat Enterprise Linux 7.3 +- SUSE Linux Enterprise Server 12 Service Pack 2 + +Installing +---------- + +This section explains how to install from a binary distribution. Binary +distributions can be downloaded from the following link. + +- [Binary Distributions](binaries) + +These distributions include **LSVMPREP** and a signed **LSVMLOAD**. + +Use the following commands to install the distibution. + +``` +# tar zxvf lsvmtools-1.0.0-x86_64.tar.gz +# cd lsvmtools-1.0.0-x86_64 +# ./install + +Created /opt/lsvmtools-1.0.0 +``` + +This installs LSVMTools in the following location. + +``` +/opt/lsvmtools-1.0.0 +``` + +Running LSVMPREP +---------------- + +**Caution: Running LSVMPREP encrypts the boot partition and makes irreversible +configuration changes to a virtual machine. Only run LSVMPREP to prepare an +image for templatization.** + +To run LSVMPREP, execute the following commands as root. + +``` +# cd /opt/lsvmtools-1.0.0 +# ./lsvmprep + +*************************************************** +* ____ _ _ _ _____ ___ ___ _ _ * +* / ___| / \ | | | |_ _|_ _/ _ \| \ | | * +* | | / _ \| | | | | | | | | | | \| | * +* | |___ / ___ \ |_| | | | | | |_| | |\ | * +* \____/_/ \_\___/ |_| |___\___/|_| \_| * +* * +* * +* LSVMPREP is about to encrypt the boot partition * +* and make irreversible configuration changes to * +* this machine. If you are certain you want to * +* proceed, type YES in uppercase and then press * +* enter; else press ENTER to terminate. * +* * +*************************************************** + +> _ +``` + +If LSVMPREP runs successfully, the image is ready to be templatized. See +[LSVM How-To](doc/LSVM_How_To.pdf) for what to do next. + +Building +-------- + +This section explains how to build LSVMTools from source, but note that +LSVMPREP requires a signed LSVMLOAD image, which must be downloaded separately +(see the previous section for details). + +To build LSVMTools, type these commands. + +``` +# ./configure +# make +``` + +These commands build LSVMPREP and an unsigned LSVMLOAD. + +To run the tests, type: + +``` +# make tests +``` +Recovering the LUKS keys +------------------------ + +In case anything goes wrong, use the following command to recover LUKS keys. + +``` +# dmsetup table --showkeys +``` + +License +------- + +``` +LSVMTools + +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE +``` + +Code of Conduct +--------------- + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/binaries/README.md b/binaries/README.md new file mode 100644 index 0000000..43d2c87 --- /dev/null +++ b/binaries/README.md @@ -0,0 +1,8 @@ +LSVMTools Binary Distributions +============================== + +Binary Distributions +-------------------- + +- [lsvmtools-1.0.0-x86_64.tar.gz](lsvmtools-1.0.0-x86_64.tar.gz) + diff --git a/binaries/lsvmtools-1.0.0-x86_64.tar.gz b/binaries/lsvmtools-1.0.0-x86_64.tar.gz new file mode 100644 index 0000000..acf1f58 Binary files /dev/null and b/binaries/lsvmtools-1.0.0-x86_64.tar.gz differ diff --git a/doc/LSVM_How_To.docx b/doc/LSVM_How_To.docx new file mode 100644 index 0000000..d30fdb3 Binary files /dev/null and b/doc/LSVM_How_To.docx differ diff --git a/doc/LSVM_How_To.pdf b/doc/LSVM_How_To.pdf new file mode 100644 index 0000000..c7b7bd4 Binary files /dev/null and b/doc/LSVM_How_To.pdf differ diff --git a/lsvmload/initrd.c b/lsvmload/initrd.c index d43903f..347d455 100644 --- a/lsvmload/initrd.c +++ b/lsvmload/initrd.c @@ -136,7 +136,7 @@ int PatchInitrd( goto done; } - PutProgress(L"Pathching %a", Str(initrdPath)); + PutProgress(L"Patching %a", Str(initrdPath)); /* Inject keys into this initrd */ { diff --git a/lsvmprep b/lsvmprep index 7f45455..178a9fe 100755 --- a/lsvmprep +++ b/lsvmprep @@ -150,6 +150,74 @@ case ${vendor} in exit 1 esac +##============================================================================== +## +## Ask for permissio to change the system +## +##============================================================================== + + +ask_permission() +{ +cat< " + read answer + echo "" + + if [ "${answer}" != "YES" ]; then + echo "$0: no action taken" + echo "" + exit 1 + fi +} + +ask_permission + +##============================================================================== +## +## check_root() +## +##============================================================================== + +check_root_passphrase() +{ + rootdev=`./scripts/rootdev` + + if [ -z "${rootdev}" ]; then + echo "$0: failed to resolve root partition" + exit 1 + fi + + echo -n "passphrase" | cryptsetup luksDump --dump-master-key --key-file=- $rootdev 2> /dev/null > /dev/null + + if [ "$?" != "0" ]; then + echo "$0: ERROR: The root partition passphrase must be 'passphrase'" + echo "" + exit 1 + fi +} + +check_root_passphrase + ##============================================================================== ## ## Resolve 'shim': @@ -825,3 +893,23 @@ cp VERSION ${lsvmprepfile} # Run sanity check: ./sanity + +##============================================================================== +## +## final_word() +## +##============================================================================== + +final_word() +{ +cat< /dev/null > /dev/null ) + tests: @ $(MAKE) -s cpio-tests @ $(MAKE) -s ext2-tests MKE2FSFLAGS="-b 1024" @@ -384,18 +383,12 @@ tests: @ $(MAKE) -s strtok-tests @ $(MAKE) -s test-crypt @ $(MAKE) -s sha-tests - -tpm-tests: +ifeq ($(HAS_TPM),yes) @ $(MAKE) -s test-seal @ $(MAKE) -s lsvmtool-tests @ $(MAKE) -s test-pcrs @ $(MAKE) -s test-pcrs256 - -$(AUTOTESTS): $(LSVMTOOL) - @ $(MAKE) -s tests - @ touch $(AUTOTESTS) - -autotests: $(AUTOTESTS) +endif ##============================================================================== ## @@ -423,3 +416,5 @@ seal: @ echo -n "ABCDEFGHIJKLMNOPQRSTUVWXYZ" > ALPHABET.in $(LSVMTOOL) seallsvmloadpolicy $(BOOTLOADER) ALPHABET.in ALPHABET.out +hastpm: + $(BINDIR)/lsvmtool hastpm diff --git a/lsvmtool/lsvmtoolmain.c b/lsvmtool/lsvmtoolmain.c index 66b4d0f..8471cf4 100644 --- a/lsvmtool/lsvmtoolmain.c +++ b/lsvmtool/lsvmtoolmain.c @@ -124,6 +124,7 @@ static EFI_TCG2_PROTOCOL* _GetTPMProtocol() if (!(protocol = TCG2_GetProtocol())) { fprintf(stderr, "Warning: TCG2_GetProtocol() failed\n"); + exit(1); } #if defined(__linux__) @@ -151,20 +152,25 @@ static EFI_TCG2_PROTOCOL* _GetTPMProtocol() return protocol; } -static void _TestIsTPMPresent() +static BOOLEAN _IsTPMPresent() { - EFI_TCG2_PROTOCOL* protocol = _GetTPMProtocol(); - EFI_STATUS status; + static EFI_TCG2_PROTOCOL* protocol = NULL; EFI_TCG2_BOOT_SERVICE_CAPABILITY capability; + TPM_RC rc; - printf("=== TestIsTPMPresent()\n"); + if (!(protocol = TCG2_GetProtocol())) + return FALSE; - status = TCG2_GetCapability(protocol, &capability); + if (TCG2_GetCapability(protocol, &capability) != EFI_SUCCESS) + return FALSE; - if (status != EFI_SUCCESS) - assert(0); + if (capability.TPMPresentFlag != TRUE) + return FALSE; - assert(capability.TPMPresentFlag == TRUE); + if ((rc = TPM2X_SetDictionaryAttackLockReset(protocol)) != TPM_RC_SUCCESS) + return FALSE; + + return TRUE; } static void _TestGetTPMRevision() @@ -2015,7 +2021,6 @@ static int _tests_command( const char** argv) { EFI_TCG2_PROTOCOL* protocol = _GetTPMProtocol(); - _TestIsTPMPresent(protocol); _TestGetTPMRevision(protocol); #if !defined(_WIN32) _TestSetDictionaryAttackLockReset(protocol); @@ -4624,6 +4629,29 @@ done: return status; } +static int _hastpm( + int argc, + const char **argv) +{ + int status = 1; + + if (argc != 1) + { + fprintf(stderr, "Usage: %s\n", argv[0]); + goto done; + } + + if (_IsTPMPresent()) + printf("yes\n"); + else + printf("no\n"); + + status = 0; + +done: + return status; +} + /* **============================================================================== ** @@ -5019,6 +5047,11 @@ static Command _commands[] = "Deserializes the specialization file", _deserialize_specfile_command, }, + { + "hastpm", + "Checks whether TPM is present or not", + _hastpm, + }, }; static size_t _ncommands = sizeof(_commands) / sizeof(_commands[0]); @@ -5110,6 +5143,4 @@ int lsvmtool_main(int argc, const char* argv[]) fprintf(stderr, "%s: unknown command: '%s'\n", argv[0], argv[1]); return 1; - - return 0; } diff --git a/scripts/install b/scripts/install index 3776861..d0b8664 100755 --- a/scripts/install +++ b/scripts/install @@ -66,3 +66,7 @@ install_lsvmtool() } install_lsvmtool ${lsvmtool} + +echo "" +echo "Created ${destdirname}" +echo ""