From patchwork Fri May 26 03:06:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 100539 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp58889qge; Thu, 25 May 2017 20:02:49 -0700 (PDT) X-Received: by 10.98.211.202 with SMTP id z71mr48452677pfk.46.1495767769076; Thu, 25 May 2017 20:02:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495767769; cv=none; d=google.com; s=arc-20160816; b=oskqdQNK00E2gbdyiLjkezeTzQuWmqqmHFzFTpYz/xn1MzlnlWk6Uwtg8VF2CipxP9 Kexfyvhb5S8aQxZLqKysDkvJlfmSuVt7uUG37UyRVwaKPxpwIMS27lZZBxCt6jlMTRqR 3pFJNw5DFL4bpmrM3poYNZFln5OwO91W6xaxG+PEyVBzeJg17HRqstXssDPovwOHSVlE MjiOJbYqO0Y3B7YgjDPJLWBz9dvqAHOkgzWsap9dVAmdUaEGd+xzHqnYwAMJP+3DfiP6 1tq6liL4grllwDyktBEGlOh5fy7VjOpGqGT7TisiPQGVWEBffotnvhhJSkSwZjn1zVXL PL3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=bExCwVIec8kX5zKC+kGsDZZruzL77t5A9SRRc9RdPuw=; b=oIcBn8CipmmR4UZFSR7ydpvDBNnsele3NMjCUv45l5A8x8puJm0jukfsEYdz3/n404 zPevOpCWYl+kx5dAU7IsvPqcs6lewlzFJS7lPurlO/7kKiYdVRMGQym371DKapd6hUFL Nib8HvC0Isg0SRYb/wbL7CVr3KixJvMMmXOT1yz7+L8jnUpvVW8UMybo8KUrggvjPm/i 193gQGeBn0GXblAP9hXm1mtRFwhP3MHTTUhTWkh3/g4kB2QfNmPTcLQpru066meR/TcO q+ylt6B/NLZllYPRMx3fmPSX6CGcLVpXjWNOFKeT0VmWw9c2VXdZYXfoICvzclWIrTWy vKWg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d22si29899690pgn.220.2017.05.25.20.02.48; Thu, 25 May 2017 20:02:49 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1946698AbdEZDCm (ORCPT + 25 others); Thu, 25 May 2017 23:02:42 -0400 Received: from mail-pf0-f180.google.com ([209.85.192.180]:35481 "EHLO mail-pf0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S969428AbdEZDCV (ORCPT ); Thu, 25 May 2017 23:02:21 -0400 Received: by mail-pf0-f180.google.com with SMTP id n23so184340987pfb.2 for ; Thu, 25 May 2017 20:02:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=bExCwVIec8kX5zKC+kGsDZZruzL77t5A9SRRc9RdPuw=; b=QMSpGiodpVcXi0S/HWz3cHq1APWKEmazUT0nt5yfrhN8eQQ0eqBUXAsvH0MxQ0ESnq nhRhdck+mZb6pb55UslCjXMe1dpDvTjlDktb7mVnDqxjAue5sZTMVBT1nAvCe8Z31p/B QkLmHjK+vznaeMrLK/9thefuGI+gsDh7cN/ro= 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=bExCwVIec8kX5zKC+kGsDZZruzL77t5A9SRRc9RdPuw=; b=VWnf8GoTE9NvxXTBbSU2XaMX+EboBqYp6wDTPIdtlB1xB/gsN1UVRjkZlSrvNNILwD BrxBTX8zig21dEhG+MEMiOP0+zeyYuQjfwJhYOfevrhgsq2rsAzvF3myJCXZzgZvrC53 i1oT6esyZvdVyujWiTgi4FXn59z/ZXxEP8zJ6t2e4ENRzyPxP56YmyQVoK/35Xdk0Iq9 ryvHJZ9pDrvrJPWb4EFKIb24R3E1UuHgwQ7q0Hmd3v4Cl8bH4lZw6ZKW989qy/PGGxAe ys554GSec8ODhEbS/nwSJrvD+rU9Q6pdTG4NniHx7gX9WQE8Cy8fHr4f4YUgppHE7bqV 8lZg== X-Gm-Message-State: AODbwcB3eNe3RS5IXICCZjkqxSH8CjSG/uw2/p5f0fF1JsbSOT/MNs6h o8Iv5Zfj1OLQVd39 X-Received: by 10.84.214.150 with SMTP id j22mr54495047pli.133.1495767740645; Thu, 25 May 2017 20:02:20 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id s4sm2782354pgr.10.2017.05.25.20.02.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 May 2017 20:02:20 -0700 (PDT) From: AKASHI Takahiro To: mcgrof@kernel.org Cc: rusty@rustcorp.com.au, dhowells@redhat.com, ming.lei@canonical.com, seth.forshee@canonical.com, kyle@kernel.org, David.Woodhouse@intel.com, linux-kernel@vger.kernel.org, AKASHI Takahiro , "Luis R . Rodriguez" Subject: [PATCH 1/4] firmware: add firmware signing Date: Fri, 26 May 2017 12:06:06 +0900 Message-Id: <20170526030609.1414-2-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170526030609.1414-1-takahiro.akashi@linaro.org> References: <20170526030609.1414-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Systems that have module signing currently enabled may wish to extend vetting of firmware passed to the kernel as well. We can re-use most of the code for module signing for firmware signature verification and signing. This will also later enable re-use of this same code for subsystems that wish to provide their own cryptographic verification requirements on userspace data needed. Contrary to module signing, the signature files are expected to be completely detached for practical and licensing puposes. If you have foo.bin, you'll need foo.bin.p7s file present for firmware signing. Firmware signing is per-data per device and if this feature is enabled permissively (by default), both valid and invalid firmware, which can be unsigned, signed by non-trusted key, or even one with invalid digest, will be loaded, just leaving a warning message in the kernel log. On the othe hand, in enforcing mode, which is enabled by either a kernel configuration (CONFIG_FIRMWARE_SIG_FORCE) or a module parameter (fw_sig_enforce), only the verified firmware are allowed to be loaded. There is one driver data option, DRIVER_DATA_REQ_NO_SIG_CHECK, which will skip signature verification check at load time even in enforcing mode. This option is solely for non security-sensitive data. Please also note any firmware loaded with request_firmware() will not be affected by firmware signing. Contrary to module signing, we do not taint the kernel in the permissive fw signing mode due to restrictions on the firmware_class API, extensions to enable this are expected however in the future. Cc: Rusty Russell Cc: David Howells Cc: Ming Lei Cc: Seth Forshee Cc: Kyle McMartin Cc: David Woodhouse Signed-off-by: Luis R. Rodriguez [akashi:migrated to driver data APIs] Signed-off-by: AKASHI Takahiro --- drivers/base/Kconfig | 25 +++++ drivers/base/firmware_class.c | 211 +++++++++++++++++++++++++++++++++++++++--- include/linux/driver_data.h | 5 + 3 files changed, 229 insertions(+), 12 deletions(-) -- 2.11.1 diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 74779ee3d3b1..4c9600437396 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -79,6 +79,31 @@ config FW_LOADER require userspace firmware loading support, but a module built out-of-tree does. +config FIRMWARE_SIG + bool "Firmware signature verification" + depends on FW_LOADER + select SYSTEM_DATA_VERIFICATION + help + Check firmware files for valid signatures upon load: if the firmware + was called foo.bin, a respective foo.bin.p7s is expected to be + present as the signature in the same directory. + + This configuration only affects drivers with driver_data APIs, + disabling DRIVER_DATA_REQ_NO_SIG_CHECK. + + For more information see Documentation/driver-api/firmware/signing.rst + +config FIRMWARE_SIG_FORCE + bool "Require all firmware to be validly signed" + depends on FIRMWARE_SIG + help + Reject unsigned files or signed files for which we don't have + a trusted key. Without this, you'll only get a record on kernel + log and yet the firmware will be loaded. + + This configuration only affects drivers with driver_data APIs, + disabling DRIVER_DATA_REQ_NO_SIG_CHECK. + config FIRMWARE_IN_KERNEL bool "Include in-kernel firmware blobs in kernel binary" depends on FW_LOADER diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index e87e91bcd8f8..590a2a834fec 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -146,6 +147,9 @@ struct driver_data_params { * o request_firmware_nowait(): __DATA_REQ_FIRMWARE_NOWAIT() */ #define __DATA_REQ_FIRMWARE() \ + .req_params = { \ + .reqs = DRIVER_DATA_REQ_NO_SIG_CHECK, \ + }, \ .priv_params = { \ .priv_reqs = DRIVER_DATA_PRIV_REQ_FALLBACK | \ DRIVER_DATA_PRIV_REQ_FALLBACK_UEVENT, \ @@ -153,7 +157,8 @@ struct driver_data_params { #define __DATA_REQ_FIRMWARE_DIRECT() \ .req_params = { \ - .reqs = DRIVER_DATA_REQ_OPTIONAL, \ + .reqs = DRIVER_DATA_REQ_OPTIONAL | \ + DRIVER_DATA_REQ_NO_SIG_CHECK, \ }, \ .priv_params = { \ .priv_reqs = DRIVER_DATA_PRIV_REQ_FALLBACK | \ @@ -161,6 +166,9 @@ struct driver_data_params { } #define __DATA_REQ_FIRMWARE_BUF(buf, size) \ + .req_params = { \ + .reqs = DRIVER_DATA_REQ_NO_SIG_CHECK, \ + }, \ .priv_params = { \ .priv_reqs = DRIVER_DATA_PRIV_REQ_FALLBACK | \ DRIVER_DATA_PRIV_REQ_FALLBACK_UEVENT | \ @@ -177,6 +185,7 @@ struct driver_data_params { .found_cb = NULL, \ .found_ctx = async_ctx, \ }, \ + .reqs = DRIVER_DATA_REQ_NO_SIG_CHECK, \ }, \ .priv_params = { \ .mode = DRIVER_DATA_ASYNC, \ @@ -204,6 +213,8 @@ struct driver_data_params { (!!((params)->reqs & DRIVER_DATA_REQ_KEEP)) #define driver_data_param_uses_api(params) \ (!!((params)->reqs & DRIVER_DATA_REQ_USE_API_VERSIONING)) +#define driver_data_param_no_sig_check(params) \ + (!!((params)->reqs & DRIVER_DATA_REQ_NO_SIG_CHECK)) #define driver_data_sync_cb(param) ((params)->cbs.sync.found_cb) #define driver_data_sync_ctx(params) ((params)->cbs.sync.found_ctx) @@ -263,6 +274,11 @@ int driver_data_async_call_api_cb(const struct firmware *driver_data, error); } +static bool fw_sig_enforce = IS_ENABLED(CONFIG_FIRMWARE_SIG_FORCE); +#ifndef CONFIG_FIRMWARE_SIG_FORCE +module_param(fw_sig_enforce, bool_enable_only, 0644); +#endif /* !CONFIG_FIRMWARE_SIG_FORCE */ + /* Builtin firmware support */ #ifdef CONFIG_FW_LOADER @@ -445,6 +461,11 @@ struct firmware_buf { void *data; size_t size; size_t allocated_size; + bool sig_ok; +#ifdef CONFIG_FIRMWARE_SIG + void *sig_data; + size_t sig_size; +#endif #ifdef CONFIG_FW_LOADER_USER_HELPER bool is_paged_buf; bool need_uevent; @@ -611,6 +632,9 @@ static void __fw_free_buf(struct kref *ref) #endif if (!buf->allocated_size) vfree(buf->data); +#ifdef CONFIG_FIRMWARE_SIG + vfree(buf->sig_data); +#endif kfree_const(buf->fw_id); kfree(buf); } @@ -648,13 +672,16 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) int i, len; int rc = -ENOENT; char *path; - enum kernel_read_file_id id = READING_FIRMWARE; - size_t msize = INT_MAX; + enum kernel_read_file_id id; + loff_t msize; /* Already populated data member means we're loading into a buffer */ if (buf->data) { id = READING_FIRMWARE_PREALLOC_BUFFER; msize = buf->allocated_size; + } else { + id = READING_FIRMWARE; + msize = LONG_MAX; } path = __getname(); @@ -673,7 +700,7 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) break; } - buf->size = 0; + /* Load firmware */ rc = kernel_read_file_from_path(path, &buf->data, &size, msize, id); if (rc) { @@ -685,11 +712,38 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf) path, rc); continue; } - dev_dbg(device, "direct-loading %s\n", buf->fw_id); buf->size = size; + +#ifdef CONFIG_FIRMWARE_SIG + len = snprintf(path, PATH_MAX, "%s/%s.p7s", + fw_path[i], buf->fw_id); + if (len >= PATH_MAX) { + rc = -ENAMETOOLONG; + break; + } + + /* Load signature */ + rc = kernel_read_file_from_path(path, &buf->sig_data, &size, + LONG_MAX, READING_FIRMWARE); + if (!rc) + buf->sig_size = size; + else if (rc == -ENOENT) + dev_info(device, + "signature of %s doesn't exist\n", buf->fw_id); + else + dev_warn(device, + "loading signature of %s failed (%d)\n", + buf->fw_id, rc); + + /* caller should check existence of signature with sig_size */ + rc = 0; +#endif /* CONFIG_FIRMWARE_SIG */ + + dev_dbg(device, "direct-loading %s\n", buf->fw_id); fw_state_done(&buf->fw_st); break; } + __putname(path); return rc; @@ -716,9 +770,9 @@ static void fw_set_page_data(struct firmware_buf *buf, struct firmware *fw) fw->size = buf->size; fw->data = buf->data; - pr_debug("%s: fw-%s buf=%p data=%p size=%u\n", + pr_debug("%s: fw-%s buf=%p data=%p size=%u sig_ok=%s\n", __func__, buf->fw_id, buf, buf->data, - (unsigned int)buf->size); + (unsigned int)buf->size, buf->sig_ok ? "(yes)" : "(no)"); } #ifdef CONFIG_PM_SLEEP @@ -822,6 +876,25 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device, return 0; } +#ifdef CONFIG_FIRMWARE_SIG +static int firmware_sig_check(struct firmware *fw) +{ + struct firmware_buf *buf = fw->priv; + int err; + + if (!buf->sig_size) + return -ENOENT; + + err = verify_pkcs7_signature(buf->data, buf->size, + buf->sig_data, buf->sig_size, + NULL, VERIFYING_FIRMWARE_SIGNATURE, NULL, NULL); + if (!err) + buf->sig_ok = true; + + return err; +} +#endif /* CONFIG_FIRMWARE_SIG */ + /* * user-mode helper code */ @@ -1224,6 +1297,83 @@ static ssize_t firmware_data_write(struct file *filp, struct kobject *kobj, return retval; } +static ssize_t firmware_sig_data_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buffer, loff_t offset, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct firmware_priv *fw_priv = to_firmware_priv(dev); + struct firmware_buf *buf; + ssize_t ret_count; + + mutex_lock(&fw_lock); + buf = fw_priv->buf; + if (!buf || fw_state_is_done(&buf->fw_st)) { + ret_count = -ENODEV; + goto out; + } + if (offset > buf->size) { + ret_count = 0; + goto out; + } + if (count > buf->size - offset) + ret_count = buf->size - offset; + else + ret_count = count; + + memcpy(buffer, buf->data + offset, ret_count); + +out: + mutex_unlock(&fw_lock); + return ret_count; +} + +static ssize_t firmware_sig_data_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buffer, loff_t offset, + size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct firmware_priv *fw_priv = to_firmware_priv(dev); + struct firmware_buf *buf; + void *buf_tmp; + size_t new_size; + ssize_t ret_count; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + mutex_lock(&fw_lock); + buf = fw_priv->buf; + if (!buf || fw_state_is_done(&buf->fw_st)) { + ret_count = -ENODEV; + goto out; + } + + if (buf->sig_data && (offset + count > buf->sig_size)) { + /* grow a buffer */ + new_size = min(size_t, PAGE_SIZE, offset + count); + buf_tmp = NULL; + if (new_size <= PAGE_SIZE) + buf_tmp = vmalloc(new_size); + if (!buf_tmp) + ret_count = -ENOMEM; + goto out; + } + memcpy(buf_tmp, buf->sig_data, buf->sig_size); + vfree(buf->sig_data); + buf->sig_data = buf_tmp; + buf->sig_size = new_size; + } + + ret_count = min(size_t, buf->sig_size - offset, count); + memcpy(buf->data + offset, buffer, ret_count); + +out: + mutex_unlock(&fw_lock); + return ret_count; +} + static struct bin_attribute firmware_attr_data = { .attr = { .name = "data", .mode = 0644 }, .size = 0, @@ -1231,6 +1381,13 @@ static struct bin_attribute firmware_attr_data = { .write = firmware_data_write, }; +static struct bin_attribute firmware_attr_sig_data = { + .attr = { .name = "sig_data", .mode = 0644 }, + .size = 0, + .read = firmware_sig_data_read, + .write = firmware_sig_data_write, +}; + static struct attribute *fw_dev_attrs[] = { &dev_attr_loading.attr, NULL @@ -1238,6 +1395,7 @@ static struct attribute *fw_dev_attrs[] = { static struct bin_attribute *fw_dev_bin_attrs[] = { &firmware_attr_data, + &firmware_attr_sig_data, NULL }; @@ -1364,9 +1522,6 @@ static int fw_load_from_user_helper(struct firmware *firmware, fw_priv->buf = firmware->priv; ret = _request_firmware_load(fw_priv, data_params, timeout); - if (!ret) - ret = assign_firmware_buf(firmware, device, data_params); - out_unlock: usermodehelper_read_unlock(); @@ -1490,11 +1645,43 @@ _request_firmware(const struct firmware **firmware_p, const char *name, "Direct firmware load for %s failed with error %d\n", name, ret); ret = driver_data_fallback(fw, name, device, data_params, ret); - } else - ret = assign_firmware_buf(fw, device, data_params); + } + if (ret) + goto out; + +#ifdef CONFIG_FIRMWARE_SIG + if (driver_data_param_no_sig_check(&data_params->req_params)) + goto skip_sig_check; + + /* Verify the data with its signature */ + ret = firmware_sig_check(fw); + if (ret) { + if (fw_sig_enforce) { + /* ENFORCING */ + dev_err(device, + "firmware [%s] verification failed (%d).\n", + name, ret); + + goto out; + } + + /* PERMISSIVE */ + dev_warn(device, + "firmware [%s] verification failed (%d), but this is ok.\n", + name, ret); + } else { + dev_info(device, "firmware [%s] verification succeeded.\n", + name); + } + + skip_sig_check: +#endif /* CONFIG_FIRMWARE_SIG */ + ret = assign_firmware_buf(fw, device, data_params); out: if (ret < 0) { + dev_warn(device, "Loading firmware failed (%d)\n", ret); + release_firmware(fw); fw = NULL; } diff --git a/include/linux/driver_data.h b/include/linux/driver_data.h index cfeaacfd74d3..039b77b82a91 100644 --- a/include/linux/driver_data.h +++ b/include/linux/driver_data.h @@ -123,11 +123,16 @@ union driver_data_cbs { * file to be present given the API range, it is only required for one * file in the API range to be present. If the %DRIVER_DATA_REQ_OPTIONAL * flag is also enabled then all files are treated as optional. + * @DRIVER_DATA_REQ_NO_SIG_CHECK: indicates that signature verification + * for this driver data is not required for any reason. + * So even if CONFIG_FIRMWARE_SIG_ENFORCE is enabled, the data will be + * successfully loaded if it does exist. */ enum driver_data_reqs { DRIVER_DATA_REQ_OPTIONAL = 1 << 0, DRIVER_DATA_REQ_KEEP = 1 << 1, DRIVER_DATA_REQ_USE_API_VERSIONING = 1 << 2, + DRIVER_DATA_REQ_NO_SIG_CHECK = 1 << 3, }; /** From patchwork Fri May 26 03:06:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 100542 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp59161qge; Thu, 25 May 2017 20:03:50 -0700 (PDT) X-Received: by 10.84.212.137 with SMTP id e9mr55536121pli.115.1495767830433; Thu, 25 May 2017 20:03:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495767830; cv=none; d=google.com; s=arc-20160816; b=BBPk1mWQVBVVJVQcpxwgjbAqxM5CcQdRy7hvvOwJdq2y8rX1d6mRX8OXjV7cmZzsuj wsIZOBbQHDaaZGhjkpyJqNdfYfe93FAM6/3D9jQg1oGZ2/cBudvdploqbKkkabar3PSa 0gtHHE8MBSroMSoxk6872O0lEOoEZIFoaXB22mVWtZowZmj5e4DBZ1LnzUMNTMw9sH40 5ysvZhQpTSDkgcze5zwepuYMZ/3ge1WOMAWsZ+gVM37feblq6DvFQaZ8/Ih5npH+oEOC uUqQj8rX6IOQsFCCTUzifT92Q6q0/b+neSIkd1QJe+14ad59zZiC76KkB9ZYL14xIUvd DcWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=d5s3nBO14T/EkE8e/Ypj6M7xuNogABUB92cy0/knhkk=; b=t9EgkxzHDC4v81SaaBbHTBtleg+DVKWYt2LrL9NDYYeytkdQPeodpRzEneblpsU5YZ eIkZx4upen0osml4FmPOMTCuabK3Oep54NAIwQxELuyT7Chwm9TilutdN9M6D/qZ2sto gbYO/Sy1XyTSTzcTRBwanBDqSZ28bVFfg8DOGPfw+05/vZygWSfdax1KWCyppg/ZJ+M5 pix6FGFTONPrDqmE7GDb9VNNv1Lel4n2fQBrtqVkjdjAqxuQaJfw6jqEB3nidg9zH9a1 mQZbdP1/+9e+zJuQjmpm8Tijr75cE5oAEy8bDgxXHzgjqr8ziOTDLR6w7d9sMP2eG61Z c0PA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 79si29412988pga.195.2017.05.25.20.03.50; Thu, 25 May 2017 20:03:50 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1946715AbdEZDDL (ORCPT + 25 others); Thu, 25 May 2017 23:03:11 -0400 Received: from mail-pf0-f179.google.com ([209.85.192.179]:33246 "EHLO mail-pf0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S969447AbdEZDC1 (ORCPT ); Thu, 25 May 2017 23:02:27 -0400 Received: by mail-pf0-f179.google.com with SMTP id e193so184457052pfh.0 for ; Thu, 25 May 2017 20:02:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=d5s3nBO14T/EkE8e/Ypj6M7xuNogABUB92cy0/knhkk=; b=f6NAbrC1r8M9d78kDOWN6BWLL4mtaGDHc4ZDOnW0vicBlUpmI1L6e4ZF6C5Xw1dzbm HwTLUcsFr77ltFpwXz+3zXyGREjKxraSuw9aLpqxfwxb1G7nHnl3S+MxAFMk0AT0ibBr Drt4rQLzFXBNyyxKl33wLYht3nW3ME4bV2GbE= 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=d5s3nBO14T/EkE8e/Ypj6M7xuNogABUB92cy0/knhkk=; b=E1Cfvn0bCw9/kHC+GQH5kWFyjeCxQ6vFQ3cUiVRjQ8zlIrbT5IAoeJRbo7iMMssL/K +617OHg29jNhaHNNoUGA5OkKiX6OeDzXpAL20S/WbxGZfwOaBgmKswYRHoTpQrCyIh5n 0A2QKE9X1r6AT5mDbiCgfPBbD8jyaVVd23McVgWTqQ357i4SsCWJr9o5C9hpLNpoiLN+ HfFT4a9nZeBbIc4jCXfwCFYF8zgmIu4zO18oGCrluerfgn5bm0+Ec3Mu0lqtmFe4K7Zf evYM6BQEEG20VsR6uwAGGFsU0ytQ8T6n9UTvJ6z2XCjlKFibeUAah7ioGnH1mYHww8sw LypQ== X-Gm-Message-State: AODbwcA2aIogNAQK1UDxPA0hlLhQljNVXvqF8I6UCrTehcHkBu/TRb5n oWpaZh6E819QsFGq X-Received: by 10.84.229.78 with SMTP id d14mr54082255pln.15.1495767747141; Thu, 25 May 2017 20:02:27 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id s68sm16175926pgc.5.2017.05.25.20.02.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 May 2017 20:02:26 -0700 (PDT) From: AKASHI Takahiro To: mcgrof@kernel.org Cc: rusty@rustcorp.com.au, dhowells@redhat.com, ming.lei@canonical.com, seth.forshee@canonical.com, kyle@kernel.org, David.Woodhouse@intel.com, linux-kernel@vger.kernel.org, AKASHI Takahiro , "Luis R . Rodriguez" Subject: [PATCH 2/4] scripts: sign-file: add firmware-signing option Date: Fri, 26 May 2017 12:06:07 +0900 Message-Id: <20170526030609.1414-3-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170526030609.1414-1-takahiro.akashi@linaro.org> References: <20170526030609.1414-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This new option (-f) allows us to create a signature file (*.p7s) for firmware binary. Signed-off-by: AKASHI Takahiro Cc: Luis R. Rodriguez --- scripts/sign-file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) -- 2.11.1 diff --git a/scripts/sign-file.c b/scripts/sign-file.c index fbd34b8e8f57..211f6531fd7e 100644 --- a/scripts/sign-file.c +++ b/scripts/sign-file.c @@ -242,8 +242,11 @@ int main(int argc, char **argv) #endif do { - opt = getopt(argc, argv, "sdpk"); + opt = getopt(argc, argv, "fsdpk"); switch (opt) { + case 'f': + use_signed_attrs = 0; + sign_only = true; save_sig = true; break; case 's': raw_sig = true; break; case 'p': save_sig = true; break; case 'd': sign_only = true; save_sig = true; break; From patchwork Fri May 26 03:06:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 100540 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp59002qge; Thu, 25 May 2017 20:03:16 -0700 (PDT) X-Received: by 10.98.130.1 with SMTP id w1mr49071620pfd.128.1495767796726; Thu, 25 May 2017 20:03:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495767796; cv=none; d=google.com; s=arc-20160816; b=tmakFN81bedPhalvC08zsG/zdSFJaUIKi4TdpfDmmM0ME18ed2c9e50LDPNAbq/d2Q MZZgnYcLgOytKF0TqSs+kBOxYS3xIH6JgRKGYBlZJdNKlmq9CVsYbBkCJcXV5Ygbu7am dlPLZZtbiE5aO7LezARKeTTkA2rRDDVSJDBq/K2hXAvKabJBxC6PpAVDSzCKassChF1x rKoBtpv0sFuSv3+CTBIkRj4c28by4vLc3bUXyY2ccmvKNUWkNyKBp8MPHfLwkKxfqetx 4hVpNXlVPs3vP+1PyqLvjnNNcHAxQny7hQoEpuB12Zbn3seNhwdFljUEzALsMMZL0Hif XkSQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=AOGbZwMy6mkdVrA3XiiVYGNbtrXuJdy/7jUtrUo0SV4=; b=ohjDrk/QyGUE2GmAlY+RChaqxZgDytnTHi+HQ3KKw2J1pYk6z2uNIqG4nsshu5hMSz XAZ3MknaSx2g5v4b6nk/MxYGR69CDlH8XvEGUNy0Qn4DTB9ChOc7yMDkeaWNIaCe33Rh HlrAyy5/OEOg0rVeknYf3EJJji4uSq08mojskWW6YGVGT+6zibpmQphuo764pBksi8QX vu8jteFAicHsM5kcneeWEYM97BggehwklRlQV0At8zcF/D+EejbzkjNq/phxx0duVr6c IvubBkSOhFQANUzhM+j8kwnLo0zkEfsp8jwgqVm72m4iWmT/YT/n5G81upHOwWERAfXV 0cCA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t141si30678767pgb.103.2017.05.25.20.03.16; Thu, 25 May 2017 20:03:16 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1946731AbdEZDDN (ORCPT + 25 others); Thu, 25 May 2017 23:03:13 -0400 Received: from mail-pf0-f173.google.com ([209.85.192.173]:33283 "EHLO mail-pf0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1946685AbdEZDCd (ORCPT ); Thu, 25 May 2017 23:02:33 -0400 Received: by mail-pf0-f173.google.com with SMTP id e193so184458850pfh.0 for ; Thu, 25 May 2017 20:02:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=AOGbZwMy6mkdVrA3XiiVYGNbtrXuJdy/7jUtrUo0SV4=; b=YfXlCpeetijQj75kWMp7QUPdr7X60RkiY0hW5A70zBb879b2jhIXiYdaY6JmVWFpdU gPW+tVXE7UrZX5+BzJ/g0XswahEBcg2YXkpDm+4+XMZ7lM733YBfouoF/sresSsDqLod u68h8Lxbl0UvfyQRNlMkuSy2Bm/x6t62Veonc= 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=AOGbZwMy6mkdVrA3XiiVYGNbtrXuJdy/7jUtrUo0SV4=; b=G41Fi2kZjlZVOk9871VWV1HzsfIig0i2Ouu2jVdUsiR3fh+eI0SH4N0JOM2o2REGt7 vkzHx9MIpyiie+n26Vhkbf3vwyYYCvD/SC2tD0arvzdT8UjncJuWQHjz5nLP5kl6QoUl 44bQ/mauAjx7E9xmrEmBGXIEOLegrfLeMALpTL14irDuRbhtXotvusAAyQ+HTkkAHQqr MJX7uWFrOuS3dZehxKg2Eq4ORLEB37ggKJ5UrxvSjsXB2kVS2BL2okwJL0XJLf6D1T4n bRej2JmeMKkyJeMhFkGqF6jDL9w9v675EaeO/Tn7Bt4tvS0lWvi8891BfB8KvKd9B9it 0uag== X-Gm-Message-State: AODbwcAsD1ExowCQqoLdjFBpwm6Aio7dYAkCzGHjE67F1VzqMDsNUJNE +o1OwlQZZox5z4LA X-Received: by 10.98.147.199 with SMTP id r68mr48435323pfk.168.1495767752190; Thu, 25 May 2017 20:02:32 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id i67sm16231808pfk.87.2017.05.25.20.02.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 May 2017 20:02:31 -0700 (PDT) From: AKASHI Takahiro To: mcgrof@kernel.org Cc: rusty@rustcorp.com.au, dhowells@redhat.com, ming.lei@canonical.com, seth.forshee@canonical.com, kyle@kernel.org, David.Woodhouse@intel.com, linux-kernel@vger.kernel.org, AKASHI Takahiro , "Luis R . Rodriguez" Subject: [PATCH 3/4] test: firmwware: add signature test to driver_data loader test Date: Fri, 26 May 2017 12:06:08 +0900 Message-Id: <20170526030609.1414-4-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170526030609.1414-1-takahiro.akashi@linaro.org> References: <20170526030609.1414-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add the following tests: No.15 - verify loaded data witha signature No.16 - verify loaded data witha signature under signature enforcing For each test, there are several test cases: * no signature provided * valid signature provided * invalid signature provided Signed-off-by: AKASHI Takahiro Cc: Luis R. Rodriguez --- lib/test_driver_data.c | 56 ++++- tools/testing/selftests/firmware/driver_data.sh | 265 +++++++++++++++++++++++- 2 files changed, 315 insertions(+), 6 deletions(-) -- 2.11.1 diff --git a/lib/test_driver_data.c b/lib/test_driver_data.c index 422ea6289396..660cf9ff9ac0 100644 --- a/lib/test_driver_data.c +++ b/lib/test_driver_data.c @@ -85,6 +85,9 @@ int num_test_devs; * @api_min: API min version to use for the test. * @api_max: API max version to use for the test. * @api_name_postfix: API name postfix + * @no_sig_check: whether or not we wish to verify the driver_data with its + * signature. If CONFIG_FIRMWARE_SIG_ENFORCE, passing the verification + * is mandatory. * @test_result: a test may use this to collect the result from the call * of the driver_data_request_async() or driver_data_request_sync() calls * used in their tests. Note that for async calls this typically will be a @@ -125,6 +128,7 @@ struct test_config { u8 api_min; u8 api_max; char *api_name_postfix; + bool no_sig_check; int test_result; }; @@ -345,6 +349,9 @@ static ssize_t config_show(struct device *dev, len += snprintf(buf+len, PAGE_SIZE, "keep:\t\t%s\n", config->keep ? "true" : "false"); + len += snprintf(buf+len, PAGE_SIZE, + "no_sig_check:\t%s\n", + config->no_sig_check ? "true" : "false"); mutex_unlock(&test_dev->config_mutex); @@ -443,6 +450,9 @@ static int config_sync_req_cb(void *context, { struct driver_data_test_device *test_dev = context; + if (unused_error) + return unused_error; + return config_load_data(test_dev, driver_data); } @@ -455,14 +465,19 @@ static int trigger_config_sync(struct driver_data_test_device *test_dev) (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) | (config->keep ? - DRIVER_DATA_REQ_KEEP : 0)), + DRIVER_DATA_REQ_KEEP : 0) | + (config->no_sig_check ? + DRIVER_DATA_REQ_NO_SIG_CHECK : + 0)), }; const struct driver_data_req_params req_params_opt_cb = { DRIVER_DATA_DEFAULT_SYNC(config_sync_req_cb, test_dev), DRIVER_DATA_SYNC_OPT_CB(config_sync_req_default_cb, test_dev), .reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) | - (config->keep ? DRIVER_DATA_REQ_KEEP : 0), + (config->keep ? DRIVER_DATA_REQ_KEEP : 0) | + (config->no_sig_check ? DRIVER_DATA_REQ_NO_SIG_CHECK : + 0), }; const struct driver_data_req_params *req_params; @@ -528,20 +543,26 @@ static int trigger_config_async(struct driver_data_test_device *test_dev) const struct driver_data_req_params req_params_default = { DRIVER_DATA_DEFAULT_ASYNC(config_async_req_cb, test_dev), .reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) | - (config->keep ? DRIVER_DATA_REQ_KEEP : 0), + (config->keep ? DRIVER_DATA_REQ_KEEP : 0) | + (config->no_sig_check ? DRIVER_DATA_REQ_NO_SIG_CHECK : + 0), }; const struct driver_data_req_params req_params_opt_cb = { DRIVER_DATA_DEFAULT_ASYNC(config_async_req_cb, test_dev), DRIVER_DATA_ASYNC_OPT_CB(config_async_req_default_cb, test_dev), .reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) | - (config->keep ? DRIVER_DATA_REQ_KEEP : 0), + (config->keep ? DRIVER_DATA_REQ_KEEP : 0) | + (config->no_sig_check ? DRIVER_DATA_REQ_NO_SIG_CHECK : + 0), }; const struct driver_data_req_params req_params_api = { DRIVER_DATA_API_CB(config_async_req_api_cb, test_dev), DRIVER_DATA_API(config->api_min, config->api_max, config->api_name_postfix), .reqs = (config->optional ? DRIVER_DATA_REQ_OPTIONAL : 0) | (config->keep ? DRIVER_DATA_REQ_KEEP : 0) | - (config->use_api_versioning ? DRIVER_DATA_REQ_USE_API_VERSIONING : 0), + (config->use_api_versioning ? DRIVER_DATA_REQ_USE_API_VERSIONING : 0) | + (config->no_sig_check ? DRIVER_DATA_REQ_NO_SIG_CHECK : + 0), }; const struct driver_data_req_params *req_params; @@ -670,6 +691,7 @@ static int __driver_data_config_init(struct test_config *config) config->use_api_versioning = false; config->api_min = 0; config->api_max = 0; + config->no_sig_check = false; config->test_result = 0; return 0; @@ -1108,6 +1130,29 @@ static ssize_t config_api_name_postfix_show(struct device *dev, static DEVICE_ATTR(config_api_name_postfix, 0644, config_api_name_postfix_show, config_api_name_postfix_store); +static ssize_t config_no_sig_check_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct driver_data_test_device *test_dev = dev_to_test_dev(dev); + struct test_config *config = &test_dev->config; + + return test_dev_config_update_bool(test_dev, buf, count, + &config->no_sig_check); +} + +static ssize_t config_no_sig_check_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct driver_data_test_device *test_dev = dev_to_test_dev(dev); + struct test_config *config = &test_dev->config; + + return test_dev_config_show_bool(test_dev, buf, config->no_sig_check); +} +static DEVICE_ATTR(config_no_sig_check, 0644, config_no_sig_check_show, + config_no_sig_check_store); + static ssize_t test_result_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1147,6 +1192,7 @@ static struct attribute *test_dev_attrs[] = { TEST_DRIVER_DATA_DEV_ATTR(config_api_min), TEST_DRIVER_DATA_DEV_ATTR(config_api_max), TEST_DRIVER_DATA_DEV_ATTR(config_api_name_postfix), + TEST_DRIVER_DATA_DEV_ATTR(config_no_sig_check), TEST_DRIVER_DATA_DEV_ATTR(test_result), NULL, diff --git a/tools/testing/selftests/firmware/driver_data.sh b/tools/testing/selftests/firmware/driver_data.sh index bfd0436cce47..f9c52a87b9d0 100755 --- a/tools/testing/selftests/firmware/driver_data.sh +++ b/tools/testing/selftests/firmware/driver_data.sh @@ -54,6 +54,10 @@ ALL_TESTS="$ALL_TESTS 0013:1:1" # system_wakeupakeup | socat - /dev/pts/7,raw,echo=0,crnl #ALL_TESTS="$ALL_TESTS 0014:0:1" +# Before running these tests, we must prepare an appropriate signature. +#ALL_TESTS="$ALL_TESTS 0015:1:1" +#ALL_TESTS="$ALL_TESTS 0016:1:1" + test_modprobe() { if [ ! -d $DIR ]; then @@ -100,6 +104,10 @@ function allow_user_defaults() # This is an unlikely real-world firmware content. :) echo "ABCD0123" >"$FW" + + # TODO: some set-up is necessary in advance + cp ${TEST_DIR}/fwbin/*sig*-*.bin ${FWPATH} + cp ${TEST_DIR}/fwbin/*sig*-*.bin.p7s ${FWPATH} } test_reqs() @@ -133,7 +141,7 @@ test_finish() { echo -n "$OLD_PATH" >/sys/module/firmware_class/parameters/path rm -f "$FW" - rmdir "$FWPATH" + rm -rf "$FWPATH" } errno_name_to_val() @@ -147,6 +155,12 @@ errno_name_to_val() echo -2;; -EINVAL) echo -22;; + -EBADMSG) + echo -74;; + -ENOKEY) + echo -126;; + -EKEYREJECTED) + echo -129;; -ERR_ANY) echo -123456;; *) @@ -164,12 +178,37 @@ errno_val_to_name() echo -ENOENT;; -22) echo -EINVAL;; + -74) + echo -EBADMSG;; + -126) + echo -ENOKEY;; + -129) + echo -EKEYREJECTED;; -123456) echo -ERR_ANY;; *) echo invalid;; esac +is_not_sig_enforced() +{ + if [ "Y" == \ + $(cat /sys/module/firmware_class/parameters/fw_sig_enforce) ] + then + echo "$0: Signature enforced. Cannot run this test." >&2 + exit 1 + fi +} + +enforce_sig_check() +{ + if ! echo -n 1 >/sys/module/firmware_class/parameters/fw_sig_enforce + then + echo "$0: Unable to set to fw_sig_enforce" >&2 + exit 1 + fi +} + config_set_async() { if ! echo -n 1 >$DIR/config_async ; then @@ -202,6 +241,22 @@ config_disable_optional() fi } +config_set_sig_check() +{ + if ! echo -n 0 >$DIR/config_no_sig_check ; then + echo "$0: Unable to set to sig_check" >&2 + exit 1 + fi +} + +config_disable_sig_check() +{ + if ! echo -n 1 >$DIR/config_no_sig_check ; then + echo "$0: Unable to disable sig_check" >&2 + exit 1 + fi +} + config_set_keep() { if ! echo -n 1 >$DIR/config_keep; then @@ -820,6 +875,212 @@ driver_data_test_0014() driver_data_test_0014a } +# no signature provided, with driver not requiring it +driver_data_test_0015_1_1() +{ + NAME=nosig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_disable_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# good signature, with driver not requiring it +driver_data_test_0015_1_2() +{ + NAME=goodsig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_disable_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# no signature provided (ENOENT) +driver_data_test_0015_2() +{ + NAME=nosig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# good signature +driver_data_test_0015_3() +{ + NAME=goodsig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# signature not signed with a trusted key (ENOKEY) +driver_data_test_0015_4() +{ + NAME=badsig1-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# digest doens't match (wrong hash value) (EKEYREJECTED) +driver_data_test_0015_5() +{ + NAME=badsig2-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# signature corrupted/parsing error (EBADMSG) +driver_data_test_0015_6() +{ + NAME=badsig3-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +driver_data_test_0015() +{ + is_not_sig_enforced + + driver_data_test_0015_1_1 + driver_data_test_0015_1_2 + driver_data_test_0015_2 + driver_data_test_0015_3 + driver_data_test_0015_4 + driver_data_test_0015_5 + driver_data_test_0015_6 +} + +# no signature provided, with driver not requiring it +driver_data_test_0016_1_1() +{ + NAME=nosig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_disable_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# good signature, with driver not requiring it +driver_data_test_0016_1_2() +{ + NAME=goodsig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_disable_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# no signature provided (ENOENT) +driver_data_test_0016_2() +{ + NAME=nosig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger_want_fail ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} -ENOENT +} + +# good signature +driver_data_test_0016_3() +{ + NAME=goodsig-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger ${FUNCNAME[0]} + config_file_should_match ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} SUCCESS +} + +# signature not signed with a trusted key (ENOKEY) +driver_data_test_0016_4() +{ + NAME=badsig1-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger_want_fail ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} -ENOKEY +} + +# digest doens't match (wrong hash value) (EKEYREJECTED) +driver_data_test_0016_5() +{ + NAME=badsig2-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger_want_fail ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} -EKEYREJECTED +} + +# signature corrupted/parsing error (EBADMSG) +driver_data_test_0016_6() +{ + NAME=badsig3-$DEFAULT_DRIVER_DATA + + driver_data_set_sync_defaults + config_set_name $NAME + config_set_sig_check + config_trigger_want_fail ${FUNCNAME[0]} + config_expect_result ${FUNCNAME[0]} -EBADMSG +} + +# This test case must be run at the last. +# Otherwe we must reboot the kernel to reset fw_sig_enforce. +driver_data_test_0016() +{ + enforce_sig_check + + driver_data_test_0016_1_1 + driver_data_test_0016_1_2 + driver_data_test_0016_2 + driver_data_test_0016_3 + driver_data_test_0016_4 + driver_data_test_0016_5 + driver_data_test_0016_6 +} + list_tests() { echo "Test ID list:" @@ -842,6 +1103,8 @@ list_tests() echo "0012 x $(get_test_count 0012) - Verify api call wills will hunt for files, ignore file" echo "0013 x $(get_test_count 0013) - Verify api call works" echo "0014 x $(get_test_count 0013) - Verify api call works with suspend + resume" + echo "0015 x $(get_test_count 0015) - Verify loaded data with signature" + echo "0016 x $(get_test_count 0016) - Verify loaded data with signature under signature enforcing" } test_reqs From patchwork Fri May 26 03:06:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 100541 Delivered-To: patch@linaro.org Received: by 10.140.96.100 with SMTP id j91csp59012qge; Thu, 25 May 2017 20:03:18 -0700 (PDT) X-Received: by 10.99.23.100 with SMTP id 36mr19891171pgx.118.1495767798821; Thu, 25 May 2017 20:03:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1495767798; cv=none; d=google.com; s=arc-20160816; b=EzjBrapXjWc9ntubWeEyAIkOg2qT8VpKBdz/1IkkGplApM9pcpuzRJgKe9T3QAvQmJ IMq2KO6BC9+G3TWP79JGX5xAAcwKu81uTuPoo2IzGI4XHrxmzuOKKp03ZsVcH6RZyChT hMtJxo+ipGFbLgWI2m6Su+2zIXLGegoWpG+BoDrgFbz4vMuruPP3ZL5zk7rpA1AGB/8D LeT71Jgn9167ZCJxhahWl0yVXXZ0fN2LGGJvs9urT3NkwH9XA3+jxob5FgGIqkLwgkHl 2mU/mE/9RoG5ecZNtBTZp+SMBkLuxmuhKjkGqzGgzLHs9ouWl5SRGriuqkK1Tl6Cxf3C qTPg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=1A8I2nEZmPOIpJAiQX9fzwArdqhJSImxS2uyuAXpJsU=; b=ViCKdq4GTpvzk1+Knfabb06ulJ4o74Ol+z0gmEwCsgkJ6rsZPeIEBBmppfT8265Skk 1zLqRfTQVilYPc0JypMse7aW0LHODpOzHnpxSS5SJAMCRMmsNmnZOEKwzDNB0EQDeOw4 a/lSmt4+WWfFQVYzu2cJI7GsMWhPW9IvQM3AwObcCEKuQQ8K3NVIKHUL2Io6F/9vN4Wo 4F2xUExs1/eMBrAbkopcue8rzZ9mKZmWF104Ikv7xPuLCh4zVPMvd3URX4fUPIo5tUb2 uNl7Sc6QOtc8hlCW976I83fE4FS1iPLqi9edWlhZGQ8esoQhXMHcsIPO167pr62FE2px OLPA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 71si10751894pgd.94.2017.05.25.20.03.18; Thu, 25 May 2017 20:03:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1946746AbdEZDDP (ORCPT + 25 others); Thu, 25 May 2017 23:03:15 -0400 Received: from mail-pf0-f180.google.com ([209.85.192.180]:33346 "EHLO mail-pf0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1946700AbdEZDCm (ORCPT ); Thu, 25 May 2017 23:02:42 -0400 Received: by mail-pf0-f180.google.com with SMTP id e193so184461854pfh.0 for ; Thu, 25 May 2017 20:02:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=1A8I2nEZmPOIpJAiQX9fzwArdqhJSImxS2uyuAXpJsU=; b=XPwqqQPbcGNi+O6AnYl+J52zLpC7t6/K2KR5l80xnqg6r384CvjvtrtRpcRlnbvwwM ASfnw5fyye7r7gnW/Hx6liKxtoh6RCmR7PIyA3UDPiYYq+BzvohdlN0uSM21Y8Ueueac gjzauj2jhSYdj2NlL4oRqGVdAZv2m+8eEjcak= 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=1A8I2nEZmPOIpJAiQX9fzwArdqhJSImxS2uyuAXpJsU=; b=YSAHzsJWWcGYbMWsMFwRAT8oIdY1FoJ5jPsGGthTHtP8+HTB4s6eJCZUuxAvCkYP11 BD1h5iygvMsScIC9xCxYnnhSJCyrwNIO5p7UZ90ImBzJXoTNek82rSVCQDnGZIjoaxpl 5XNSeXyQuDJu5e1p6S/C0SXzlxNPeFmhGlW2at6Hq9hv4rEyeYKRp2iAPmA3cK0i4YQX n7V6BSi8ti5pBvpYFNGZuq4WPRr1cP1tKNZ5ON0s1zhoMe2cnXTZwPeEvI8VeCDgtinE dQ6s2xWenMwHnFi/uqTJ85KXISAqPcMPFUfUggTcu4L+lWAkLgPE1Azu3//ICsAZ+DXm eS6Q== X-Gm-Message-State: AODbwcAbWD2ZEZNdMBrYvQTT6ZU7d0u1GqOmvguyqpCWXibwBwP0YSAk gFOE8gNhqojSP+qU X-Received: by 10.99.54.141 with SMTP id d135mr31307857pga.85.1495767761865; Thu, 25 May 2017 20:02:41 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id 19sm14395266pfz.39.2017.05.25.20.02.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 May 2017 20:02:40 -0700 (PDT) From: AKASHI Takahiro To: mcgrof@kernel.org Cc: rusty@rustcorp.com.au, dhowells@redhat.com, ming.lei@canonical.com, seth.forshee@canonical.com, kyle@kernel.org, David.Woodhouse@intel.com, linux-kernel@vger.kernel.org, AKASHI Takahiro , "Luis R . Rodriguez" Subject: [PATCH 4/4] firmware: document signature verification for driver data Date: Fri, 26 May 2017 12:06:09 +0900 Message-Id: <20170526030609.1414-5-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.11.1 In-Reply-To: <20170526030609.1414-1-takahiro.akashi@linaro.org> References: <20170526030609.1414-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org add descriptions and usage about firmware signing in driver data APIs. Signed-off-by: AKASHI Takahiro Cc: Luis R. Rodriguez --- Documentation/driver-api/firmware/driver_data.rst | 6 ++ .../driver-api/firmware/fallback-mechanisms.rst | 5 +- Documentation/driver-api/firmware/signing.rst | 81 ++++++++++++++++++++++ 3 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 Documentation/driver-api/firmware/signing.rst -- 2.11.1 diff --git a/Documentation/driver-api/firmware/driver_data.rst b/Documentation/driver-api/firmware/driver_data.rst index be7c7ff99151..cdc47144a8b2 100644 --- a/Documentation/driver-api/firmware/driver_data.rst +++ b/Documentation/driver-api/firmware/driver_data.rst @@ -94,6 +94,12 @@ in these callbacks it frees it for you by default after callback handlers are issued. If you wish to keep the driver data around after your callbacks you must specify this through the driver data request parameter data structure. +Signature verification +====================== + + * `data signing`_ +.. _`data signing`: ./signing.rst + Driver data private internal functionality ========================================== diff --git a/Documentation/driver-api/firmware/fallback-mechanisms.rst b/Documentation/driver-api/firmware/fallback-mechanisms.rst index d19354794e67..e557d6630330 100644 --- a/Documentation/driver-api/firmware/fallback-mechanisms.rst +++ b/Documentation/driver-api/firmware/fallback-mechanisms.rst @@ -81,11 +81,12 @@ and a file upload firmware into: * /sys/$DEVPATH/loading * /sys/$DEVPATH/data + * /sys/$DEVPATH/sig_data To upload firmware you will echo 1 onto the loading file to indicate you are loading firmware. You then cat the firmware into the data file, -and you notify the kernel the firmware is ready by echo'ing 0 onto -the loading file. +optionally its signature file, and you notify the kernel the firmware is +ready by echo'ing 0 onto the loading file. The firmware device used to help load firmware using sysfs is only created if direct firmware loading fails and if the fallback mechanism is enabled for your diff --git a/Documentation/driver-api/firmware/signing.rst b/Documentation/driver-api/firmware/signing.rst new file mode 100644 index 000000000000..2dbee104700e --- /dev/null +++ b/Documentation/driver-api/firmware/signing.rst @@ -0,0 +1,81 @@ +================================ +Kernel firmware signing facility +================================ + +Overview +======== + +The kernel firmware signing facility enables to cryptographically sign +firmware files on a system using the same keys used for module signing. +Firmware files's signatures consist of PKCS#7 messages of the respective +firmware file. A firmware file named foo.bin, would have its respective +signature on the filesystem as foo.bin.p7s. When firmware signature +checking is enabled (FIRMWARE_SIG) and when one of the above APIs is used +against foo.bin, the file foo.bin.p7s will also be looked for. If +FIRMWARE_SIG_FORCE is enabled the foo.bin file will only be allowed to +be returned to callers of the above APIs if and only if the foo.bin.p7s +file is confirmed to be a valid signature of the foo.bin file. If +FIRMWARE_SIG_FORCE is not enabled and only FIRMWARE_SIG is enabled the +kernel will be permissive and enabled unsigned firmware files, or firmware +files with incorrect signatures. If FIRMWARE_SIG is not enabled the +signature file is ignored completely. + +Firmware signing increases security by making it harder to load a malicious +firmware into the kernel. The firmware signature checking is done by the +kernel so that it is not necessary to have trusted userspace bits. + +Configuring firmware signing +============================ + +The firmware signing facility is enabled by going to the section:: + + -> Device Drivers + -> Generic Driver Options + -> Userspace firmware loading support (FW_LOADER [=y]) + -> Firmware signature verification (FIRMWARE_SIG [=y]) + +If you want to not allow unsigned firmware to be loaded you should +enable:: + + -> Require all firmware to be validly signed (FIRMWARE_SIG_FORCE [=y]) + +under the same menu. + +Using signing keys +================== + +The same key types used for module signing can be used for firmware +signing. For details on that refer to `Kernel module signing`_. + +.. _`Kernel module signing`: /admin-guide/module-signing.rst + +You will need: + + A) A DER-encoded X.509 certificate containing the public key. + B) A DER-encoded PKCS#7 message containing the signatures, these are + the .p7s files. + C) A binary blob that is the detached data for the PKCS#7 message, this + is the firmware files + +A) is must be made available to the kernel. One way to do this is to provide a +DER-encoded in the source directory as .x509 when you build the kernel. + +Signing firmware files +====================== + +To generate a DER-encoded PKCS#7 signature message for each firmware file +you can use the following commands: + + scripts/sign-file -f sha256 \ + $PRIVATE_KEY_FILE_IN_PEM_FORM \ + $X509_CERT_FILE_IN_PEM_FORM \ + $FIRMWARE_BLOB_NAME + + or + + openssl smime -sign -in $FIRMWARE_BLOB_NAME \ + -outform DER \ + -inkey $PRIVATE_KEY_FILE_IN_PEM_FORM \ + -signer $X509_CERT_FILE_IN_PEM_FORM \ + -nocerts -md $DIGEST_ALGORITHM -binary > \ + $(FIRMWARE_BLOB_NAME).p7s