From patchwork Tue Oct 10 22:26:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 9998085 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 58799601AE for ; Tue, 10 Oct 2017 22:26:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4ABC5287DB for ; Tue, 10 Oct 2017 22:26:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3DE44287E0; Tue, 10 Oct 2017 22:26:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AECBB287DB for ; Tue, 10 Oct 2017 22:26:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756596AbdJJW0Z (ORCPT ); Tue, 10 Oct 2017 18:26:25 -0400 Received: from mail-qt0-f201.google.com ([209.85.216.201]:63027 "EHLO mail-qt0-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756166AbdJJW0Y (ORCPT ); Tue, 10 Oct 2017 18:26:24 -0400 Received: by mail-qt0-f201.google.com with SMTP id z19so11628qtg.21 for ; Tue, 10 Oct 2017 15:26:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:date:message-id:subject:from:to:cc; bh=0Bd/nwU/TGyGvrA+dd6nFWLZDV5E6t0jGqY+lmXdRoM=; b=WNwwwUQIpQyuHG8IvaGQ78PeIXZzVilDia4ZJ9LGFKg/8r/QRY0XF+FCnHYvUciGpw hDgU8GOYLVuMGu/mPraQgb1rpUp2JYSCSW+iJXgDewLm6ADw5fGlJd22QY6kd3RcizGQ zFbiD/5fDxpjP3gCwohj1fY0+oqVJz8BLhZihBYx+6Dqnr+UP6Ul82nm0f4Nz/86I2YP HP3/vEKHwj//ez1CtpXY8s3SwI2rbWEm1YoL3eRJNLKLZC0kJ5v84YfSlxdGPtlgwV+b ryeqTvMBLlYdUjZzaIWLm/6srBmoLzhLZ7o5d4jTtBelSMtuxi9L6IEQxvq2PBYgQUdf m5/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:date:message-id:subject:from:to:cc; bh=0Bd/nwU/TGyGvrA+dd6nFWLZDV5E6t0jGqY+lmXdRoM=; b=I29l7XEfduOjxFqHlZfa/FxkLWk54vklMKI3e/12KubQqHul+/BdqVES4ehDNcTq+q Zggcek/jx4u8uD9n+Qh0JBIHTGpddprcQmcofXHZyeUD1j+idhqdt285hUK4vmQ6JG7k KVny6SULb4Eoz8CxAR2VKnpYx6d0FDpGqtKiGL4WjoOt+HJqtQFp5p/YEDcn8agxsp3Q QIZwUXSHckjvtvveePBvJBmPyANFMB3j0p6Dey9UuXII6EUZAJy/FSSPeQFYlLChwfD7 /vno1TLy4Se0rWYo+zjHh4O335Vyg605w9Q6EQh4Uw7D7DoLNBtxJAjjrsFEGQZWypOJ UitA== X-Gm-Message-State: AMCzsaUUEBpL2z8RTAx1R8yLTGudJHNcOQa/7fL9SxAwJyaHRHcIMKxA TMGp/na9jk6OExzsmxNdqVFLXty2Q91D9s2qZ+7gVWEB1tLLE/m+H5R3zkoGg/IjEGdPVFxU2Ux hbGuuurWli365QPgbJ6aAcpUjv24hnDvOJ2k= X-Google-Smtp-Source: AOwi7QCNmyp+g92Gz3ynHMe+4fYCecEIOjITxxeLs4VQt2ETCke46a7c3MyEjN/qr6Wxi9ZnjaiCBxB6P8zKQ2GKKZ27FA== MIME-Version: 1.0 X-Received: by 10.55.160.15 with SMTP id j15mr11418164qke.0.1507674383453; Tue, 10 Oct 2017 15:26:23 -0700 (PDT) Date: Tue, 10 Oct 2017 15:26:09 -0700 Message-Id: <20171010222609.5185-1-mjg59@google.com> X-Mailer: git-send-email 2.14.2.920.gcf0c67979c-goog Subject: [PATCH] EVM: Allow userspace to signal an RSA key has been loaded From: Matthew Garrett To: linux-integrity@vger.kernel.org Cc: zohar@linux.vnet.ibm.com, Matthew Garrett Sender: linux-integrity-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 is a write-once interface in order to avoid a compromised system from being able to load an additional key type later. Signed-off-by: Matthew Garrett --- Documentation/ABI/testing/evm | 39 ++++++++++++++++++++++++-------------- security/integrity/evm/evm.h | 3 +++ security/integrity/evm/evm_secfs.c | 27 ++++++++++++++------------ 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/Documentation/ABI/testing/evm b/Documentation/ABI/testing/evm index 8374d4557e5d..0463c3339bb1 100644 --- a/Documentation/ABI/testing/evm +++ b/Documentation/ABI/testing/evm @@ -7,17 +7,28 @@ 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 > /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 /evm: + + 1: enable HMAC validation and creation + 2: enable digital signature validation + 3: enable HMAC and digital signature validation and HMAC + creation + + 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. (A sample + dracut patch, which loads the trusted/encrypted key + and enables EVM, is available from + http://linux-ima.sourceforge.net/#EVM.) diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 2ff02459fcfd..abbe8f4302ed 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) 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..c7bc38a7ca94 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,27 @@ 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; + } + + evm_initialized |= (i|EVM_SETUP); return count; }