summary refs log tree commit diff
path: root/security
diff options
context:
space:
mode:
authorMatthew Garrett <mjg59@google.com>2017-10-11 12:10:14 -0700
committerMimi Zohar <zohar@linux.vnet.ibm.com>2017-11-08 15:16:36 -0500
commitf00d79750712511d0a83c108eea0d44b680a915f (patch)
treef0bdb9499c9e6b7bb7c37ace6b70d25bc5035ac5 /security
parent096b85464832d2a7bd7bd6d4db2fafed2ab77244 (diff)
downloadlinux-f00d79750712511d0a83c108eea0d44b680a915f.tar.gz
EVM: Allow userspace to signal an RSA key has been loaded
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>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/evm/evm.h3
-rw-r--r--security/integrity/evm/evm_secfs.c29
2 files changed, 20 insertions, 12 deletions
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index f5f12727771a..241aca315b0c 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -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;
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index c8dccd54d501..319cf16d6603 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -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;
 }