EVM: Allow userspace to signal an RSA key has been loaded
authorMatthew Garrett <mjg59@google.com>
Wed, 11 Oct 2017 19:10:14 +0000 (12:10 -0700)
committerMimi Zohar <zohar@linux.vnet.ibm.com>
Wed, 8 Nov 2017 20:16:36 +0000 (15:16 -0500)
EVM will only perform validation once a key has been loaded. This key
may either be a symmetric trusted key (for HMAC validation and creation)
or the public half of an asymmetric key (for digital signature
validation). The /sys/kernel/security/evm interface allows userland to
signal that a symmetric key has been loaded, but does not allow userland
to signal that an asymmetric public key has been loaded.

This patch extends the interface to permit userspace to pass a bitmask
of loaded key types. It also allows userspace to block loading of a
symmetric key in order to avoid a compromised system from being able to
load an additional key type later.

Signed-off-by: Matthew Garrett <mjg59@google.com>
Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Documentation/ABI/testing/evm
security/integrity/evm/evm.h
security/integrity/evm/evm_secfs.c

index 8374d45..a0bbccb 100644 (file)
@@ -7,17 +7,36 @@ Description:
                HMAC-sha1 value across the extended attributes, storing the
                value as the extended attribute 'security.evm'.
 
-               EVM depends on the Kernel Key Retention System to provide it
-               with a trusted/encrypted key for the HMAC-sha1 operation.
-               The key is loaded onto the root's keyring using keyctl.  Until
-               EVM receives notification that the key has been successfully
-               loaded onto the keyring (echo 1 > <securityfs>/evm), EVM
-               can not create or validate the 'security.evm' xattr, but
-               returns INTEGRITY_UNKNOWN.  Loading the key and signaling EVM
-               should be done as early as possible.  Normally this is done
-               in the initramfs, which has already been measured as part
-               of the trusted boot.  For more information on creating and
-               loading existing trusted/encrypted keys, refer to:
-               Documentation/keys-trusted-encrypted.txt.  (A sample dracut
-               patch, which loads the trusted/encrypted key and enables
-               EVM, is available from http://linux-ima.sourceforge.net/#EVM.)
+               EVM supports two classes of security.evm. The first is
+               an HMAC-sha1 generated locally with a
+               trusted/encrypted key stored in the Kernel Key
+               Retention System. The second is a digital signature
+               generated either locally or remotely using an
+               asymmetric key. These keys are loaded onto root's
+               keyring using keyctl, and EVM is then enabled by
+               echoing a value to <securityfs>/evm:
+
+               1: enable HMAC validation and creation
+               2: enable digital signature validation
+               3: enable HMAC and digital signature validation and HMAC
+                  creation
+
+               Further writes will be blocked if HMAC support is enabled or
+               if bit 32 is set:
+
+               echo 0x80000002 ><securityfs>/evm
+
+               will enable digital signature validation and block
+               further writes to <securityfs>/evm.
+
+               Until this is done, EVM can not create or validate the
+               'security.evm' xattr, but returns INTEGRITY_UNKNOWN.
+               Loading keys and signaling EVM should be done as early
+               as possible.  Normally this is done in the initramfs,
+               which has already been measured as part of the trusted
+               boot.  For more information on creating and loading
+               existing trusted/encrypted keys, refer to:
+               Documentation/keys-trusted-encrypted.txt. Both dracut
+               (via 97masterkey and 98integrity) and systemd (via
+               core/ima-setup) have support for loading keys at boot
+               time.
index f5f1272..241aca3 100644 (file)
@@ -23,6 +23,9 @@
 
 #define EVM_INIT_HMAC  0x0001
 #define EVM_INIT_X509  0x0002
+#define EVM_SETUP       0x80000000 /* userland has signaled key load */
+
+#define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP)
 
 extern int evm_initialized;
 extern char *evm_hmac;
index c8dccd5..319cf16 100644 (file)
@@ -40,7 +40,7 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
        if (*ppos != 0)
                return 0;
 
-       sprintf(temp, "%d", evm_initialized);
+       sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP));
        rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));
 
        return rc;
@@ -61,24 +61,29 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,
 static ssize_t evm_write_key(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
-       char temp[80];
-       int i;
+       int i, ret;
 
-       if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC))
+       if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP))
                return -EPERM;
 
-       if (count >= sizeof(temp) || count == 0)
-               return -EINVAL;
-
-       if (copy_from_user(temp, buf, count) != 0)
-               return -EFAULT;
+       ret = kstrtoint_from_user(buf, count, 0, &i);
 
-       temp[count] = '\0';
+       if (ret)
+               return ret;
 
-       if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
+       /* Reject invalid values */
+       if (!i || (i & ~EVM_INIT_MASK) != 0)
                return -EINVAL;
 
-       evm_init_key();
+       if (i & EVM_INIT_HMAC) {
+               ret = evm_init_key();
+               if (ret != 0)
+                       return ret;
+               /* Forbid further writes after the symmetric key is loaded */
+               i |= EVM_SETUP;
+       }
+
+       evm_initialized |= i;
 
        return count;
 }