From patchwork Thu Jan 3 14:32:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chun-Yi Lee X-Patchwork-Id: 10747445 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 493CF91E for ; Thu, 3 Jan 2019 14:32:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 38845212E8 for ; Thu, 3 Jan 2019 14:32:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2C1D6285DB; Thu, 3 Jan 2019 14:32:52 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,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 67783212E8 for ; Thu, 3 Jan 2019 14:32:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731939AbfACOco (ORCPT ); Thu, 3 Jan 2019 09:32:44 -0500 Received: from mail-pf1-f196.google.com ([209.85.210.196]:36633 "EHLO mail-pf1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730990AbfACOcn (ORCPT ); Thu, 3 Jan 2019 09:32:43 -0500 Received: by mail-pf1-f196.google.com with SMTP id b85so16779976pfc.3; Thu, 03 Jan 2019 06:32:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6flrUmMX0zCwN8hqPfXb7LHwkacbKKpcvD5VVnZ+2oc=; b=n8rhowxI/qfOtDToRl693kXZjBQju3kBVNWgsoiyjiCASwDBOkrkhysf2vqpxKZ0rN dHUXNxk3iUihvL+WRPL/cbR7HVTEfn6RZMfOOVLY1YOguwc0EeVPI9MKj2pv9/KQTAAY Kgp8TB+yYGiAWLNBwA5FZdCmr6HgqVQ5kZe5R/t1szDUvmKBFPrnq/RjYuq599cCEGvG 008pND5tyt0N/AAvZHia8gSVjmqPYBoKF6tALEcgYFzCSGez1AEgHkd5ZdrWLFd5XwIG FwobcqAqY7YKSRitdIa2BrSRg8xSfhuQzCmxRVqYyKgODRs1tJ3dTCouPsgJmWVBD4dx R9wA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6flrUmMX0zCwN8hqPfXb7LHwkacbKKpcvD5VVnZ+2oc=; b=S7jnwKd3Ts3aqdcUX6Y/QE77IOMBZKf9NE7yArOAQeZnnlvjVwdsMVs/r2oiCaSMqc mOCB+PSf4aeyZplrMLl/H/Vmrmq6RPEA5Q9mhG9DhqNBjEIsUOc9f4Xb1OULBldIucL1 WQT9dF+HVTNg29ybAg5C5MhfkugRHrjf4dwuGofHrYTyH3iAdp6Co0lDo1MMmc0x2Pa5 KUAwD1RMeb3VebIHeSleKs9Bks7F2CMmSvszeYo8PY46+U+dVOLMb+ri8D+CPtAIKkxH venGccosKP28GfUZ4Wy2f+h6MujAUs+s/UkmuIXeh5LaRoG1TV4KVG4sUwYhAQIK2ooS 4CKw== X-Gm-Message-State: AJcUukeXF4a+IU9MKwI8IzFSv8ndOjEYU9DdA9j8D7PCJPEm0O0D1PFm oVVQTVokHEGLMljfHd1xc9o= X-Google-Smtp-Source: ALg8bN5xIkHsD0+CGb7Gcqu3kCWhcEXkMyD2qaXsD66IkhJ/HCoAkkgc1/L5qQX8qipyTriSLNN30g== X-Received: by 2002:a63:4819:: with SMTP id v25mr17095798pga.308.1546525962149; Thu, 03 Jan 2019 06:32:42 -0800 (PST) Received: from linux-l9pv.suse ([124.11.22.254]) by smtp.gmail.com with ESMTPSA id x3sm184403100pgt.45.2019.01.03.06.32.37 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 03 Jan 2019 06:32:40 -0800 (PST) From: "Lee, Chun-Yi" X-Google-Original-From: "Lee, Chun-Yi" To: "Rafael J . Wysocki" , Pavel Machek Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, keyrings@vger.kernel.org, "Lee, Chun-Yi" , "Rafael J. Wysocki" , Chen Yu , Oliver Neukum , Ryan Chen , David Howells , Giovanni Gherdovich , Randy Dunlap , Jann Horn , Andy Lutomirski Subject: [PATCH 1/5 v2] PM / hibernate: Create snapshot keys handler Date: Thu, 3 Jan 2019 22:32:23 +0800 Message-Id: <20190103143227.9138-2-jlee@suse.com> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20190103143227.9138-1-jlee@suse.com> References: <20190103143227.9138-1-jlee@suse.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds a snapshot keys handler for using the key retention service api to create keys for snapshot image encryption and authentication. This handler uses TPM trusted key as the snapshot master key, and the encryption key and authentication key are derived from the snapshot key. The user defined key can also be used as the snapshot master key , but user must be aware that the security of user key relies on user space. The name of snapshot key is fixed to "swsusp-kmk". User should use the keyctl tool to load the key blob to root's user keyring. e.g. # /bin/keyctl add trusted swsusp-kmk "load `cat swsusp-kmk.blob`" @u or create a new user key. e.g. # /bin/keyctl add user swsusp-kmk password @u Then the disk_kmk sysfs file can be used to trigger the initialization of snapshot key: # echo 1 > /sys/power/disk_kmk After the initialization be triggered, the secret in the payload of swsusp-key will be copied by hibernation and be erased. Then user can use keyctl to remove swsusp-kmk key from root's keyring. If user does not trigger the initialization by disk_kmk file after swsusp-kmk be loaded to kernel. Then the snapshot key will be initialled when hibernation be triggered. v2: - Fixed bug of trusted_key_init's return value. - Fixed wording in Kconfig - Removed VLA usage - Removed the checking of capability for writing disk_kmk. - Fixed Kconfig, select trusted key. - Add memory barrier before setting key initialized flag. Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Chen Yu Cc: Oliver Neukum Cc: Ryan Chen Cc: David Howells Cc: Giovanni Gherdovich Cc: Randy Dunlap Cc: Jann Horn Cc: Andy Lutomirski Signed-off-by: "Lee, Chun-Yi" --- kernel/power/Kconfig | 14 +++ kernel/power/Makefile | 1 + kernel/power/hibernate.c | 33 ++++++ kernel/power/power.h | 16 +++ kernel/power/snapshot_key.c | 245 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 309 insertions(+) create mode 100644 kernel/power/snapshot_key.c diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index f8fe57d1022e..506a3c5a7a0d 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -76,6 +76,20 @@ config HIBERNATION For more information take a look at . +config HIBERNATION_ENC_AUTH + bool "Hibernation encryption and authentication" + depends on HIBERNATION + select TRUSTED_KEYS + select CRYPTO_AES + select CRYPTO_HMAC + select CRYPTO_SHA512 + help + This option will encrypt and authenticate the memory snapshot image + of hibernation. It prevents that the snapshot image be arbitrarily + modified. A user can use the TPM's trusted key or user defined key + as the master key of hibernation. The TPM trusted key depends on TPM. + The security of user defined key relies on user space. + config ARCH_SAVE_PAGE_KEYS bool diff --git a/kernel/power/Makefile b/kernel/power/Makefile index e7e47d9be1e5..d949adbaf580 100644 --- a/kernel/power/Makefile +++ b/kernel/power/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_FREEZER) += process.o obj-$(CONFIG_SUSPEND) += suspend.o obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o +obj-$(CONFIG_HIBERNATION_ENC_AUTH) += snapshot_key.o obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index abef759de7c8..ecc31e8e40d0 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -1034,6 +1034,36 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, power_attr(disk); +#ifdef CONFIG_HIBERNATION_ENC_AUTH +static ssize_t disk_kmk_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + if (snapshot_key_initialized()) + return sprintf(buf, "initialized\n"); + else + return sprintf(buf, "uninitialized\n"); +} + +static ssize_t disk_kmk_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t n) +{ + int error = 0; + char *p; + int len; + + p = memchr(buf, '\n', n); + len = p ? p - buf : n; + if (strncmp(buf, "1", len)) + return -EINVAL; + + error = snapshot_key_init(); + + return error ? error : n; +} + +power_attr(disk_kmk); +#endif /* !CONFIG_HIBERNATION_ENC_AUTH */ + static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -1138,6 +1168,9 @@ power_attr(reserved_size); static struct attribute * g[] = { &disk_attr.attr, +#ifdef CONFIG_HIBERNATION_ENC_AUTH + &disk_kmk_attr.attr, +#endif &resume_offset_attr.attr, &resume_attr.attr, &image_size_attr.attr, diff --git a/kernel/power/power.h b/kernel/power/power.h index 9e58bdc8a562..fe2dfa0d4d36 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -4,6 +4,12 @@ #include #include #include +#include + +/* The max size of encrypted key blob */ +#define KEY_BLOB_BUFF_LEN 512 +#define SNAPSHOT_KEY_SIZE SHA512_DIGEST_SIZE +#define DERIVED_KEY_SIZE SHA512_DIGEST_SIZE struct swsusp_info { struct new_utsname uts; @@ -20,6 +26,16 @@ struct swsusp_info { extern void __init hibernate_reserved_size_init(void); extern void __init hibernate_image_size_init(void); +#ifdef CONFIG_HIBERNATION_ENC_AUTH +/* kernel/power/snapshot_key.c */ +extern int snapshot_key_init(void); +extern bool snapshot_key_initialized(void); +extern int snapshot_get_auth_key(u8 *auth_key, bool may_sleep); +extern int snapshot_get_enc_key(u8 *enc_key, bool may_sleep); +#else +static inline int snapshot_key_init(void) { return 0; } +#endif /* !CONFIG_HIBERNATION_ENC_AUTH */ + #ifdef CONFIG_ARCH_HIBERNATION_HEADER /* Maximum size of architecture specific data in a hibernation header */ #define MAX_ARCH_HEADER_SIZE (sizeof(struct new_utsname) + 4) diff --git a/kernel/power/snapshot_key.c b/kernel/power/snapshot_key.c new file mode 100644 index 000000000000..3a569b505d8d --- /dev/null +++ b/kernel/power/snapshot_key.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* snapshot keys handler + * + * Copyright (C) 2018 Lee, Chun-Yi + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "power.h" + +static const char hash_alg[] = "sha512"; +static struct crypto_shash *hash_tfm; + +/* The master key of snapshot */ +static struct snapshot_key { + const char *key_name; + bool initialized; + unsigned int key_len; + u8 key[SNAPSHOT_KEY_SIZE]; +} skey = { + .key_name = "swsusp-kmk", +}; + +static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen, + bool may_sleep) +{ + struct shash_desc *desc; + int err; + + desc = kzalloc(sizeof(struct shash_desc) + + crypto_shash_descsize(hash_tfm), + may_sleep ? GFP_KERNEL : GFP_ATOMIC); + if (!desc) + return -ENOMEM; + + desc->tfm = hash_tfm; + desc->flags = may_sleep ? CRYPTO_TFM_REQ_MAY_SLEEP : 0; + err = crypto_shash_digest(desc, buf, buflen, digest); + shash_desc_zero(desc); + kzfree(desc); + + return err; +} + +static int calc_key_hash(u8 *key, unsigned int key_len, const char *salt, + u8 *hash, bool may_sleep) +{ + unsigned int salted_buf_len; + u8 *salted_buf; + int ret; + + if (!key || !hash_tfm || !hash) + return -EINVAL; + + salted_buf_len = strlen(salt) + 1 + SNAPSHOT_KEY_SIZE; + salted_buf = kzalloc(salted_buf_len, + may_sleep ? GFP_KERNEL : GFP_ATOMIC); + if (!salted_buf) + return -ENOMEM; + + strcpy(salted_buf, salt); + memcpy(salted_buf + strlen(salted_buf) + 1, key, key_len); + + ret = calc_hash(hash, salted_buf, salted_buf_len, may_sleep); + memzero_explicit(salted_buf, salted_buf_len); + kzfree(salted_buf); + + return ret; +} + +/* Derive authentication/encryption key */ +static int get_derived_key(u8 *derived_key, const char *derived_type_str, + bool may_sleep) +{ + int ret; + + if (!skey.initialized || !hash_tfm) + return -EINVAL; + + ret = calc_key_hash(skey.key, skey.key_len, derived_type_str, + derived_key, may_sleep); + + return ret; +} + +int snapshot_get_auth_key(u8 *auth_key, bool may_sleep) +{ + return get_derived_key(auth_key, "AUTH_KEY", may_sleep); +} + +int snapshot_get_enc_key(u8 *enc_key, bool may_sleep) +{ + return get_derived_key(enc_key, "ENC_KEY", may_sleep); +} + +bool snapshot_key_initialized(void) +{ + return skey.initialized; +} + +static bool invalid_key(u8 *key, unsigned int key_len) +{ + int i; + + if (!key || !key_len) + return true; + + if (key_len > SNAPSHOT_KEY_SIZE) { + pr_warn("Size of swsusp key more than: %d.\n", + SNAPSHOT_KEY_SIZE); + return true; + } + + /* zero keyblob is invalid key */ + for (i = 0; i < key_len; i++) { + if (key[i] != 0) + return false; + } + pr_warn("The swsusp key should not be zero.\n"); + + return true; +} + +static int trusted_key_init(void) +{ + struct trusted_key_payload *tkp; + struct key *key; + int err = 0; + + pr_debug("%s\n", __func__); + + /* find out swsusp-key */ + key = request_key(&key_type_trusted, skey.key_name, NULL); + if (IS_ERR(key)) { + pr_err("Request key error: %ld\n", PTR_ERR(key)); + err = PTR_ERR(key); + return err; + } + + down_write(&key->sem); + tkp = key->payload.data[0]; + if (invalid_key(tkp->key, tkp->key_len)) { + err = -EINVAL; + goto key_invalid; + } + skey.key_len = tkp->key_len; + memcpy(skey.key, tkp->key, tkp->key_len); + /* burn the original key contents */ + memzero_explicit(tkp->key, tkp->key_len); + +key_invalid: + up_write(&key->sem); + key_put(key); + + return err; +} + +static int user_key_init(void) +{ + struct user_key_payload *ukp; + struct key *key; + int err = 0; + + pr_debug("%s\n", __func__); + + /* find out swsusp-key */ + key = request_key(&key_type_user, skey.key_name, NULL); + if (IS_ERR(key)) { + pr_err("Request key error: %ld\n", PTR_ERR(key)); + err = PTR_ERR(key); + return err; + } + + down_write(&key->sem); + ukp = user_key_payload_locked(key); + if (!ukp) { + /* key was revoked before we acquired its semaphore */ + err = -EKEYREVOKED; + goto key_invalid; + } + if (invalid_key(ukp->data, ukp->datalen)) { + err = -EINVAL; + goto key_invalid; + } + skey.key_len = ukp->datalen; + memcpy(skey.key, ukp->data, ukp->datalen); + /* burn the original key contents */ + memzero_explicit(ukp->data, ukp->datalen); + +key_invalid: + up_write(&key->sem); + key_put(key); + + return err; +} + +/* this function may sleeps */ +int snapshot_key_init(void) +{ + int err; + + pr_debug("%s\n", __func__); + + if (skey.initialized) + return 0; + + hash_tfm = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(hash_tfm)) { + pr_err("Can't allocate %s transform: %ld\n", + hash_alg, PTR_ERR(hash_tfm)); + return PTR_ERR(hash_tfm); + } + + err = trusted_key_init(); + if (err) + err = user_key_init(); + if (err) + goto key_fail; + + barrier(); + skey.initialized = true; + + pr_info("Snapshot key is initialled.\n"); + + return 0; + +key_fail: + crypto_free_shash(hash_tfm); + hash_tfm = NULL; + + return err; +} From patchwork Thu Jan 3 14:32:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chun-Yi Lee X-Patchwork-Id: 10747447 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6774A14DE for ; Thu, 3 Jan 2019 14:32:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 55C57212E8 for ; Thu, 3 Jan 2019 14:32:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 48617285DB; Thu, 3 Jan 2019 14:32:55 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,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 E339D212E8 for ; Thu, 3 Jan 2019 14:32:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731954AbfACOcx (ORCPT ); Thu, 3 Jan 2019 09:32:53 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:46548 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731053AbfACOcv (ORCPT ); Thu, 3 Jan 2019 09:32:51 -0500 Received: by mail-pg1-f194.google.com with SMTP id w7so16067355pgp.13; Thu, 03 Jan 2019 06:32:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=DPJumJ/ohwlthM0jS0UnPH6ZGUkW7vBJmnCc4y48ckw=; b=mkip1umkG9dZrIPl+GdCUoYYoeKzf7AE1ZORUc3EQRjPgnGXVpdM0l/N13+D2Q8Czc 29kSYL3CLtCllzwSIH85lwgsnXDMOQT1M8TcD+x6JsL7cUNv/yikAnCmHvQUDcw5L88r HlLwsRd9ai248MOdq1uVkvZf9HNoj0BQJY5RmBAuVN0U370uWm6fSS2YQUdqS/n+JzrL hQRwZhtGQgncU2VKVbDvRcRcWBlk2CvnaqPG2/gMcMqHaBHBE3X1d+jU4QvdVZ8/ZwzU CqWH9IDKlL78zF4XEnmfKlT6j3G0prKM0cm7VWAlegjxt1aPf6GZXDXWWRbfFqEGNInI 1FHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=DPJumJ/ohwlthM0jS0UnPH6ZGUkW7vBJmnCc4y48ckw=; b=YWHXdUybQ44jx0fCR89h3+SpCl0nWXgD/zpwTYoliXhGWxuSuNc393ZdNtmXQ2wWQz +rDMFkO9XLNvBJm9BpFF5VxwXyc+cBm9ISPq/M3WTkZpfjfiN/eEcsJTpNShnkrEcpc2 32wqH86Uul1i6P2Cszrd1MCeiL0oX5sfPZBsEOGMRozk04BydaoK3pVHiob7CMALzGiP n4u01uIe/WPm5dNUWE335v5q9qYzK6G+SYm1LvSUpb/WwX+eh2BsXNZOZItCpaS2N/oF +q/HrEckZbZYKjiZAn5M98Mqo0AgIoNkPTqYClolmR2i8tqV+eFy3XNYRp06AUgsZ8/f W3Nw== X-Gm-Message-State: AJcUukfj6TvVlUQUPYm5MUe8ZglGHwpvvAuTV0VIVeYmD4Ot603V5WZh y7rogYHXqqSuXXgBH3NG2Tg= X-Google-Smtp-Source: ALg8bN7DMu3txA46sQrVoCo77Y3E/12yPYWg3fG1H4acZLPeBhKB4M9sR0Fyzvenx4EEc6CpFM7DPA== X-Received: by 2002:a63:5c41:: with SMTP id n1mr16515176pgm.1.1546525969653; Thu, 03 Jan 2019 06:32:49 -0800 (PST) Received: from linux-l9pv.suse ([124.11.22.254]) by smtp.gmail.com with ESMTPSA id x3sm184403100pgt.45.2019.01.03.06.32.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 03 Jan 2019 06:32:48 -0800 (PST) From: "Lee, Chun-Yi" X-Google-Original-From: "Lee, Chun-Yi" To: "Rafael J . Wysocki" , Pavel Machek Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, keyrings@vger.kernel.org, "Lee, Chun-Yi" , "Rafael J. Wysocki" , Chen Yu , Oliver Neukum , Ryan Chen , David Howells , Giovanni Gherdovich , Randy Dunlap , Jann Horn , Andy Lutomirski Subject: [PATCH 2/5] PM / hibernate: Generate and verify signature for snapshot image Date: Thu, 3 Jan 2019 22:32:24 +0800 Message-Id: <20190103143227.9138-3-jlee@suse.com> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20190103143227.9138-1-jlee@suse.com> References: <20190103143227.9138-1-jlee@suse.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When producing memory snapshot image, hibernation uses HMAC-SHA512 with snapshot key (from TPM trusted key) to calculate the hash of all data pages in snapshot image. The hash result will be kept in the snapshot header as the image signature. Before hibernation restores image, kernel executes HMAC-SHA512 again and compares the result with the signature in the header to verify the integrity of snapshot image. If the verification failed, the resume process will be stopped. Then the snapshot image will be discarded and system will boot as normal. On the other hand, a trampoline page be created in snapshot image when hibernation. This trampoline page be used to forward the state of snapshot key and the result of snapshot image verification from boot kernel to image kernel when resuming. The trampoline page will also be used to forward the snapshot key in the later patch. Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Chen Yu Cc: Oliver Neukum Cc: Ryan Chen Cc: David Howells Cc: Giovanni Gherdovich Cc: Randy Dunlap Cc: Jann Horn Cc: Andy Lutomirski Signed-off-by: "Lee, Chun-Yi" --- kernel/power/hibernate.c | 18 ++- kernel/power/power.h | 26 ++++ kernel/power/snapshot.c | 387 +++++++++++++++++++++++++++++++++++++++++++++-- kernel/power/swap.c | 6 + kernel/power/user.c | 12 ++ 5 files changed, 432 insertions(+), 17 deletions(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index ecc31e8e40d0..0dda6a9f0af1 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -271,10 +271,14 @@ static int create_image(int platform_mode) { int error; + error = snapshot_prepare_hash(false); + if (error) + return error; + error = dpm_suspend_end(PMSG_FREEZE); if (error) { pr_err("Some devices failed to power down, aborting hibernation\n"); - return error; + goto finish_hash; } error = platform_pre_snapshot(platform_mode); @@ -331,6 +335,9 @@ static int create_image(int platform_mode) dpm_resume_start(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); + finish_hash: + snapshot_finish_hash(); + return error; } @@ -694,6 +701,14 @@ int hibernate(void) return -EPERM; } + error = snapshot_key_init(); + if (error) + return error; + + error = snapshot_create_trampoline(); + if (error) + return error; + lock_system_sleep(); /* The snapshot device should not be opened while we're running */ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) { @@ -750,6 +765,7 @@ int hibernate(void) pm_restore_gfp_mask(); } else { pm_pr_dbg("Image restored successfully.\n"); + snapshot_restore_trampoline(); } Free_bitmaps: diff --git a/kernel/power/power.h b/kernel/power/power.h index fe2dfa0d4d36..c614b0a294e3 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -11,6 +11,10 @@ #define SNAPSHOT_KEY_SIZE SHA512_DIGEST_SIZE #define DERIVED_KEY_SIZE SHA512_DIGEST_SIZE +/* HMAC algorithm for hibernate snapshot signature */ +#define SNAPSHOT_HMAC "hmac(sha512)" +#define SNAPSHOT_DIGEST_SIZE SHA512_DIGEST_SIZE + struct swsusp_info { struct new_utsname uts; u32 version_code; @@ -19,6 +23,17 @@ struct swsusp_info { unsigned long image_pages; unsigned long pages; unsigned long size; + unsigned long trampoline_pfn; + u8 signature[SNAPSHOT_DIGEST_SIZE]; +} __aligned(PAGE_SIZE); + +/* + * The trampoline page is used to forward information + * from boot kernel to image kernel in restore stage. + */ +struct trampoline { + bool snapshot_key_valid; + int sig_verify_ret; } __aligned(PAGE_SIZE); #ifdef CONFIG_HIBERNATION @@ -27,12 +42,19 @@ extern void __init hibernate_reserved_size_init(void); extern void __init hibernate_image_size_init(void); #ifdef CONFIG_HIBERNATION_ENC_AUTH +/* kernel/power/snapshot.c */ +extern int snapshot_image_verify_decrypt(void); +extern int snapshot_prepare_hash(bool may_sleep); +extern void snapshot_finish_hash(void); /* kernel/power/snapshot_key.c */ extern int snapshot_key_init(void); extern bool snapshot_key_initialized(void); extern int snapshot_get_auth_key(u8 *auth_key, bool may_sleep); extern int snapshot_get_enc_key(u8 *enc_key, bool may_sleep); #else +static inline int snapshot_image_verify_decrypt(void) { return 0; } +static inline int snapshot_prepare_hash(bool may_sleep) { return 0; } +static inline void snapshot_finish_hash(void) {} static inline int snapshot_key_init(void) { return 0; } #endif /* !CONFIG_HIBERNATION_ENC_AUTH */ @@ -171,6 +193,10 @@ extern int snapshot_read_next(struct snapshot_handle *handle); extern int snapshot_write_next(struct snapshot_handle *handle); extern void snapshot_write_finalize(struct snapshot_handle *handle); extern int snapshot_image_loaded(struct snapshot_handle *handle); +extern int snapshot_create_trampoline(void); +extern void snapshot_init_trampoline(void); +extern void snapshot_restore_trampoline(void); +extern void snapshot_free_trampoline(void); /* If unset, the snapshot device cannot be open. */ extern atomic_t snapshot_device_available; diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 640b2034edd6..e817c035f378 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -33,12 +33,16 @@ #include #include #include +#include #include #include #include #include #include +#ifdef CONFIG_HIBERNATION_ENC_AUTH +#include +#endif #include "power.h" @@ -79,6 +83,15 @@ static inline void hibernate_restore_protect_page(void *page_address) {} static inline void hibernate_restore_unprotect_page(void *page_address) {} #endif /* CONFIG_STRICT_KERNEL_RWX && CONFIG_ARCH_HAS_SET_MEMORY */ +/* the trampoline is used by image kernel */ +static void *trampoline_virt; + +/* trampoline pfn from swsusp_info in snapshot for snapshot_write_next() */ +static unsigned long trampoline_pfn; + +/* Keep the buffer for foward page in snapshot_write_next() */ +static void *trampoline_buff; + static int swsusp_page_is_free(struct page *); static void swsusp_set_page_forbidden(struct page *); static void swsusp_unset_page_forbidden(struct page *); @@ -1393,8 +1406,246 @@ static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) } #endif /* CONFIG_HIGHMEM */ -static void copy_data_pages(struct memory_bitmap *copy_bm, - struct memory_bitmap *orig_bm) +/* Total number of image pages */ +static unsigned int nr_copy_pages; + +/* Point array for collecting buffers' address in snapshot_write_next() */ +static void **h_buf; + +#ifdef CONFIG_HIBERNATION_ENC_AUTH +/* + * Signature of snapshot image + */ +static u8 signature[SNAPSHOT_DIGEST_SIZE]; + +/* Keep the signature verification result for trampoline */ +static int sig_verify_ret; + +/* keep the snapshot key status for trampoline */ +static bool snapshot_key_valid; + +static u8 *s4_verify_digest; +static struct shash_desc *s4_verify_desc; + +int snapshot_prepare_hash(bool may_sleep) +{ + char auth_key[DERIVED_KEY_SIZE]; + struct crypto_shash *tfm; + size_t digest_size, desc_size; + int ret; + + ret = snapshot_get_auth_key(auth_key, may_sleep); + if (ret) { + pr_warn_once("auth key is invalid: %d\n", ret); + return -EINVAL; + } + snapshot_key_valid = true; + + tfm = crypto_alloc_shash(SNAPSHOT_HMAC, 0, 0); + if (IS_ERR(tfm)) { + pr_err("Allocate HMAC failed: %ld\n", PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + + ret = crypto_shash_setkey(tfm, auth_key, DERIVED_KEY_SIZE); + if (ret) { + pr_err("Set HMAC key failed\n"); + goto error; + } + + desc_size = crypto_shash_descsize(tfm) + sizeof(*s4_verify_desc); + digest_size = crypto_shash_digestsize(tfm); + s4_verify_digest = kzalloc(digest_size + desc_size, + may_sleep ? GFP_KERNEL : GFP_ATOMIC); + if (!s4_verify_digest) { + pr_err("Allocate digest failed\n"); + ret = -ENOMEM; + goto error; + } + + s4_verify_desc = (void *) s4_verify_digest + digest_size; + s4_verify_desc->tfm = tfm; + if (may_sleep) + s4_verify_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; + ret = crypto_shash_init(s4_verify_desc); + if (ret < 0) + goto free_shash; + + return 0; + + free_shash: + kfree(s4_verify_digest); + error: + crypto_free_shash(tfm); + s4_verify_digest = NULL; + s4_verify_desc = NULL; + return ret; +} + +void snapshot_finish_hash(void) +{ + if (s4_verify_desc) + crypto_free_shash(s4_verify_desc->tfm); + kfree(s4_verify_digest); + s4_verify_desc = NULL; + s4_verify_digest = NULL; +} + +int snapshot_image_verify_decrypt(void) +{ + int ret, i; + + if (!h_buf) { + ret = -ENOMEM; + goto error; + } + + ret = snapshot_key_init(); + if (ret) + goto error_prep; + + ret = snapshot_prepare_hash(true); + if (ret || !s4_verify_desc) + goto error_prep; + + for (i = 0; i < nr_copy_pages; i++) { + ret = crypto_shash_update(s4_verify_desc, *(h_buf + i), PAGE_SIZE); + if (ret) + goto error_shash; + } + + ret = crypto_shash_final(s4_verify_desc, s4_verify_digest); + if (ret) + goto error_shash; + + pr_debug("Signature %*phN\n", SNAPSHOT_DIGEST_SIZE, signature); + pr_debug("Digest %*phN\n", SNAPSHOT_DIGEST_SIZE, s4_verify_digest); + if (memcmp(signature, s4_verify_digest, SNAPSHOT_DIGEST_SIZE)) + ret = -EKEYREJECTED; + + error_shash: + snapshot_finish_hash(); + + error_prep: + vfree(h_buf); + if (ret) + pr_warn("Signature verification failed: %d\n", ret); + error: + sig_verify_ret = ret; + return ret; +} + +static int +__copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) +{ + unsigned long pfn, dst_pfn; + struct page *d_page; + void *crypto_buffer = NULL; + int ret = 0; + + memory_bm_position_reset(orig_bm); + memory_bm_position_reset(copy_bm); + for (;;) { + pfn = memory_bm_next_pfn(orig_bm); + if (unlikely(pfn == BM_END_OF_MAP)) + break; + dst_pfn = memory_bm_next_pfn(copy_bm); + copy_data_page(dst_pfn, pfn); + + /* Setup buffer */ + d_page = pfn_to_page(dst_pfn); + if (PageHighMem(d_page)) { + void *kaddr = kmap_atomic(d_page); + + copy_page(buffer, kaddr); + kunmap_atomic(kaddr); + crypto_buffer = buffer; + } else { + crypto_buffer = page_address(d_page); + } + + /* Generate digest */ + if (!s4_verify_desc) + continue; + ret = crypto_shash_update(s4_verify_desc, crypto_buffer, + PAGE_SIZE); + if (ret) + return ret; + } + + if (s4_verify_desc) { + ret = crypto_shash_final(s4_verify_desc, s4_verify_digest); + if (ret) + return ret; + + memset(signature, 0, SNAPSHOT_DIGEST_SIZE); + memcpy(signature, s4_verify_digest, SNAPSHOT_DIGEST_SIZE); + } + + return 0; +} + +static void alloc_h_buf(void) +{ + h_buf = vmalloc(sizeof(void *) * nr_copy_pages); + if (!h_buf) + pr_err("Allocate buffer point array failed\n"); +} + +static void init_signature(struct swsusp_info *info) +{ + memcpy(info->signature, signature, SNAPSHOT_DIGEST_SIZE); +} + +static void load_signature(struct swsusp_info *info) +{ + memset(signature, 0, SNAPSHOT_DIGEST_SIZE); + memcpy(signature, info->signature, SNAPSHOT_DIGEST_SIZE); +} + +static void init_sig_verify(struct trampoline *t) +{ + t->sig_verify_ret = sig_verify_ret; + t->snapshot_key_valid = snapshot_key_valid; + sig_verify_ret = 0; + snapshot_key_valid = 0; +} + +static void handle_sig_verify(struct trampoline *t) +{ + if (t->sig_verify_ret) + pr_warn("Signature verification failed: %d\n", + t->sig_verify_ret); + else if (t->snapshot_key_valid) + pr_info("Signature verification passed.\n"); +} +#else +static int +__copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) +{ + unsigned long pfn; + + memory_bm_position_reset(orig_bm); + memory_bm_position_reset(copy_bm); + for (;;) { + pfn = memory_bm_next_pfn(orig_bm); + if (unlikely(pfn == BM_END_OF_MAP)) + break; + copy_data_page(memory_bm_next_pfn(copy_bm), pfn); + } + + return 0; +} + +static inline void alloc_h_buf(void) {} +static inline void init_signature(struct swsusp_info *info) {} +static inline void load_signature(struct swsusp_info *info) {} +static inline void init_sig_verify(struct trampoline *t) {} +static inline void handle_sig_verify(struct trampoline *t) {} +#endif /* !CONFIG_HIBERNATION_ENC_AUTH */ + +static int copy_data_pages(struct memory_bitmap *copy_bm, + struct memory_bitmap *orig_bm) { struct zone *zone; unsigned long pfn; @@ -1408,18 +1659,9 @@ static void copy_data_pages(struct memory_bitmap *copy_bm, if (page_is_saveable(zone, pfn)) memory_bm_set_bit(orig_bm, pfn); } - memory_bm_position_reset(orig_bm); - memory_bm_position_reset(copy_bm); - for(;;) { - pfn = memory_bm_next_pfn(orig_bm); - if (unlikely(pfn == BM_END_OF_MAP)) - break; - copy_data_page(memory_bm_next_pfn(copy_bm), pfn); - } + return __copy_data_pages(copy_bm, orig_bm); } -/* Total number of image pages */ -static unsigned int nr_copy_pages; /* Number of pages needed for saving the original pfns of the image pages */ static unsigned int nr_meta_pages; /* @@ -1961,6 +2203,7 @@ static int swsusp_alloc(struct memory_bitmap *copy_bm, asmlinkage __visible int swsusp_save(void) { unsigned int nr_pages, nr_highmem; + int ret; pr_info("Creating hibernation image:\n"); @@ -1984,7 +2227,11 @@ asmlinkage __visible int swsusp_save(void) * Kill them. */ drain_local_pages(NULL); - copy_data_pages(©_bm, &orig_bm); + ret = copy_data_pages(©_bm, &orig_bm); + if (ret) { + pr_err("Copy data pages failed\n"); + return ret; + } /* * End of critical section. From now on, we can write to memory, @@ -2038,10 +2285,98 @@ static int init_header(struct swsusp_info *info) info->pages = snapshot_get_image_size(); info->size = info->pages; info->size <<= PAGE_SHIFT; + info->trampoline_pfn = page_to_pfn(virt_to_page(trampoline_virt)); + init_signature(info); return init_header_complete(info); } /** + * create trampoline - Create a trampoline page before snapshot be created + * In hibernation process, this routine will be called by kernel before + * the snapshot image be created. It can be used in resuming process. + */ +int snapshot_create_trampoline(void) +{ + if (trampoline_virt) { + pr_warn("Tried to create trampoline again\n"); + return 0; + } + + trampoline_virt = (void *)get_zeroed_page(GFP_KERNEL); + if (!trampoline_virt) { + pr_err("Allocate trampoline page failed\n"); + return -ENOMEM; + } + trampoline_pfn = 0; + trampoline_buff = NULL; + + return 0; +} + +/** + * initial trampoline - Put data to trampoline buffer for target kernel + * + * In resuming process, this routine will be called by boot kernel before + * the target kernel be restored. The boot kernel uses trampoline buffer + * to transfer information to target kernel. + */ +void snapshot_init_trampoline(void) +{ + struct trampoline *t; + + if (!trampoline_pfn || !trampoline_buff) { + pr_err("Did not find trampoline buffer, pfn: %ld\n", + trampoline_pfn); + return; + } + + hibernate_restore_unprotect_page(trampoline_buff); + memset(trampoline_buff, 0, PAGE_SIZE); + t = (struct trampoline *)trampoline_buff; + + init_sig_verify(t); + + pr_info("Hibernation trampoline page prepared\n"); +} + +/** + * restore trampoline - Handle the data from boot kernel and free. + * + * In resuming process, this routine will be called by target kernel + * after target kernel is restored. The target kernel handles + * the data in trampoline that it is transferred from boot kernel. + */ +void snapshot_restore_trampoline(void) +{ + struct trampoline *t; + + if (!trampoline_virt) { + pr_err("Doesn't have trampoline page\n"); + return; + } + + t = (struct trampoline *)trampoline_virt; + + handle_sig_verify(t); + snapshot_free_trampoline(); +} + +void snapshot_free_trampoline(void) +{ + if (!trampoline_virt) { + pr_err("No trampoline page can be freed\n"); + return; + } + + trampoline_pfn = 0; + trampoline_buff = NULL; + memset(trampoline_virt, 0, PAGE_SIZE); + free_page((unsigned long)trampoline_virt); + trampoline_virt = NULL; + pr_info("Trampoline freed\n"); +} + +/** * pack_pfns - Prepare PFNs for saving. * @bm: Memory bitmap. * @buf: Memory buffer to store the PFNs in. @@ -2188,6 +2523,8 @@ static int load_header(struct swsusp_info *info) if (!error) { nr_copy_pages = info->image_pages; nr_meta_pages = info->pages - info->image_pages - 1; + trampoline_pfn = info->trampoline_pfn; + load_signature(info); } return error; } @@ -2521,7 +2858,8 @@ static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) * Get the address that snapshot_write_next() should return to its caller to * write to. */ -static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) +static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca, + unsigned long *pfn_out) { struct pbe *pbe; struct page *page; @@ -2530,6 +2868,9 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) if (pfn == BM_END_OF_MAP) return ERR_PTR(-EFAULT); + if (pfn_out) + *pfn_out = pfn; + page = pfn_to_page(pfn); if (PageHighMem(page)) return get_highmem_page_buffer(page, ca); @@ -2577,6 +2918,7 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) int snapshot_write_next(struct snapshot_handle *handle) { static struct chain_allocator ca; + unsigned long pfn; int error = 0; /* Check if we have already loaded the entire image */ @@ -2601,6 +2943,12 @@ int snapshot_write_next(struct snapshot_handle *handle) safe_pages_list = NULL; + /* Allocate buffer point array for generating + * digest to compare with signature. + * h_buf will freed in snapshot_image_verify_decrypt(). + */ + alloc_h_buf(); + error = memory_bm_create(©_bm, GFP_ATOMIC, PG_ANY); if (error) return error; @@ -2624,21 +2972,28 @@ int snapshot_write_next(struct snapshot_handle *handle) chain_init(&ca, GFP_ATOMIC, PG_SAFE); memory_bm_position_reset(&orig_bm); restore_pblist = NULL; - handle->buffer = get_buffer(&orig_bm, &ca); + handle->buffer = get_buffer(&orig_bm, &ca, &pfn); handle->sync_read = 0; if (IS_ERR(handle->buffer)) return PTR_ERR(handle->buffer); + if (h_buf) + *h_buf = handle->buffer; } } else { copy_last_highmem_page(); /* Restore page key for data page (s390 only). */ page_key_write(handle->buffer); hibernate_restore_protect_page(handle->buffer); - handle->buffer = get_buffer(&orig_bm, &ca); + handle->buffer = get_buffer(&orig_bm, &ca, &pfn); if (IS_ERR(handle->buffer)) return PTR_ERR(handle->buffer); if (handle->buffer != buffer) handle->sync_read = 0; + /* Capture the trampoline for transfer data */ + if (pfn == trampoline_pfn && trampoline_pfn) + trampoline_buff = handle->buffer; + if (h_buf) + *(h_buf + (handle->cur - nr_meta_pages - 1)) = handle->buffer; } handle->cur++; return PAGE_SIZE; diff --git a/kernel/power/swap.c b/kernel/power/swap.c index d7f6c1a288d3..2e669f589830 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -1095,6 +1095,9 @@ static int load_image(struct swap_map_handle *handle, snapshot_write_finalize(snapshot); if (!snapshot_image_loaded(snapshot)) ret = -ENODATA; + if (!ret) + ret = snapshot_image_verify_decrypt(); + snapshot_init_trampoline(); } swsusp_show_speed(start, stop, nr_to_read, "Read"); return ret; @@ -1447,6 +1450,9 @@ static int load_image_lzo(struct swap_map_handle *handle, } } } + if (!ret) + ret = snapshot_image_verify_decrypt(); + snapshot_init_trampoline(); } swsusp_show_speed(start, stop, nr_to_read, "Read"); out_clean: diff --git a/kernel/power/user.c b/kernel/power/user.c index 2d8b60a3c86b..d5c8f777e8d8 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -248,6 +248,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, if (!data->frozen || data->ready) break; pm_restore_gfp_mask(); + snapshot_restore_trampoline(); free_basic_memory_bitmaps(); data->free_bitmaps = false; thaw_processes(); @@ -259,6 +260,12 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, error = -EPERM; break; } + error = snapshot_key_init(); + if (error) + return error; + error = snapshot_create_trampoline(); + if (error) + return error; pm_restore_gfp_mask(); error = hibernation_snapshot(data->platform_support); if (!error) { @@ -275,6 +282,11 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, error = -EPERM; break; } + if (snapshot_image_verify_decrypt()) { + error = -EPERM; + break; + } + snapshot_init_trampoline(); error = hibernation_restore(data->platform_support); break; From patchwork Thu Jan 3 14:32:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chun-Yi Lee X-Patchwork-Id: 10747453 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F200991E for ; Thu, 3 Jan 2019 14:33:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E25B7212E8 for ; Thu, 3 Jan 2019 14:33:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D61D8285DB; Thu, 3 Jan 2019 14:33: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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,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 05787212E8 for ; Thu, 3 Jan 2019 14:33:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729649AbfACOdZ (ORCPT ); Thu, 3 Jan 2019 09:33:25 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:35735 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727436AbfACOdZ (ORCPT ); Thu, 3 Jan 2019 09:33:25 -0500 Received: by mail-pg1-f194.google.com with SMTP id s198so16087661pgs.2; Thu, 03 Jan 2019 06:33:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=akAh1HQffuLJ3sc/ovPWRTcFl4jaDX0Beb5XW/vb6Kw=; b=POoRBGjdD/evWXS3xe43k96zmlu/46ZiCrHiUlfF6DptnJYa9G0M23PiblbZ8WszIk dAVK4fGu0/EsE9mjC7vEbQ7s7VZn64HbvXOTtCJXJrcVQXaYPw/QZ6PEzsPZJuE2Zf11 DNypDNyPpUiFXgyYqsEbYsUbKrXlp42rbEVt2Q2MzUU0PSa2qyPVlVV6XpWz0nu0NsPU uF71pWN7olxpuqEC3itz4ChmtaxsQj78LbrzBfoPBJ0WAFgVPvDe41jLZZStEEvr07Ws JF4HhUogZsad98fO57CEG51QrrAIGNGccBt066hHTm8wdkghZPll8YmOMKdZUVpY6vVn 61lg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=akAh1HQffuLJ3sc/ovPWRTcFl4jaDX0Beb5XW/vb6Kw=; b=XikgV9q6ly8qzYUSaDs7XH7IRd5aLdsdNbQATn1jpUdpynqESqnZnl/pV7UKvLl2/W nzaNOtIaNxlkrSWBEyaMllQUJXN55oGeb5Gj0IKDNLE/yow3MFcmi2X1WlLU4wHqREzH q71k5Yih9/34hAw4bg28yrWAJPobbYN7HRvohYb4Xm3olaq+BnQtjs2FFikFDol34EPn La+mhGkV9M8VDiAie4oXZRbS2x6TYIjGeZCjhDKA1v+IGC+eK9Tci0/7l4Ymj/nPmuWz NgyR0AAFOfT8V9HaQXmVL4YzLM+ZmRhGiWYRdaB314Ws4EH1iFNYsunusnZ/lX2F4UWp UjBw== X-Gm-Message-State: AJcUukfNaKCcHWabX6OGymkecS9YhMVCh07YKfZ/6OKFkfj/YzTsG6LJ KaynlZViu3LEarUhmUnBTVM= X-Google-Smtp-Source: ALg8bN48PozTjMsgdPqPr7ml5mwCn9CPqJ8TC64v2EMd5P1SYcEzsXHevbsl6UqfCKS0RuB3Y/Qk1A== X-Received: by 2002:a63:f047:: with SMTP id s7mr17196057pgj.441.1546526004274; Thu, 03 Jan 2019 06:33:24 -0800 (PST) Received: from linux-l9pv.suse ([124.11.22.254]) by smtp.gmail.com with ESMTPSA id x3sm184403100pgt.45.2019.01.03.06.33.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 03 Jan 2019 06:33:23 -0800 (PST) From: "Lee, Chun-Yi" X-Google-Original-From: "Lee, Chun-Yi" To: "Rafael J . Wysocki" , Pavel Machek Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, keyrings@vger.kernel.org, "Lee, Chun-Yi" , "Rafael J. Wysocki" , Chen Yu , Oliver Neukum , Ryan Chen , David Howells , Giovanni Gherdovich , Randy Dunlap , Jann Horn , Andy Lutomirski Subject: [PATCH 3/5] PM / hibernate: Encrypt snapshot image Date: Thu, 3 Jan 2019 22:32:25 +0800 Message-Id: <20190103143227.9138-4-jlee@suse.com> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20190103143227.9138-1-jlee@suse.com> References: <20190103143227.9138-1-jlee@suse.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP To protect the secret in memory snapshot image, this patch adds the logic to encrypt snapshot pages by AES-CTR. Using AES-CTR is because it's simple, fast and parallelizable. But this patch didn't implement parallel encryption. The encrypt key is derived from the snapshot key. And the initialization vector will be kept in snapshot header for resuming. Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Chen Yu Cc: Oliver Neukum Cc: Ryan Chen Cc: David Howells Cc: Giovanni Gherdovich Cc: Randy Dunlap Cc: Jann Horn Cc: Andy Lutomirski Signed-off-by: "Lee, Chun-Yi" --- kernel/power/hibernate.c | 8 ++- kernel/power/power.h | 6 ++ kernel/power/snapshot.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 164 insertions(+), 4 deletions(-) diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 0dda6a9f0af1..5ac2ab6f4a0e 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -275,10 +275,14 @@ static int create_image(int platform_mode) if (error) return error; + error = snapshot_prepare_crypto(false, true); + if (error) + goto finish_hash; + error = dpm_suspend_end(PMSG_FREEZE); if (error) { pr_err("Some devices failed to power down, aborting hibernation\n"); - goto finish_hash; + goto finish_crypto; } error = platform_pre_snapshot(platform_mode); @@ -335,6 +339,8 @@ static int create_image(int platform_mode) dpm_resume_start(in_suspend ? (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); + finish_crypto: + snapshot_finish_crypto(); finish_hash: snapshot_finish_hash(); diff --git a/kernel/power/power.h b/kernel/power/power.h index c614b0a294e3..41263fdd3a54 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -5,6 +5,7 @@ #include #include #include +#include /* The max size of encrypted key blob */ #define KEY_BLOB_BUFF_LEN 512 @@ -24,6 +25,7 @@ struct swsusp_info { unsigned long pages; unsigned long size; unsigned long trampoline_pfn; + u8 iv[AES_BLOCK_SIZE]; u8 signature[SNAPSHOT_DIGEST_SIZE]; } __aligned(PAGE_SIZE); @@ -44,6 +46,8 @@ extern void __init hibernate_image_size_init(void); #ifdef CONFIG_HIBERNATION_ENC_AUTH /* kernel/power/snapshot.c */ extern int snapshot_image_verify_decrypt(void); +extern int snapshot_prepare_crypto(bool may_sleep, bool create_iv); +extern void snapshot_finish_crypto(void); extern int snapshot_prepare_hash(bool may_sleep); extern void snapshot_finish_hash(void); /* kernel/power/snapshot_key.c */ @@ -53,6 +57,8 @@ extern int snapshot_get_auth_key(u8 *auth_key, bool may_sleep); extern int snapshot_get_enc_key(u8 *enc_key, bool may_sleep); #else static inline int snapshot_image_verify_decrypt(void) { return 0; } +static inline int snapshot_prepare_crypto(bool may_sleep, bool create_iv) { return 0; } +static inline void snapshot_finish_crypto(void) {} static inline int snapshot_prepare_hash(bool may_sleep) { return 0; } static inline void snapshot_finish_hash(void) {} static inline int snapshot_key_init(void) { return 0; } diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index e817c035f378..cd10ab5e4850 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -41,7 +41,11 @@ #include #include #ifdef CONFIG_HIBERNATION_ENC_AUTH +#include +#include +#include #include +#include #endif #include "power.h" @@ -1413,6 +1417,127 @@ static unsigned int nr_copy_pages; static void **h_buf; #ifdef CONFIG_HIBERNATION_ENC_AUTH +static struct skcipher_request *sk_req; +static u8 iv[AES_BLOCK_SIZE]; +static void *c_buffer; + +static void init_iv(struct swsusp_info *info) +{ + memcpy(info->iv, iv, AES_BLOCK_SIZE); +} + +static void load_iv(struct swsusp_info *info) +{ + memcpy(iv, info->iv, AES_BLOCK_SIZE); +} + +int snapshot_prepare_crypto(bool may_sleep, bool create_iv) +{ + char enc_key[DERIVED_KEY_SIZE]; + struct crypto_skcipher *tfm; + int ret = 0; + + ret = snapshot_get_enc_key(enc_key, may_sleep); + if (ret) { + pr_warn_once("enc key is invalid\n"); + return -EINVAL; + } + + c_buffer = (void *)get_zeroed_page(GFP_KERNEL); + if (!c_buffer) { + pr_err("Allocate crypto buffer page failed\n"); + return -ENOMEM; + } + + tfm = crypto_alloc_skcipher("ctr(aes)", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + pr_err("failed to allocate skcipher (%d)\n", ret); + goto alloc_fail; + } + + ret = crypto_skcipher_setkey(tfm, enc_key, AES_MAX_KEY_SIZE); + if (ret) { + pr_err("failed to setkey (%d)\n", ret); + goto set_fail; + } + + sk_req = skcipher_request_alloc(tfm, GFP_KERNEL); + if (!sk_req) { + pr_err("failed to allocate request\n"); + ret = -ENOMEM; + goto set_fail; + } + if (may_sleep) + skcipher_request_set_callback(sk_req, CRYPTO_TFM_REQ_MAY_SLEEP, + NULL, NULL); + if (create_iv) + get_random_bytes(iv, AES_BLOCK_SIZE); + + return 0; + +set_fail: + crypto_free_skcipher(tfm); +alloc_fail: + __free_page(c_buffer); + + return ret; +} + +void snapshot_finish_crypto(void) +{ + struct crypto_skcipher *tfm; + + if (!sk_req) + return; + + tfm = crypto_skcipher_reqtfm(sk_req); + skcipher_request_zero(sk_req); + skcipher_request_free(sk_req); + crypto_free_skcipher(tfm); + __free_page(c_buffer); + sk_req = NULL; +} + +static int encrypt_data_page(void *hash_buffer) +{ + struct scatterlist src[1], dst[1]; + u8 iv_tmp[AES_BLOCK_SIZE]; + int ret = 0; + + if (!sk_req) + return 0; + + memcpy(iv_tmp, iv, sizeof(iv)); + sg_init_one(src, hash_buffer, PAGE_SIZE); + sg_init_one(dst, c_buffer, PAGE_SIZE); + skcipher_request_set_crypt(sk_req, src, dst, PAGE_SIZE, iv_tmp); + ret = crypto_skcipher_encrypt(sk_req); + + copy_page(hash_buffer, c_buffer); + memset(c_buffer, 0, PAGE_SIZE); + + return ret; +} + +static int decrypt_data_page(void *encrypted_page) +{ + struct scatterlist src[1], dst[1]; + u8 iv_tmp[AES_BLOCK_SIZE]; + int ret = 0; + + memcpy(iv_tmp, iv, sizeof(iv)); + sg_init_one(src, encrypted_page, PAGE_SIZE); + sg_init_one(dst, c_buffer, PAGE_SIZE); + skcipher_request_set_crypt(sk_req, src, dst, PAGE_SIZE, iv_tmp); + ret = crypto_skcipher_decrypt(sk_req); + + copy_page(encrypted_page, c_buffer); + memset(c_buffer, 0, PAGE_SIZE); + + return ret; +} + /* * Signature of snapshot image */ @@ -1508,22 +1633,30 @@ int snapshot_image_verify_decrypt(void) if (ret || !s4_verify_desc) goto error_prep; + ret = snapshot_prepare_crypto(true, false); + if (ret) + goto error_prep; + for (i = 0; i < nr_copy_pages; i++) { ret = crypto_shash_update(s4_verify_desc, *(h_buf + i), PAGE_SIZE); if (ret) - goto error_shash; + goto error_shash_crypto; + ret = decrypt_data_page(*(h_buf + i)); + if (ret) + goto error_shash_crypto; } ret = crypto_shash_final(s4_verify_desc, s4_verify_digest); if (ret) - goto error_shash; + goto error_shash_crypto; pr_debug("Signature %*phN\n", SNAPSHOT_DIGEST_SIZE, signature); pr_debug("Digest %*phN\n", SNAPSHOT_DIGEST_SIZE, s4_verify_digest); if (memcmp(signature, s4_verify_digest, SNAPSHOT_DIGEST_SIZE)) ret = -EKEYREJECTED; - error_shash: + error_shash_crypto: + snapshot_finish_crypto(); snapshot_finish_hash(); error_prep: @@ -1564,6 +1697,17 @@ __copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) crypto_buffer = page_address(d_page); } + /* Encrypt hashed page */ + encrypt_data_page(crypto_buffer); + + /* Copy encrypted buffer to destination page in high memory */ + if (PageHighMem(d_page)) { + void *kaddr = kmap_atomic(d_page); + + copy_page(kaddr, crypto_buffer); + kunmap_atomic(kaddr); + } + /* Generate digest */ if (!s4_verify_desc) continue; @@ -1638,6 +1782,8 @@ __copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) } static inline void alloc_h_buf(void) {} +static inline void init_iv(struct swsusp_info *info) {} +static inline void load_iv(struct swsusp_info *info) {} static inline void init_signature(struct swsusp_info *info) {} static inline void load_signature(struct swsusp_info *info) {} static inline void init_sig_verify(struct trampoline *t) {} @@ -2286,6 +2432,7 @@ static int init_header(struct swsusp_info *info) info->size = info->pages; info->size <<= PAGE_SHIFT; info->trampoline_pfn = page_to_pfn(virt_to_page(trampoline_virt)); + init_iv(info); init_signature(info); return init_header_complete(info); } @@ -2524,6 +2671,7 @@ static int load_header(struct swsusp_info *info) nr_copy_pages = info->image_pages; nr_meta_pages = info->pages - info->image_pages - 1; trampoline_pfn = info->trampoline_pfn; + load_iv(info); load_signature(info); } return error; From patchwork Thu Jan 3 14:32:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chun-Yi Lee X-Patchwork-Id: 10747455 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1E3AD91E for ; Thu, 3 Jan 2019 14:33:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0ABF2212E8 for ; Thu, 3 Jan 2019 14:33:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id EFADA285DB; Thu, 3 Jan 2019 14:33:36 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,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 567A0212E8 for ; Thu, 3 Jan 2019 14:33:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727404AbfACOdf (ORCPT ); Thu, 3 Jan 2019 09:33:35 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:44102 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727436AbfACOdf (ORCPT ); Thu, 3 Jan 2019 09:33:35 -0500 Received: by mail-pg1-f194.google.com with SMTP id t13so16073201pgr.11; Thu, 03 Jan 2019 06:33:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=JGhtKGi3o8lk8X2ye6RGCUPzf2p6fpMW9sxGqwlivHw=; b=YeUWqNO5YGPX03UrjdMkd0phQpBkPzwsK8He+lX0G64SV6BVODvlGvtDks+YUTGptW TvEYY9U+HwQ7q9tJbqFLCwGv8Yif5JQsdsBromE8koWLOo6LZTZa/I2bA8WR2VGF13RF mpQfi+PPHxaS8Qq8Xf0BYeAiBj7tEIAMuMcNjfF8HzG7EzFD1B5YoP9Qpz4iYoFXV6oI zKeeTy1sQLVgkdS4mTKYuP0W3FNJgrmdQtHQ5pGeoMi2vxLUugCwxKtyFmnVmv+mDdi3 qzZsxFcNFfhFVmEbnp/ExtehrneCcscsynIOC6DvemQZ6HJ8FObSt/ALzxqkgwbZTTy/ MEXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=JGhtKGi3o8lk8X2ye6RGCUPzf2p6fpMW9sxGqwlivHw=; b=JCNWKCgYgXSw004XHInIZsrMhsp7yrjcrth0bh83wDbwA17Y4zx7DRXCKekQXHhugR jyxe8Ehq7cdxGD5M55LySPlDHXduLtipEsHDaI7tvXkD5y1KVehkSvw/+bjeIxrrJorr PJNTgTDZDMwqjWv7h94Vf3nHuo9WIv+uvqWIWQOKbx1yxshrex3ZMWGKLrGKNJlfxGTE ecblgkXZ7Eg4MOKeOQXXpY2Wfuaq3p6WMl9YePkmtjQyJC31MohH5a6YN+rVL3MpwAR6 94H5TLP588nv1tV2VQfPnmurNpX+W0i5CWINVYdK06YFaoDwZ/cWCIWGlSysZnchS/1e LbkA== X-Gm-Message-State: AJcUukdPgjtCWMX2cU8u26L20Cxeyu0jgfkFSwxYVHhWp8JUKHtIC75P BtNO6vCZs80dyca++/OOWo0= X-Google-Smtp-Source: ALg8bN7ruLo5PjadUD+MUFjqpuS56zo+SgH4rbwT+1gSIK+7za5+d2qqbonXw8HZ5/7z4MIHD+8k6w== X-Received: by 2002:a63:4819:: with SMTP id v25mr17098768pga.308.1546526014050; Thu, 03 Jan 2019 06:33:34 -0800 (PST) Received: from linux-l9pv.suse ([124.11.22.254]) by smtp.gmail.com with ESMTPSA id x3sm184403100pgt.45.2019.01.03.06.33.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 03 Jan 2019 06:33:33 -0800 (PST) From: "Lee, Chun-Yi" X-Google-Original-From: "Lee, Chun-Yi" To: "Rafael J . Wysocki" , Pavel Machek Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, keyrings@vger.kernel.org, "Lee, Chun-Yi" , "Rafael J. Wysocki" , Chen Yu , Oliver Neukum , Ryan Chen , David Howells , Giovanni Gherdovich , Randy Dunlap , Jann Horn , Andy Lutomirski Subject: [PATCH 4/5 v2] PM / hibernate: Erase the snapshot master key in snapshot pages Date: Thu, 3 Jan 2019 22:32:26 +0800 Message-Id: <20190103143227.9138-5-jlee@suse.com> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20190103143227.9138-1-jlee@suse.com> References: <20190103143227.9138-1-jlee@suse.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If the encryption key be guessed then the snapshot master key can also be grabbed from snapshot image. Which means that the authentication key can also be calculated. So kernel erases master key in snapshot pages. Because the master key in image kernel be erased, kernel uses the trampoline page to forward snapshot master key to image kernel. v2: - Add memory barrier after cleaning key initialized flag. Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Chen Yu Cc: Oliver Neukum Cc: Ryan Chen Cc: David Howells Cc: Giovanni Gherdovich Cc: Randy Dunlap Cc: Jann Horn Cc: Andy Lutomirski Signed-off-by: "Lee, Chun-Yi" --- kernel/power/power.h | 6 ++++ kernel/power/snapshot.c | 5 ++++ kernel/power/snapshot_key.c | 67 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/kernel/power/power.h b/kernel/power/power.h index 41263fdd3a54..d2fc73b2e200 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -36,6 +36,7 @@ struct swsusp_info { struct trampoline { bool snapshot_key_valid; int sig_verify_ret; + u8 snapshot_key[SNAPSHOT_KEY_SIZE]; } __aligned(PAGE_SIZE); #ifdef CONFIG_HIBERNATION @@ -55,6 +56,9 @@ extern int snapshot_key_init(void); extern bool snapshot_key_initialized(void); extern int snapshot_get_auth_key(u8 *auth_key, bool may_sleep); extern int snapshot_get_enc_key(u8 *enc_key, bool may_sleep); +extern void snapshot_key_page_erase(unsigned long pfn, void *buff_addr); +extern void snapshot_key_trampoline_backup(struct trampoline *t); +extern void snapshot_key_trampoline_restore(struct trampoline *t); #else static inline int snapshot_image_verify_decrypt(void) { return 0; } static inline int snapshot_prepare_crypto(bool may_sleep, bool create_iv) { return 0; } @@ -62,6 +66,8 @@ static inline void snapshot_finish_crypto(void) {} static inline int snapshot_prepare_hash(bool may_sleep) { return 0; } static inline void snapshot_finish_hash(void) {} static inline int snapshot_key_init(void) { return 0; } +static inline void snapshot_key_trampoline_backup(struct trampoline *t) {} +static inline void snapshot_key_trampoline_restore(struct trampoline *t) {} #endif /* !CONFIG_HIBERNATION_ENC_AUTH */ #ifdef CONFIG_ARCH_HIBERNATION_HEADER diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index cd10ab5e4850..80ed8e7c5ed8 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1697,6 +1697,9 @@ __copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm) crypto_buffer = page_address(d_page); } + /* Erase key data in snapshot */ + snapshot_key_page_erase(pfn, crypto_buffer); + /* Encrypt hashed page */ encrypt_data_page(crypto_buffer); @@ -2482,6 +2485,7 @@ void snapshot_init_trampoline(void) t = (struct trampoline *)trampoline_buff; init_sig_verify(t); + snapshot_key_trampoline_backup(t); pr_info("Hibernation trampoline page prepared\n"); } @@ -2505,6 +2509,7 @@ void snapshot_restore_trampoline(void) t = (struct trampoline *)trampoline_virt; handle_sig_verify(t); + snapshot_key_trampoline_restore(t); snapshot_free_trampoline(); } diff --git a/kernel/power/snapshot_key.c b/kernel/power/snapshot_key.c index 3a569b505d8d..9d478c27d6b9 100644 --- a/kernel/power/snapshot_key.c +++ b/kernel/power/snapshot_key.c @@ -29,11 +29,27 @@ static struct snapshot_key { const char *key_name; bool initialized; unsigned int key_len; + unsigned long pfn; /* pfn of keyblob */ + unsigned long addr_offset; /* offset in page for keyblob */ u8 key[SNAPSHOT_KEY_SIZE]; + u8 fingerprint[SHA512_DIGEST_SIZE]; /* fingerprint of keyblob */ } skey = { .key_name = "swsusp-kmk", }; +static void snapshot_key_clean(void) +{ + crypto_free_shash(hash_tfm); + hash_tfm = NULL; + skey.initialized = false; + barrier(); + skey.pfn = 0; + skey.key_len = 0; + skey.addr_offset = 0; + memzero_explicit(skey.key, SNAPSHOT_KEY_SIZE); + memzero_explicit(skey.fingerprint, SHA512_DIGEST_SIZE); +} + static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen, bool may_sleep) { @@ -81,6 +97,53 @@ static int calc_key_hash(u8 *key, unsigned int key_len, const char *salt, return ret; } +static int get_key_fingerprint(u8 *fingerprint, u8 *key, unsigned int key_len, + bool may_sleep) +{ + return calc_key_hash(key, key_len, "FINGERPRINT", fingerprint, may_sleep); +} + +void snapshot_key_page_erase(unsigned long pfn, void *buff_addr) +{ + if (!skey.initialized || pfn != skey.pfn) + return; + + /* erase key data from snapshot buffer page */ + if (!memcmp(skey.key, buff_addr + skey.addr_offset, skey.key_len)) { + memzero_explicit(buff_addr + skey.addr_offset, skey.key_len); + pr_info("Erased swsusp key in snapshot pages.\n"); + } +} + +/* this function may sleeps because snapshot_key_init() */ +void snapshot_key_trampoline_backup(struct trampoline *t) +{ + if (!t || snapshot_key_init()) + return; + + memcpy(t->snapshot_key, skey.key, skey.key_len); +} + +/* Be called after snapshot image restored success */ +void snapshot_key_trampoline_restore(struct trampoline *t) +{ + u8 fingerprint[SHA512_DIGEST_SIZE]; + + if (!skey.initialized || !t) + return; + + /* check key fingerprint before restore */ + get_key_fingerprint(fingerprint, t->snapshot_key, skey.key_len, true); + if (memcmp(skey.fingerprint, fingerprint, SHA512_DIGEST_SIZE)) { + pr_warn("Restored swsusp key failed, fingerprint mismatch.\n"); + snapshot_key_clean(); + return; + } + + memcpy(skey.key, t->snapshot_key, skey.key_len); + memzero_explicit(t->snapshot_key, SNAPSHOT_KEY_SIZE); +} + /* Derive authentication/encryption key */ static int get_derived_key(u8 *derived_key, const char *derived_type_str, bool may_sleep) @@ -230,10 +293,14 @@ int snapshot_key_init(void) if (err) goto key_fail; + skey.pfn = page_to_pfn(virt_to_page(skey.key)); + skey.addr_offset = (unsigned long) skey.key & ~PAGE_MASK; + get_key_fingerprint(skey.fingerprint, skey.key, skey.key_len, true); barrier(); skey.initialized = true; pr_info("Snapshot key is initialled.\n"); + pr_debug("Fingerprint %*phN\n", SHA512_DIGEST_SIZE, skey.fingerprint); return 0; From patchwork Thu Jan 3 14:32:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chun-Yi Lee X-Patchwork-Id: 10747457 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1D87F91E for ; Thu, 3 Jan 2019 14:33:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0D2D3212E8 for ; Thu, 3 Jan 2019 14:33:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 01479285DB; Thu, 3 Jan 2019 14:33:42 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,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 260CF212E8 for ; Thu, 3 Jan 2019 14:33:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731984AbfACOdl (ORCPT ); Thu, 3 Jan 2019 09:33:41 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:45138 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727436AbfACOdl (ORCPT ); Thu, 3 Jan 2019 09:33:41 -0500 Received: by mail-pg1-f194.google.com with SMTP id y4so16070995pgc.12; Thu, 03 Jan 2019 06:33:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Sg5UAtchFgQ0BNWYd59GPtUZC/WN5NLonMT9IwTkV/o=; b=i7bghvuxWSyaPyuQDoVfIpj1eCJP2eZk0Tp+KmMEW82aleMJY/P33hRCBlyCyLhyOW OoxzhAEIuZklYmnO8wDURxKu7DcHjiPvXJ8F/pw9hueEXeQzTcAGcg/9nXUFjIr4jXkr Sz9I6rOdhrx3yIJfHppW+1OAE/ZAHUwaJ2yLJRHSjSS+GZ2gIFc8uoJ7eGnMnix/Ojfh 7P75w2iLghKyT2m9YbgKaScFwvpb/JKOpLWcwcQZMncXPe69p2JA93rsNeWvQdh5uA67 PDeh18NV/BKAkcNJRe2RRc4J1v3TR4fwQhr7/JiZvR/+NnN/ixGk7N+1cRaTh0t1QOt/ Mliw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Sg5UAtchFgQ0BNWYd59GPtUZC/WN5NLonMT9IwTkV/o=; b=Q7NhdFdofSW/q5A2ec8rSCZ20wJYTwUbBfmuVIYpGRBXslPd6s39eTZ3S7Fc23dcjo gPORJcL7Dgd4Tzu+zsIu5CWPV/rRRBcqJUALywqJKVimpZ1AwNKNCfhWv8ZZhfo4w9Em cCNW2ugOZxd3U/sNYmPogW88CedSr9czdOSTp0SvQXfDmfD0B8egCa73bzgezM8yjorq 9seJBXfK5CR8XQZcejj+YET5m0UuD/KJWAS6biBlnr0zbNWPDqMbR13fxTPx3nRpHDU/ ce4CRtG6aAwsMnwMDR9gYmTms/EZRi2AzNaR3ffowPCFrGjwWIfKDgYLktBBq42o7NX8 TQ2w== X-Gm-Message-State: AJcUukehKL6Vo5tj4hmTyenwUqNcjbPLIN/MR0vFWbuub98UaNS8h09f PNgiYeBOnpwp8RBi+r/xLQg= X-Google-Smtp-Source: ALg8bN5WF4RK7kaTdoILliQEh+TKbS7mBZWfi7iyB3ePMeZUWgE18s3jmDEwmV31qFA2EbXBJzUFXQ== X-Received: by 2002:a63:9f19:: with SMTP id g25mr17188481pge.327.1546526019700; Thu, 03 Jan 2019 06:33:39 -0800 (PST) Received: from linux-l9pv.suse ([124.11.22.254]) by smtp.gmail.com with ESMTPSA id x3sm184403100pgt.45.2019.01.03.06.33.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 03 Jan 2019 06:33:39 -0800 (PST) From: "Lee, Chun-Yi" X-Google-Original-From: "Lee, Chun-Yi" To: "Rafael J . Wysocki" , Pavel Machek Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, keyrings@vger.kernel.org, "Lee, Chun-Yi" , "Rafael J. Wysocki" , Chen Yu , Oliver Neukum , Ryan Chen , David Howells , Giovanni Gherdovich , Randy Dunlap , Jann Horn , Andy Lutomirski Subject: [PATCH 5/5 v2] PM / hibernate: An option to request that snapshot image must be authenticated Date: Thu, 3 Jan 2019 22:32:27 +0800 Message-Id: <20190103143227.9138-6-jlee@suse.com> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20190103143227.9138-1-jlee@suse.com> References: <20190103143227.9138-1-jlee@suse.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This kernel option is similar to the option for kernel module signature verification. When this option is unselected, kernel will be tainted by restored from a snapshot image without (valid) signature. When the option is selected, kernel will refuse the system to be restored from a unauthenticated image. The hibernation resume process will be stopped , the snapshot image will be discarded and system just boots as normal. The hibernation can be triggered without snapshot master key when this option is unselected. But kernel will be tainted after hibernation resume. v2: - Fixed wording in Kconfig Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Chen Yu Cc: Oliver Neukum Cc: Ryan Chen Cc: David Howells Cc: Giovanni Gherdovich Cc: Randy Dunlap Cc: Jann Horn Cc: Andy Lutomirski Signed-off-by: "Lee, Chun-Yi" --- Documentation/admin-guide/kernel-parameters.txt | 6 ++++ include/linux/kernel.h | 3 +- kernel/panic.c | 1 + kernel/power/Kconfig | 11 +++++++ kernel/power/hibernate.c | 8 +++-- kernel/power/power.h | 5 ++++ kernel/power/snapshot.c | 40 +++++++++++++++++++++++-- kernel/power/user.c | 2 +- 8 files changed, 69 insertions(+), 7 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 37e235be1d35..f103b5d4676f 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3991,6 +3991,12 @@ protect_image Turn on image protection during restoration (that will set all pages holding image data during restoration read-only). + enforce_auth When HIBERNATION_ENC_AUTH is set, this means + that snapshot image without (valid) signature + will fail to restore. + Note that if HIBERNATION_ENC_AUTH_FORCE is + set, that is always true, so this option does + nothing. retain_initrd [RAM] Keep initrd memory after extraction diff --git a/include/linux/kernel.h b/include/linux/kernel.h index d6aac75b51ba..61714489cb57 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -598,7 +598,8 @@ extern enum system_states { #define TAINT_LIVEPATCH 15 #define TAINT_AUX 16 #define TAINT_RANDSTRUCT 17 -#define TAINT_FLAGS_COUNT 18 +#define TAINT_UNSAFE_HIBERNATE 18 +#define TAINT_FLAGS_COUNT 19 struct taint_flag { char c_true; /* character printed when tainted */ diff --git a/kernel/panic.c b/kernel/panic.c index d10c340c43b0..7179c6d8d38f 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -335,6 +335,7 @@ const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = { [ TAINT_LIVEPATCH ] = { 'K', ' ', true }, [ TAINT_AUX ] = { 'X', ' ', true }, [ TAINT_RANDSTRUCT ] = { 'T', ' ', true }, + [ TAINT_UNSAFE_HIBERNATE ] = { 'H', ' ', true }, }; /** diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 506a3c5a7a0d..cf1896c32014 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -90,6 +90,17 @@ config HIBERNATION_ENC_AUTH as the master key of hibernation. The TPM trusted key depends on TPM. The security of user defined key relies on user space. +config HIBERNATION_ENC_AUTH_FORCE + bool "Require hibernate snapshot image to be validly signed" + depends on HIBERNATION_ENC_AUTH + help + This option will prevent that a snapshot image without (valid) + signature be restored. Without this option, an unauthenticated + snapshot image can be restored but the restored kernel will be + tainted, which also means that the hibernation can be triggered + without snapshot key but kernel will be tainted without this + option. + config ARCH_SAVE_PAGE_KEYS bool diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 5ac2ab6f4a0e..9515bad0897e 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -272,11 +272,11 @@ static int create_image(int platform_mode) int error; error = snapshot_prepare_hash(false); - if (error) + if (error && snapshot_is_enforce_auth()) return error; error = snapshot_prepare_crypto(false, true); - if (error) + if (error && snapshot_is_enforce_auth()) goto finish_hash; error = dpm_suspend_end(PMSG_FREEZE); @@ -708,7 +708,7 @@ int hibernate(void) } error = snapshot_key_init(); - if (error) + if (error && snapshot_is_enforce_auth()) return error; error = snapshot_create_trampoline(); @@ -1248,6 +1248,8 @@ static int __init hibernate_setup(char *str) } else if (IS_ENABLED(CONFIG_STRICT_KERNEL_RWX) && !strncmp(str, "protect_image", 13)) { enable_restore_image_protection(); + } else if (!strncmp(str, "enforce_auth", 10)) { + snapshot_set_enforce_auth(); } return 1; } diff --git a/kernel/power/power.h b/kernel/power/power.h index d2fc73b2e200..edb63991bcdc 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -36,6 +36,7 @@ struct swsusp_info { struct trampoline { bool snapshot_key_valid; int sig_verify_ret; + bool enforce_auth; u8 snapshot_key[SNAPSHOT_KEY_SIZE]; } __aligned(PAGE_SIZE); @@ -51,6 +52,8 @@ extern int snapshot_prepare_crypto(bool may_sleep, bool create_iv); extern void snapshot_finish_crypto(void); extern int snapshot_prepare_hash(bool may_sleep); extern void snapshot_finish_hash(void); +extern void snapshot_set_enforce_auth(void); +extern int snapshot_is_enforce_auth(void); /* kernel/power/snapshot_key.c */ extern int snapshot_key_init(void); extern bool snapshot_key_initialized(void); @@ -65,6 +68,8 @@ static inline int snapshot_prepare_crypto(bool may_sleep, bool create_iv) { retu static inline void snapshot_finish_crypto(void) {} static inline int snapshot_prepare_hash(bool may_sleep) { return 0; } static inline void snapshot_finish_hash(void) {} +static inline void snapshot_set_enforce_auth(void) {} +static inline int snapshot_is_enforce_auth(void) { return 0; } static inline int snapshot_key_init(void) { return 0; } static inline void snapshot_key_trampoline_backup(struct trampoline *t) {} static inline void snapshot_key_trampoline_restore(struct trampoline *t) {} diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index 80ed8e7c5ed8..03a76c474ab7 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1538,6 +1538,23 @@ static int decrypt_data_page(void *encrypted_page) return ret; } +/* enforce the snapshot to be signed */ +#ifdef CONFIG_HIBERNATION_ENC_AUTH_FORCE +static bool enforce_auth = true; +#else +static bool enforce_auth; +#endif + +void snapshot_set_enforce_auth(void) +{ + enforce_auth = true; +} + +int snapshot_is_enforce_auth(void) +{ + return enforce_auth; +} + /* * Signature of snapshot image */ @@ -1604,6 +1621,8 @@ int snapshot_prepare_hash(bool may_sleep) crypto_free_shash(tfm); s4_verify_digest = NULL; s4_verify_desc = NULL; + if (!enforce_auth) + ret = 0; return ret; } @@ -1665,6 +1684,8 @@ int snapshot_image_verify_decrypt(void) pr_warn("Signature verification failed: %d\n", ret); error: sig_verify_ret = ret; + if (!enforce_auth) + ret = 0; return ret; } @@ -1752,6 +1773,7 @@ static void load_signature(struct swsusp_info *info) static void init_sig_verify(struct trampoline *t) { + t->enforce_auth = enforce_auth; t->sig_verify_ret = sig_verify_ret; t->snapshot_key_valid = snapshot_key_valid; sig_verify_ret = 0; @@ -1760,11 +1782,25 @@ static void init_sig_verify(struct trampoline *t) static void handle_sig_verify(struct trampoline *t) { - if (t->sig_verify_ret) + enforce_auth = t->enforce_auth; + if (enforce_auth) + pr_info("Enforce the snapshot to be validly signed\n"); + + if (t->sig_verify_ret) { pr_warn("Signature verification failed: %d\n", t->sig_verify_ret); - else if (t->snapshot_key_valid) + if (t->snapshot_key_valid) + pr_warn("Did not find valid snapshot key.\n"); + /* taint kernel */ + if (!enforce_auth) { + pr_warn("System resumed from unsafe snapshot - " + "tainting kernel\n"); + add_taint(TAINT_UNSAFE_HIBERNATE, LOCKDEP_STILL_OK); + pr_info("%s\n", print_tainted()); + } + } else if (t->snapshot_key_valid) { pr_info("Signature verification passed.\n"); + } } #else static int diff --git a/kernel/power/user.c b/kernel/power/user.c index d5c8f777e8d8..9597f48f01d0 100644 --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -261,7 +261,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, break; } error = snapshot_key_init(); - if (error) + if (error && snapshot_is_enforce_auth()) return error; error = snapshot_create_trampoline(); if (error) From patchwork Fri Jan 11 19:11:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephan Mueller X-Patchwork-Id: 10760561 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 371A914E5 for ; Fri, 11 Jan 2019 19:13:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2641628488 for ; Fri, 11 Jan 2019 19:13:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 19C1B284E4; Fri, 11 Jan 2019 19:13:59 +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.7 required=2.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,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 B76C728488 for ; Fri, 11 Jan 2019 19:13:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2390331AbfAKTN5 (ORCPT ); Fri, 11 Jan 2019 14:13:57 -0500 Received: from mo4-p01-ob.smtp.rzone.de ([81.169.146.164]:15915 "EHLO mo4-p01-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390316AbfAKTN4 (ORCPT ); Fri, 11 Jan 2019 14:13:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1547234033; s=strato-dkim-0002; d=chronox.de; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: X-RZG-CLASS-ID:X-RZG-AUTH:From:Subject:Sender; bh=z1JSnWMAdIBaOoX07NP+bwCKYNTj6YxEKLWL5bKCEIo=; b=MSQydjtdFivNpvUE7oCRv0hNtvFzhbhGJfF3I9zH1LZD5PRhdOvI0Q5gX2jTAW6PK0 EK2TG5Cnwk6fhZGggldxtSaT6bBu0m1NutnZzlrpzWuQbIdDcHr+gSqcEDgJ8oLOwdEM 1Nrv+h94DWLKobEj0ew9DDZY06Hc3Kouu5g/bg+uWJxRTp26UJIBLsY10fGi1jdStaUo x8DX6KR771bszv6QVw8idxr1MyL9DiY8B6AhugGSswpzcdoJ80Pu8bcZcvflRJ2szEeB EfXEUBDPupEAmTKDChZ8aWPaVXa8XbEaZMyiGij6iJeIQfCNmrvL4Q1kslmSCPKF1fJs e0tQ== X-RZG-AUTH: ":P2ERcEykfu11Y98lp/T7+hdri+uKZK8TKWEqNyiHySGSa9k9xmwdNnzGHXPaLvSbdkg=" X-RZG-CLASS-ID: mo00 Received: from positron.chronox.de by smtp.strato.de (RZmta 44.9 DYNA|AUTH) with ESMTPSA id 309bcfv0BJDQfl8 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (curve secp521r1 with 521 ECDH bits, eq. 15360 bits RSA)) (Client did not present a certificate); Fri, 11 Jan 2019 20:13:26 +0100 (CET) From: Stephan =?iso-8859-1?q?M=FCller?= To: Eric Biggers Cc: Herbert Xu , James Bottomley , Andy Lutomirski , "Lee, Chun-Yi" , "Rafael J . Wysocki" , Pavel Machek , linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, keyrings@vger.kernel.org, "Rafael J. Wysocki" , Chen Yu , Oliver Neukum , Ryan Chen , David Howells , Giovanni Gherdovich , Randy Dunlap , Jann Horn , Andy Lutomirski , linux-crypto@vger.kernel.org Subject: [PATCH 6/6] crypto: tcrypt - add KDF test invocation Date: Fri, 11 Jan 2019 20:11:12 +0100 Message-ID: <2181239.cWAz3ldHXA@positron.chronox.de> In-Reply-To: <9733066.Vrs4h5eWcW@positron.chronox.de> References: <20190103143227.9138-1-jlee@suse.com> <20190109082103.GA8586@sol.localdomain> <9733066.Vrs4h5eWcW@positron.chronox.de> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Enable testing of the SP800-108 and RFC5869 KDFs. Signed-off-by: Stephan Mueller --- crypto/tcrypt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index e7fb87e114a5..5606e59e80ec 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -2054,6 +2054,14 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret += tcrypt_test("cbc(sm4)"); ret += tcrypt_test("ctr(sm4)"); break; + case 192: + ret += tcrypt_test("kdf_ctr(hmac(sha256))"); + ret += tcrypt_test("kdf_dpi(hmac(sha256))"); + ret += tcrypt_test("kdf_fb(hmac(sha256))"); + break; + case 193: + ret += tcrypt_test("hkdf(hmac(sha256))"); + break; case 200: test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0, speed_template_16_24_32);