From patchwork Thu Aug 24 08:17:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110881 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315858qge; Thu, 24 Aug 2017 01:19:36 -0700 (PDT) X-Received: by 10.84.142.129 with SMTP id 1mr1708274plx.179.1503562776692; Thu, 24 Aug 2017 01:19:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562776; cv=none; d=google.com; s=arc-20160816; b=bKJwczftm7hYjlnNuBr2/DptZhkfY7ivQCgYldiGm2tsJjGcIbFjH+B74VTTwRsoMe gGNWGxLzs9j92xPE+T2OsXKP3fnU1AEQ0ItUEehzuLJLa0MdsHxI+Jhuf++KAmwxNurz 2pw9OVeNp3EByIUC+g3VDriYSA+VEaUbGgSZ68d7hcnK0ySxqYmPr7sAWNGYGvHdwihz +b27+mj234M5Dy50sGAYLh2MLG0fVM9uA2/nnxPxyEuKWwg1HJnC7bk5IL7prMw9D8kr 83FRZpdraYLzfH0fUZWqqUdk5wKDzyag6cF09WjeBBTk6nM19ShY741WOmy09gASPs0e 707w== 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=3Wc3VF3K3Rr5czr1jOJUnQoDSz7V0DBKvp0WD3BA0Zg=; b=bemJJtl3bhO1u7Jz4BN2Bl6Bn+vWR5t6WEjDnpWTDXjtfTJietQFSUxdMz9+JuD81o ZqpGzhQ/WdO50x76KFHulm7ryEApvAdyfE92PwI7lk+UQ45Zc/KKWe5lEsb3MqAbayM9 ZbsOZ56EUaNB4ZkWy+QwO1FoOHQlcGgN8mPF5oy0rguR0SoZqVbOUzII/4u5AP96xuDP 5sbe6Fi3Vw41inrin4Hf1PreDoXO23fYGMLtypCIndCazhuIavmyV0HFOKRJJ51pznK5 aQhBficZcWIn8zdvnxLxeZCGzae87FQrFHY3B8++1lJZCN96G/wLuUB/WtjmyF19gtmR PsnQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ZlHEvf+L; 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 g33si2561477plb.846.2017.08.24.01.19.36; Thu, 24 Aug 2017 01:19:36 -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 header.s=google header.b=ZlHEvf+L; 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 S1752254AbdHXITU (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:20 -0400 Received: from mail-pg0-f46.google.com ([74.125.83.46]:36598 "EHLO mail-pg0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751368AbdHXIRe (ORCPT ); Thu, 24 Aug 2017 04:17:34 -0400 Received: by mail-pg0-f46.google.com with SMTP id 83so13437767pgb.3 for ; Thu, 24 Aug 2017 01:17:33 -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=3Wc3VF3K3Rr5czr1jOJUnQoDSz7V0DBKvp0WD3BA0Zg=; b=ZlHEvf+LH7OtwKmQLVetbwRRQz+CLUaiYUN+U6e8g5s1Nw+NPH8/NT4WFYLhIXmAu2 V8r+f+FWyIs+vWWTV+tckHg/t60tj6CqcJetpooIPrDXgH+lF5lvLsCuYiAWV3N93x5X UyaTsssHdCIeXb78HWiyD7G9p6OGpmLKFfgT4= 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=3Wc3VF3K3Rr5czr1jOJUnQoDSz7V0DBKvp0WD3BA0Zg=; b=mEbj7VWgCE7QQTcoUTEzHHWD/afle4PbIfK7+y+TPSscN3VZCghr3oREz6tCSsGJ0i ZDHXMLmsK/Yu4Bws2tY0RjrACETNXxzfIxDzwlpLGO/QyvNh4749xUx6Vrq8CzJUrb5t 4pOLT6C25AxC4bv9F7Ld74vn68rUeUA4NEXW3nu67W5/TubpBLk1NORzsVIpG4yT0Uwh 0eGDqmpwScWzJv42vaBq0FF+CQjPqOc4t7P3yGYPD6am1cbVmKFJTnsySixLMbPdxT94 P+k2qSjRz7Eid7QUbQiq8NICCmq2dRW6q9uX4WPnRRwOJDrWM6reOMC1eKH3JxKZ8D/8 bs/w== X-Gm-Message-State: AHYfb5h8bRFA8fdK4CLlhN7F6cRxlXBXyW3bkqVtbKjztTrif8S64yCo qaXcWaO4O8fkOvhT X-Received: by 10.98.30.131 with SMTP id e125mr5753954pfe.244.1503562653436; Thu, 24 Aug 2017 01:17:33 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id x11sm7187363pfk.43.2017.08.24.01.17.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:17:33 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 01/14] MODSIGN: Export module signature definitions Date: Thu, 24 Aug 2017 17:17:58 +0900 Message-Id: <20170824081811.19299-2-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Thiago Jung Bauermann IMA will use the module_signature format for append signatures, so export the relevant definitions and factor out the code which verifies that the appended signature trailer is valid. Also, create a CONFIG_MODULE_SIG_FORMAT option so that IMA can select it and be able to use validate_module_signature without having to depend on CONFIG_MODULE_SIG. Signed-off-by: Thiago Jung Bauermann --- include/linux/module.h | 3 -- include/linux/module_signature.h | 47 +++++++++++++++++++++++++ init/Kconfig | 6 +++- kernel/Makefile | 2 +- kernel/module.c | 1 + kernel/module_signing.c | 74 +++++++++++++++++----------------------- 6 files changed, 85 insertions(+), 48 deletions(-) create mode 100644 include/linux/module_signature.h -- 2.14.1 diff --git a/include/linux/module.h b/include/linux/module.h index e7bdd549e527..672ad2016262 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -23,9 +23,6 @@ #include #include -/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ -#define MODULE_SIG_STRING "~Module signature appended~\n" - /* Not Yet Implemented */ #define MODULE_SUPPORTED_DEVICE(name) diff --git a/include/linux/module_signature.h b/include/linux/module_signature.h new file mode 100644 index 000000000000..e80728e5b86c --- /dev/null +++ b/include/linux/module_signature.h @@ -0,0 +1,47 @@ +/* Module signature handling. + * + * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * 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. + */ + +#ifndef _LINUX_MODULE_SIGNATURE_H +#define _LINUX_MODULE_SIGNATURE_H + +/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ +#define MODULE_SIG_STRING "~Module signature appended~\n" + +enum pkey_id_type { + PKEY_ID_PGP, /* OpenPGP generated key ID */ + PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ + PKEY_ID_PKCS7, /* Signature in PKCS#7 message */ +}; + +/* + * Module signature information block. + * + * The constituents of the signature section are, in order: + * + * - Signer's name + * - Key identifier + * - Signature data + * - Information block + */ +struct module_signature { + u8 algo; /* Public-key crypto algorithm [0] */ + u8 hash; /* Digest algorithm [0] */ + u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */ + u8 signer_len; /* Length of signer's name [0] */ + u8 key_id_len; /* Length of key identifier [0] */ + u8 __pad[3]; + __be32 sig_len; /* Length of signature data */ +}; + +int validate_module_sig(const struct module_signature *ms, size_t file_len); +int mod_verify_sig(const void *mod, unsigned long *_modlen); + +#endif /* _LINUX_MODULE_SIGNATURE_H */ diff --git a/init/Kconfig b/init/Kconfig index 8514b25db21c..c3ac1170b93a 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1734,7 +1734,7 @@ config MODULE_SRCVERSION_ALL config MODULE_SIG bool "Module signature verification" depends on MODULES - select SYSTEM_DATA_VERIFICATION + select MODULE_SIG_FORMAT help Check modules for valid signatures upon load: the signature is simply appended to the module. For more information see @@ -1749,6 +1749,10 @@ config MODULE_SIG debuginfo strip done by some packagers (such as rpmbuild) and inclusion into an initramfs that wants the module size reduced. +config MODULE_SIG_FORMAT + def_bool n + select SYSTEM_DATA_VERIFICATION + config MODULE_SIG_FORCE bool "Require modules to be validly signed" depends on MODULE_SIG diff --git a/kernel/Makefile b/kernel/Makefile index 4cb8e8b23c6e..d5f9748ab19f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -56,7 +56,7 @@ obj-y += up.o endif obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_MODULE_SIG) += module_signing.o +obj-$(CONFIG_MODULE_SIG_FORMAT) += module_signing.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_CRASH_CORE) += crash_core.o diff --git a/kernel/module.c b/kernel/module.c index 40f983cbea81..52921fccb51a 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/kernel/module_signing.c b/kernel/module_signing.c index 937c844bee4a..204c60d4cc9f 100644 --- a/kernel/module_signing.c +++ b/kernel/module_signing.c @@ -11,36 +11,38 @@ #include #include +#include #include #include #include #include "module-internal.h" -enum pkey_id_type { - PKEY_ID_PGP, /* OpenPGP generated key ID */ - PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ - PKEY_ID_PKCS7, /* Signature in PKCS#7 message */ -}; - -/* - * Module signature information block. - * - * The constituents of the signature section are, in order: +/** + * validate_module_sig - validate that the given signature is sane * - * - Signer's name - * - Key identifier - * - Signature data - * - Information block + * @ms: Signature to validate. + * @file_len: Size of the file to which @ms is appended. */ -struct module_signature { - u8 algo; /* Public-key crypto algorithm [0] */ - u8 hash; /* Digest algorithm [0] */ - u8 id_type; /* Key identifier type [PKEY_ID_PKCS7] */ - u8 signer_len; /* Length of signer's name [0] */ - u8 key_id_len; /* Length of key identifier [0] */ - u8 __pad[3]; - __be32 sig_len; /* Length of signature data */ -}; +int validate_module_sig(const struct module_signature *ms, size_t file_len) +{ + if (be32_to_cpu(ms->sig_len) >= file_len - sizeof(*ms)) + return -EBADMSG; + else if (ms->id_type != PKEY_ID_PKCS7) { + pr_err("Module is not signed with expected PKCS#7 message\n"); + return -ENOPKG; + } else if (ms->algo != 0 || + ms->hash != 0 || + ms->signer_len != 0 || + ms->key_id_len != 0 || + ms->__pad[0] != 0 || + ms->__pad[1] != 0 || + ms->__pad[2] != 0) { + pr_err("PKCS#7 signature info has unexpected non-zero params\n"); + return -EBADMSG; + } + + return 0; +} /* * Verify the signature on a module. @@ -49,6 +51,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) { struct module_signature ms; size_t modlen = *_modlen, sig_len; + int ret; pr_devel("==>%s(,%zu)\n", __func__, modlen); @@ -56,30 +59,15 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) return -EBADMSG; memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms)); - modlen -= sizeof(ms); + + ret = validate_module_sig(&ms, modlen); + if (ret) + return ret; sig_len = be32_to_cpu(ms.sig_len); - if (sig_len >= modlen) - return -EBADMSG; - modlen -= sig_len; + modlen -= sig_len + sizeof(ms); *_modlen = modlen; - if (ms.id_type != PKEY_ID_PKCS7) { - pr_err("Module is not signed with expected PKCS#7 message\n"); - return -ENOPKG; - } - - if (ms.algo != 0 || - ms.hash != 0 || - ms.signer_len != 0 || - ms.key_id_len != 0 || - ms.__pad[0] != 0 || - ms.__pad[1] != 0 || - ms.__pad[2] != 0) { - pr_err("PKCS#7 signature info has unexpected non-zero params\n"); - return -EBADMSG; - } - return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len, NULL, VERIFYING_MODULE_SIGNATURE, NULL, NULL); From patchwork Thu Aug 24 08:17:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110879 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315608qge; Thu, 24 Aug 2017 01:19:21 -0700 (PDT) X-Received: by 10.84.198.67 with SMTP id o61mr654676pld.289.1503562761815; Thu, 24 Aug 2017 01:19:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562761; cv=none; d=google.com; s=arc-20160816; b=1IgMYlCyzh9IlsyDj8cyoL6NYzCBG40tAQNXUD5nrSxgtRV4+Ud2+5mOGt8t5ZkONK fY59EGdJRfirHUL5EWiEXwAuTPp9VkMP/M5XRWp7DbEbwly1uMeST0waqzK+dUPnIEVQ 8LZhwGfn21fGHREVewuGD9Pkb9fZ+MksUwZjYW+jG9p+nIJzduI3v+8Pf8Bkr9woF+ct aKUuPJSmFnhVBFafLWjkehSdvAqBWAQNefb52jPTQNc9APNJMsDWmb9FwICuCSDeFfi8 6+IIzDaF3INduMotOGE9iqpE+VynOScnz1Jwh6H7SI7AO/yKH+9j8xu1ccC5aB1IZxuJ 3dZQ== 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=Rfo2+5LeGE+0yDd6Q+gfTnhnQP/fr7cddTXkW8oK8a8=; b=wlQbKyhp+WRp+QBacp/zanTI8ICtZsM7EEkz5gTes6AP1NpMEHhzk11TiZ4riczxmZ vJikf+lfDxAyMroh5DFUP0miwFnEpe1bIk6heexlLplxKipBtOz9AsOykMauFdsh2E2S NThFToucPeM0zev2wsqJcXHff5jB0aS1pl9c9m5jV6zA0gXyuPLqlcIELGDYxlWb6imG M1Pqc9sPCHxmivVGpiuLNG7rB3tlygsgimzG8xuqmELQ92UsuaH57qVlop2kRraaasQ2 pGI9YKhf1N8aMlBawsCfj67CxfatO3qL6Fxyh0iUtT7xKUkTpHeiYG9K/l3/HG4nnw6i iSjQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Zgfkae0n; 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 n9si2385009pge.35.2017.08.24.01.19.21; Thu, 24 Aug 2017 01:19:21 -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 header.s=google header.b=Zgfkae0n; 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 S1752202AbdHXITS (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:18 -0400 Received: from mail-pg0-f45.google.com ([74.125.83.45]:37506 "EHLO mail-pg0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751349AbdHXIRp (ORCPT ); Thu, 24 Aug 2017 04:17:45 -0400 Received: by mail-pg0-f45.google.com with SMTP id y129so13384911pgy.4 for ; Thu, 24 Aug 2017 01:17:45 -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=Rfo2+5LeGE+0yDd6Q+gfTnhnQP/fr7cddTXkW8oK8a8=; b=Zgfkae0nghKxloSmXTMQr99+bCRU0PbFl+ZoKANXNPSUf4ideh8dvSOmLZ+2b5YeJp 8JrFxclGoLRKZi4qbXv4uNxXVZOKWHT3NKLlrlpnHVcedobzjNCRjUHLL5Y9RjXvZ/k5 sk/MgHG3bEkeVrHxGXE8a3KqG19NjOPlL4YTQ= 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=Rfo2+5LeGE+0yDd6Q+gfTnhnQP/fr7cddTXkW8oK8a8=; b=VC21102m0FrL9zdvnff3C8h8Fms4UoqLadgZ5RzZyug/YgL1ufqESHGZNsYqZkCH0r 8+UMYNypobGvtceumvw3qmpdNKl2JenpN7JLiPqw5CCIEsLompq5J5pWnUklNlqctK97 ECEI5hG4DCq9l6U+9W/1Ut/EIVWxkJgWufrjOHQWiGQBG9AAnpPyABcs5HpHv5PMrqh8 wB1/IF1WTHt1DsYO903/vNLVbUpgkpwM/oOFwkwNXyOZ1Ym/epQh2vH51axDjGNXhmxD tjPU4LgjOtx6CYXodUjMLiWpSN2ZEP+t9rvDSpRvaGfkeqdUdwHuF2ANrBb+XkxrJEjC TNcQ== X-Gm-Message-State: AHYfb5iJTGEa9uWMWqDgkurJjDB/UIpezb0RvRRkCLcoJ5s8NvwJx1qA wKv51lBM4WVu/cOS X-Received: by 10.84.215.210 with SMTP id g18mr6162441plj.210.1503562665279; Thu, 24 Aug 2017 01:17:45 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id y23sm7262506pge.65.2017.08.24.01.17.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:17:44 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 02/14] include: pe.h: remove message[] from mz header definition Date: Thu, 24 Aug 2017 17:17:59 +0900 Message-Id: <20170824081811.19299-3-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org message[] field won't be part of the definition of mz header. This change is crucial for enabling kexec_file_load on arm64 because arm64's "Image" binary, as in PE format, doesn't have any data for it and accordingly the following check in pefile_parse_binary() will fail: chkaddr(cursor, mz->peaddr, sizeof(*pe)); Signed-off-by: AKASHI Takahiro Cc: David Howells Cc: Vivek Goyal Cc: Herbert Xu Cc: David S. Miller --- include/linux/pe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) -- 2.14.1 Reviewed-by: Ard Biesheuvel diff --git a/include/linux/pe.h b/include/linux/pe.h index 143ce75be5f0..3482b18a48b5 100644 --- a/include/linux/pe.h +++ b/include/linux/pe.h @@ -166,7 +166,7 @@ struct mz_hdr { uint16_t oem_info; /* oem specific */ uint16_t reserved1[10]; /* reserved */ uint32_t peaddr; /* address of pe header */ - char message[64]; /* message to print */ + char message[]; /* message to print */ }; struct mz_reloc { From patchwork Thu Aug 24 08:18:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110878 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315583qge; Thu, 24 Aug 2017 01:19:19 -0700 (PDT) X-Received: by 10.84.218.4 with SMTP id q4mr6009465pli.202.1503562759462; Thu, 24 Aug 2017 01:19:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562759; cv=none; d=google.com; s=arc-20160816; b=DwPw2Ugitl89enzkVFxJxm4e7vf5rNwbcV25QoxvDN+ljUqod1OgN7YTzHUAx648TH 8VyFSVTn6of1Cu9XnM8HfCz0zJeOuzvznr2PKDGffbnaZz+yBWm95E8YsI+R3QBqy7/H dZz7BX66tVTYtFrIpfDdNUF+2098bgXj/38abx6yzr7htHoR/vwZKgisL4rvjfGxwoIu iXvkh8H0rvTBTuxIJvZUxBfOJTXfPesQpkKnHFAgHUzTjH4RiEIJdCkxuG2OgiWPTTkR S+/ctG1xuSMPjtrzrzUGcQFF80s9gVJeJk4k2lY9lTnRatASyfCTyic/n+Bttd6pbo2m BDow== 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=AH9ill+BBKG9jKGLdFZoHHEIy0c5O4yy5/jZBaiKyeI=; b=QGsaUfNd9nvNe5X6z51Gn+6YoD5UEnoUbCULsnbOgLYf/fRTgBn4cGYUZp3UFsK3N3 mOvjbkzlF08uHkOvxTAfvKGXWTmEAP/MmMb90xh03UqiXDmaOzWyZRwtKk+fFK0ghJvW Kmvwq2MdfrXF2PaK4OeAyKGar1muhbFOSPErkd4nNSjfImjmgjEc6wg1FHiASprdND9N IPIievxDdNdNhdOTdYL96Do01Ac8IpNsqixBXf5DYQqD7nbAkwgNDtVqWqiJzeUbFcC+ PoJsyphuY9usn/VG50hUio1Q4Npc1XVQ/g2xh2/0sKO4DJogyrmTdfoP9Ukne5DLq2WM ww2A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Ra2dJ5lz; 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 w88si2467457pfa.519.2017.08.24.01.19.19; Thu, 24 Aug 2017 01:19:19 -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 header.s=google header.b=Ra2dJ5lz; 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 S1752131AbdHXITR (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:17 -0400 Received: from mail-pg0-f52.google.com ([74.125.83.52]:33353 "EHLO mail-pg0-f52.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751422AbdHXISE (ORCPT ); Thu, 24 Aug 2017 04:18:04 -0400 Received: by mail-pg0-f52.google.com with SMTP id t3so13495700pgt.0 for ; Thu, 24 Aug 2017 01:18:03 -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=AH9ill+BBKG9jKGLdFZoHHEIy0c5O4yy5/jZBaiKyeI=; b=Ra2dJ5lzsoWv1hJCKIpv/xU10f1PySx7KWE3IlW38A99YPXiOIPCdBvHLGVrSXd0xo lW3jhbMdjjCQe8H8lNj2rE1j5k8bbu0rLim81nUrAgnUqtkx+JdUJpZxclRts00wOSE4 QZlwwT2Hh4rWPTQXmGhew6PzrABNyw6lX78nc= 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=AH9ill+BBKG9jKGLdFZoHHEIy0c5O4yy5/jZBaiKyeI=; b=dh43EiY3wOJMDtq3FjJycattMC+xC4td+Dy+mGOFoJgueKqH1fpjmVDyXOvBkmMtVm RqDX7hgJSfr7HS/xzUGfyoxjvbNP+xqzY8HJjCkY8oGM3rbY680cgU6600Sx5m9jcNGx X8QeYgzKAuWCkz4ag2XuV7yN+vIPH9f2qyD4NTd5n1Cv4f4cQ3mjP8+Cbfw13JdBTp6c //tABovqVt7cXz2hWguq2T0i+04YZPLMTaPA4diODkh41AmyOIiVrxNlud89oggjVm8p xIBiqB3futgt8swplO7KSrAZHRj8YQTlUKe0wnV8EOEHgVTqBnq/yReDwQ0HAB04fmzQ jkkg== X-Gm-Message-State: AHYfb5iI6P5ktUlfAfZP5fifWkpULxLZb3WiXGhLscHnxFMDRPMsvUBe hobv4r6jnz7LI5Jl X-Received: by 10.84.167.2 with SMTP id c2mr6042381plb.371.1503562683677; Thu, 24 Aug 2017 01:18:03 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id o9sm6691952pfk.91.2017.08.24.01.18.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:03 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro , Linus Torvalds Subject: [PATCH 03/14] resource: add walk_system_ram_res_rev() Date: Thu, 24 Aug 2017 17:18:00 +0900 Message-Id: <20170824081811.19299-4-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-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 function, being a variant of walk_system_ram_res() introduced in commit 8c86e70acead ("resource: provide new functions to walk through resources"), walks through a list of all the resources of System RAM in reversed order, i.e., from higher to lower. It will be used in kexec_file implementation on arm64. Signed-off-by: AKASHI Takahiro Cc: Vivek Goyal Cc: Andrew Morton Cc: Linus Torvalds --- include/linux/ioport.h | 3 +++ kernel/resource.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) -- 2.14.1 diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 6230064d7f95..9a212266299f 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -271,6 +271,9 @@ extern int walk_system_ram_res(u64 start, u64 end, void *arg, int (*func)(u64, u64, void *)); extern int +walk_system_ram_res_rev(u64 start, u64 end, void *arg, + int (*func)(u64, u64, void *)); +extern int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, u64 end, void *arg, int (*func)(u64, u64, void *)); diff --git a/kernel/resource.c b/kernel/resource.c index 9b5f04404152..1d6d734c75ac 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -469,6 +470,53 @@ int walk_system_ram_res(u64 start, u64 end, void *arg, return ret; } +int walk_system_ram_res_rev(u64 start, u64 end, void *arg, + int (*func)(u64, u64, void *)) +{ + struct resource res, *rams; + u64 orig_end; + int count, i; + int ret = -1; + + count = 16; /* initial */ +again: + /* create a list */ + rams = vmalloc(sizeof(struct resource) * count); + if (!rams) + return ret; + + res.start = start; + res.end = end; + res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; + orig_end = res.end; + i = 0; + while ((res.start < res.end) && + (!find_next_iomem_res(&res, IORES_DESC_NONE, true))) { + if (i >= count) { + /* unlikely but */ + vfree(rams); + count += 16; + goto again; + } + + rams[i].start = res.start; + rams[i++].end = res.end; + + res.start = res.end + 1; + res.end = orig_end; + } + + /* go reverse */ + for (i--; i >= 0; i--) { + ret = (*func)(rams[i].start, rams[i].end, arg); + if (ret) + break; + } + + vfree(rams); + return ret; +} + #if !defined(CONFIG_ARCH_HAS_WALK_MEMORY) /* From patchwork Thu Aug 24 08:18:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110884 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5316939qge; Thu, 24 Aug 2017 01:20:42 -0700 (PDT) X-Received: by 10.84.213.16 with SMTP id f16mr6325978pli.158.1503562841925; Thu, 24 Aug 2017 01:20:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562841; cv=none; d=google.com; s=arc-20160816; b=hIz7eNWQd1AVLfc8/VBG8ob/XVwp5k4lJWleX/K/SN3vcffkOKFH0J6RgCJ+P0OhcC z1PP3DOx4v4HA1w/dTOffh3EVvGCCBH6E88BcXDygIxqPft4cz31qdj7oASF2T8SQe1i evxsoS8V0UjKOLtmgR09pMoGLV018vhqtPhPEnHebczlNRsYIDxL7t4WcOfUdobjNqJF D6lmxFPOyflBq/9s4XOw7PlcEd/5SZT/BHXlMLaaeEGm6t1TOucDBvBNj37mQSK28Cv4 Uv0SoBnfqfiMtKfkPFOB6debs4LxpTrWI8RUcc4ttM/a2mqyAKbtre/Z4VdTBz0qXgbX K0lA== 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=CGdY2z6Urvyvq28qeFx8g/OjwXtcCLFz3K0E1JkRtNo=; b=TOFkvS6/l5Ds3WqJY6a+GrfMIZNASJKIxC1aUpeW8+kEkwtimZT2JWxM/ayjseWiJ7 UlYmNwY9tc1ZkR7cLQPrRrlT1jJyNsd67Q2G2Hs8xHgI1ibbwL1GRRPCDxmR7j1evyPY Y1+/26DOo3SKCgiMCpMQki9Zxb/Jsi8ZXmQo5OwErd9GYsy73CdcAMIGoXc5gir8D+Va REpCJwdngk/k19z8uirENwHzquWhrcmcGuQDRFLEIRMJFOtuquxA9Lin9fQ2sz3LjYqj 15Tf3zkRNtaN1jA2TYOHRA5wI6QrfqVnN0RY4wlFCCpP2+RtsdvHx5LP6x54Vygs9rph SBTg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=OzR6nNiS; 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 91si2576914ply.126.2017.08.24.01.20.41; Thu, 24 Aug 2017 01:20:41 -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 header.s=google header.b=OzR6nNiS; 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 S1752031AbdHXITO (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:14 -0400 Received: from mail-pg0-f42.google.com ([74.125.83.42]:37679 "EHLO mail-pg0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751372AbdHXISS (ORCPT ); Thu, 24 Aug 2017 04:18:18 -0400 Received: by mail-pg0-f42.google.com with SMTP id y129so13391959pgy.4 for ; Thu, 24 Aug 2017 01:18:18 -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=CGdY2z6Urvyvq28qeFx8g/OjwXtcCLFz3K0E1JkRtNo=; b=OzR6nNiSK+RSVyK9F9v6CJ4y9W1Z7BuMCzTPBW1byib5py1bhBcz4FT/COuYJQdpZp i9zGh+qa+3ZE42G396HSLrrwOzzWlfV6rmz3NoPtFJeA+E9QDaV5HpySCqcxdnyjsjoP XC8P3WBTMPM75AV9KXIjHGa4sLg6MSUWBTezA= 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=CGdY2z6Urvyvq28qeFx8g/OjwXtcCLFz3K0E1JkRtNo=; b=Zd55I/wpwgnrw1LTmbQb9cfgqH1da6CD8MckUxQx+jX0cjBISTuu3tigXJKzNfGVAc gsE15+KHc7xwzn8iGQoMt78SMkYZoQCI8RfnyVqbfB7UosJg42a+u2H3YcshPBNpMmiq x6NNe9aCm6zRBbnXTKNFjBp4tBCrnllEDv2eurbo9CtPLBJL/2bkz/fx3PdIsPcl2BJc 1NHE17eXEwndp8aNPJPY8WaupbM4Hii0IplMGYlmikGFqkxvWFs6AkfoHOT9Jn9+GV6z jrpXOmLuLjoG/N0qcISt/9i1i3uKuMyUplkzHubbth0LD8ShocW6hOMi2Yabjb1Skqod ui+Q== X-Gm-Message-State: AHYfb5hOrqHyiSdJVLcaeX9S92gPvNyrNL5LJ766e3y/Bk6WpJRvNOSA mzz/HUPZlf3eCzdesBX73w== X-Received: by 10.84.132.73 with SMTP id 67mr5899035ple.53.1503562697956; Thu, 24 Aug 2017 01:18:17 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id u4sm6231478pgn.74.2017.08.24.01.18.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:17 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 04/14] kexec_file: factor out vmlinux (elf) parser from powerpc Date: Thu, 24 Aug 2017 17:18:01 +0900 Message-Id: <20170824081811.19299-5-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org build_elf_exec_info() can also be useful for other architectures, including arm64. So let it factored out. Signed-off-by: AKASHI Takahiro Cc: Michael Ellerman Cc: Thiago Jung Bauermann Cc: Dave Young Cc: Vivek Goyal Cc: Baoquan He --- arch/Kconfig | 3 + arch/powerpc/Kconfig | 1 + arch/powerpc/kernel/kexec_elf_64.c | 464 ------------------------------------- include/linux/elf.h | 62 +++++ include/linux/kexec.h | 19 ++ kernel/Makefile | 1 + kernel/kexec_file_elf.c | 454 ++++++++++++++++++++++++++++++++++++ 7 files changed, 540 insertions(+), 464 deletions(-) create mode 100644 kernel/kexec_file_elf.c -- 2.14.1 diff --git a/arch/Kconfig b/arch/Kconfig index 21d0089117fe..e940d16412f4 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -9,6 +9,9 @@ config KEXEC_CORE select CRASH_CORE bool +config KEXEC_FILE_ELF + bool + config HAVE_IMA_KEXEC bool diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 36f858c37ca7..f73921bbe29a 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -529,6 +529,7 @@ config KEXEC config KEXEC_FILE bool "kexec file based system call" select KEXEC_CORE + select KEXEC_FILE_ELF select HAVE_IMA_KEXEC select BUILD_BIN2C depends on PPC64 diff --git a/arch/powerpc/kernel/kexec_elf_64.c b/arch/powerpc/kernel/kexec_elf_64.c index 9a42309b091a..a0c92bd14259 100644 --- a/arch/powerpc/kernel/kexec_elf_64.c +++ b/arch/powerpc/kernel/kexec_elf_64.c @@ -26,475 +26,11 @@ #include #include #include -#include #include #include -#include #define PURGATORY_STACK_SIZE (16 * 1024) -#define elf_addr_to_cpu elf64_to_cpu - -#ifndef Elf_Rel -#define Elf_Rel Elf64_Rel -#endif /* Elf_Rel */ - -struct elf_info { - /* - * Where the ELF binary contents are kept. - * Memory managed by the user of the struct. - */ - const char *buffer; - - const struct elfhdr *ehdr; - const struct elf_phdr *proghdrs; - struct elf_shdr *sechdrs; -}; - -static inline bool elf_is_elf_file(const struct elfhdr *ehdr) -{ - return memcmp(ehdr->e_ident, ELFMAG, SELFMAG) == 0; -} - -static uint64_t elf64_to_cpu(const struct elfhdr *ehdr, uint64_t value) -{ - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) - value = le64_to_cpu(value); - else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - value = be64_to_cpu(value); - - return value; -} - -static uint16_t elf16_to_cpu(const struct elfhdr *ehdr, uint16_t value) -{ - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) - value = le16_to_cpu(value); - else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - value = be16_to_cpu(value); - - return value; -} - -static uint32_t elf32_to_cpu(const struct elfhdr *ehdr, uint32_t value) -{ - if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) - value = le32_to_cpu(value); - else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) - value = be32_to_cpu(value); - - return value; -} - -/** - * elf_is_ehdr_sane - check that it is safe to use the ELF header - * @buf_len: size of the buffer in which the ELF file is loaded. - */ -static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len) -{ - if (ehdr->e_phnum > 0 && ehdr->e_phentsize != sizeof(struct elf_phdr)) { - pr_debug("Bad program header size.\n"); - return false; - } else if (ehdr->e_shnum > 0 && - ehdr->e_shentsize != sizeof(struct elf_shdr)) { - pr_debug("Bad section header size.\n"); - return false; - } else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT || - ehdr->e_version != EV_CURRENT) { - pr_debug("Unknown ELF version.\n"); - return false; - } - - if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) { - size_t phdr_size; - - /* - * e_phnum is at most 65535 so calculating the size of the - * program header cannot overflow. - */ - phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum; - - /* Sanity check the program header table location. */ - if (ehdr->e_phoff + phdr_size < ehdr->e_phoff) { - pr_debug("Program headers at invalid location.\n"); - return false; - } else if (ehdr->e_phoff + phdr_size > buf_len) { - pr_debug("Program headers truncated.\n"); - return false; - } - } - - if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) { - size_t shdr_size; - - /* - * e_shnum is at most 65536 so calculating - * the size of the section header cannot overflow. - */ - shdr_size = sizeof(struct elf_shdr) * ehdr->e_shnum; - - /* Sanity check the section header table location. */ - if (ehdr->e_shoff + shdr_size < ehdr->e_shoff) { - pr_debug("Section headers at invalid location.\n"); - return false; - } else if (ehdr->e_shoff + shdr_size > buf_len) { - pr_debug("Section headers truncated.\n"); - return false; - } - } - - return true; -} - -static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr) -{ - struct elfhdr *buf_ehdr; - - if (len < sizeof(*buf_ehdr)) { - pr_debug("Buffer is too small to hold ELF header.\n"); - return -ENOEXEC; - } - - memset(ehdr, 0, sizeof(*ehdr)); - memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident)); - if (!elf_is_elf_file(ehdr)) { - pr_debug("No ELF header magic.\n"); - return -ENOEXEC; - } - - if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) { - pr_debug("Not a supported ELF class.\n"); - return -ENOEXEC; - } else if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB && - ehdr->e_ident[EI_DATA] != ELFDATA2MSB) { - pr_debug("Not a supported ELF data format.\n"); - return -ENOEXEC; - } - - buf_ehdr = (struct elfhdr *) buf; - if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) { - pr_debug("Bad ELF header size.\n"); - return -ENOEXEC; - } - - ehdr->e_type = elf16_to_cpu(ehdr, buf_ehdr->e_type); - ehdr->e_machine = elf16_to_cpu(ehdr, buf_ehdr->e_machine); - ehdr->e_version = elf32_to_cpu(ehdr, buf_ehdr->e_version); - ehdr->e_entry = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry); - ehdr->e_phoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff); - ehdr->e_shoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff); - ehdr->e_flags = elf32_to_cpu(ehdr, buf_ehdr->e_flags); - ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize); - ehdr->e_phnum = elf16_to_cpu(ehdr, buf_ehdr->e_phnum); - ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize); - ehdr->e_shnum = elf16_to_cpu(ehdr, buf_ehdr->e_shnum); - ehdr->e_shstrndx = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx); - - return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC; -} - -/** - * elf_is_phdr_sane - check that it is safe to use the program header - * @buf_len: size of the buffer in which the ELF file is loaded. - */ -static bool elf_is_phdr_sane(const struct elf_phdr *phdr, size_t buf_len) -{ - - if (phdr->p_offset + phdr->p_filesz < phdr->p_offset) { - pr_debug("ELF segment location wraps around.\n"); - return false; - } else if (phdr->p_offset + phdr->p_filesz > buf_len) { - pr_debug("ELF segment not in file.\n"); - return false; - } else if (phdr->p_paddr + phdr->p_memsz < phdr->p_paddr) { - pr_debug("ELF segment address wraps around.\n"); - return false; - } - - return true; -} - -static int elf_read_phdr(const char *buf, size_t len, struct elf_info *elf_info, - int idx) -{ - /* Override the const in proghdrs, we are the ones doing the loading. */ - struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx]; - const char *pbuf; - struct elf_phdr *buf_phdr; - - pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr)); - buf_phdr = (struct elf_phdr *) pbuf; - - phdr->p_type = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type); - phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset); - phdr->p_paddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr); - phdr->p_vaddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr); - phdr->p_flags = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags); - - /* - * The following fields have a type equivalent to Elf_Addr - * both in 32 bit and 64 bit ELF. - */ - phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz); - phdr->p_memsz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz); - phdr->p_align = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align); - - return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC; -} - -/** - * elf_read_phdrs - read the program headers from the buffer - * - * This function assumes that the program header table was checked for sanity. - * Use elf_is_ehdr_sane() if it wasn't. - */ -static int elf_read_phdrs(const char *buf, size_t len, - struct elf_info *elf_info) -{ - size_t phdr_size, i; - const struct elfhdr *ehdr = elf_info->ehdr; - - /* - * e_phnum is at most 65535 so calculating the size of the - * program header cannot overflow. - */ - phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum; - - elf_info->proghdrs = kzalloc(phdr_size, GFP_KERNEL); - if (!elf_info->proghdrs) - return -ENOMEM; - - for (i = 0; i < ehdr->e_phnum; i++) { - int ret; - - ret = elf_read_phdr(buf, len, elf_info, i); - if (ret) { - kfree(elf_info->proghdrs); - elf_info->proghdrs = NULL; - return ret; - } - } - - return 0; -} - -/** - * elf_is_shdr_sane - check that it is safe to use the section header - * @buf_len: size of the buffer in which the ELF file is loaded. - */ -static bool elf_is_shdr_sane(const struct elf_shdr *shdr, size_t buf_len) -{ - bool size_ok; - - /* SHT_NULL headers have undefined values, so we can't check them. */ - if (shdr->sh_type == SHT_NULL) - return true; - - /* Now verify sh_entsize */ - switch (shdr->sh_type) { - case SHT_SYMTAB: - size_ok = shdr->sh_entsize == sizeof(Elf_Sym); - break; - case SHT_RELA: - size_ok = shdr->sh_entsize == sizeof(Elf_Rela); - break; - case SHT_DYNAMIC: - size_ok = shdr->sh_entsize == sizeof(Elf_Dyn); - break; - case SHT_REL: - size_ok = shdr->sh_entsize == sizeof(Elf_Rel); - break; - case SHT_NOTE: - case SHT_PROGBITS: - case SHT_HASH: - case SHT_NOBITS: - default: - /* - * This is a section whose entsize requirements - * I don't care about. If I don't know about - * the section I can't care about it's entsize - * requirements. - */ - size_ok = true; - break; - } - - if (!size_ok) { - pr_debug("ELF section with wrong entry size.\n"); - return false; - } else if (shdr->sh_addr + shdr->sh_size < shdr->sh_addr) { - pr_debug("ELF section address wraps around.\n"); - return false; - } - - if (shdr->sh_type != SHT_NOBITS) { - if (shdr->sh_offset + shdr->sh_size < shdr->sh_offset) { - pr_debug("ELF section location wraps around.\n"); - return false; - } else if (shdr->sh_offset + shdr->sh_size > buf_len) { - pr_debug("ELF section not in file.\n"); - return false; - } - } - - return true; -} - -static int elf_read_shdr(const char *buf, size_t len, struct elf_info *elf_info, - int idx) -{ - struct elf_shdr *shdr = &elf_info->sechdrs[idx]; - const struct elfhdr *ehdr = elf_info->ehdr; - const char *sbuf; - struct elf_shdr *buf_shdr; - - sbuf = buf + ehdr->e_shoff + idx * sizeof(*buf_shdr); - buf_shdr = (struct elf_shdr *) sbuf; - - shdr->sh_name = elf32_to_cpu(ehdr, buf_shdr->sh_name); - shdr->sh_type = elf32_to_cpu(ehdr, buf_shdr->sh_type); - shdr->sh_addr = elf_addr_to_cpu(ehdr, buf_shdr->sh_addr); - shdr->sh_offset = elf_addr_to_cpu(ehdr, buf_shdr->sh_offset); - shdr->sh_link = elf32_to_cpu(ehdr, buf_shdr->sh_link); - shdr->sh_info = elf32_to_cpu(ehdr, buf_shdr->sh_info); - - /* - * The following fields have a type equivalent to Elf_Addr - * both in 32 bit and 64 bit ELF. - */ - shdr->sh_flags = elf_addr_to_cpu(ehdr, buf_shdr->sh_flags); - shdr->sh_size = elf_addr_to_cpu(ehdr, buf_shdr->sh_size); - shdr->sh_addralign = elf_addr_to_cpu(ehdr, buf_shdr->sh_addralign); - shdr->sh_entsize = elf_addr_to_cpu(ehdr, buf_shdr->sh_entsize); - - return elf_is_shdr_sane(shdr, len) ? 0 : -ENOEXEC; -} - -/** - * elf_read_shdrs - read the section headers from the buffer - * - * This function assumes that the section header table was checked for sanity. - * Use elf_is_ehdr_sane() if it wasn't. - */ -static int elf_read_shdrs(const char *buf, size_t len, - struct elf_info *elf_info) -{ - size_t shdr_size, i; - - /* - * e_shnum is at most 65536 so calculating - * the size of the section header cannot overflow. - */ - shdr_size = sizeof(struct elf_shdr) * elf_info->ehdr->e_shnum; - - elf_info->sechdrs = kzalloc(shdr_size, GFP_KERNEL); - if (!elf_info->sechdrs) - return -ENOMEM; - - for (i = 0; i < elf_info->ehdr->e_shnum; i++) { - int ret; - - ret = elf_read_shdr(buf, len, elf_info, i); - if (ret) { - kfree(elf_info->sechdrs); - elf_info->sechdrs = NULL; - return ret; - } - } - - return 0; -} - -/** - * elf_read_from_buffer - read ELF file and sets up ELF header and ELF info - * @buf: Buffer to read ELF file from. - * @len: Size of @buf. - * @ehdr: Pointer to existing struct which will be populated. - * @elf_info: Pointer to existing struct which will be populated. - * - * This function allows reading ELF files with different byte order than - * the kernel, byte-swapping the fields as needed. - * - * Return: - * On success returns 0, and the caller should call elf_free_info(elf_info) to - * free the memory allocated for the section and program headers. - */ -int elf_read_from_buffer(const char *buf, size_t len, struct elfhdr *ehdr, - struct elf_info *elf_info) -{ - int ret; - - ret = elf_read_ehdr(buf, len, ehdr); - if (ret) - return ret; - - elf_info->buffer = buf; - elf_info->ehdr = ehdr; - if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) { - ret = elf_read_phdrs(buf, len, elf_info); - if (ret) - return ret; - } - if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) { - ret = elf_read_shdrs(buf, len, elf_info); - if (ret) { - kfree(elf_info->proghdrs); - return ret; - } - } - - return 0; -} - -/** - * elf_free_info - free memory allocated by elf_read_from_buffer - */ -void elf_free_info(struct elf_info *elf_info) -{ - kfree(elf_info->proghdrs); - kfree(elf_info->sechdrs); - memset(elf_info, 0, sizeof(*elf_info)); -} -/** - * build_elf_exec_info - read ELF executable and check that we can use it - */ -static int build_elf_exec_info(const char *buf, size_t len, struct elfhdr *ehdr, - struct elf_info *elf_info) -{ - int i; - int ret; - - ret = elf_read_from_buffer(buf, len, ehdr, elf_info); - if (ret) - return ret; - - /* Big endian vmlinux has type ET_DYN. */ - if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { - pr_err("Not an ELF executable.\n"); - goto error; - } else if (!elf_info->proghdrs) { - pr_err("No ELF program header.\n"); - goto error; - } - - for (i = 0; i < ehdr->e_phnum; i++) { - /* - * Kexec does not support loading interpreters. - * In addition this check keeps us from attempting - * to kexec ordinay executables. - */ - if (elf_info->proghdrs[i].p_type == PT_INTERP) { - pr_err("Requires an ELF interpreter.\n"); - goto error; - } - } - - return 0; -error: - elf_free_info(elf_info); - return -ENOEXEC; -} - static int elf64_probe(const char *buf, unsigned long len) { struct elfhdr ehdr; diff --git a/include/linux/elf.h b/include/linux/elf.h index ba069e8f4f78..e758bb4365c1 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h @@ -1,6 +1,8 @@ #ifndef _LINUX_ELF_H #define _LINUX_ELF_H +#include +#include #include #include @@ -55,4 +57,64 @@ static inline int elf_coredump_extra_notes_write(struct coredump_params *cprm) { extern int elf_coredump_extra_notes_size(void); extern int elf_coredump_extra_notes_write(struct coredump_params *cprm); #endif + +static inline u16 elf16_to_cpu(const struct elfhdr *ehdr, u16 value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le16_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be16_to_cpu(value); + + return value; +} + +static inline u16 cpu_to_elf16(const struct elfhdr *ehdr, u16 value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = cpu_to_le16(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = cpu_to_be16(value); + + return value; +} + +static inline u32 elf32_to_cpu(const struct elfhdr *ehdr, u32 value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le32_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be32_to_cpu(value); + + return value; +} + +static inline u32 cpu_to_elf32(const struct elfhdr *ehdr, u32 value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = cpu_to_le32(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = cpu_to_be32(value); + + return value; +} + +static inline u64 elf64_to_cpu(const struct elfhdr *ehdr, u64 value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = le64_to_cpu(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = be64_to_cpu(value); + + return value; +} + +static inline u64 cpu_to_elf64(const struct elfhdr *ehdr, u64 value) +{ + if (ehdr->e_ident[EI_DATA] == ELFDATA2LSB) + value = cpu_to_le64(value); + else if (ehdr->e_ident[EI_DATA] == ELFDATA2MSB) + value = cpu_to_be64(value); + + return value; +} #endif /* _LINUX_ELF_H */ diff --git a/include/linux/kexec.h b/include/linux/kexec.h index dd056fab9e35..db98e3459e90 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -22,6 +22,7 @@ #ifdef CONFIG_KEXEC_CORE #include #include +#include #include #include #include @@ -162,6 +163,24 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *)); extern int kexec_add_buffer(struct kexec_buf *kbuf); int kexec_locate_mem_hole(struct kexec_buf *kbuf); + +#ifdef CONFIG_KEXEC_FILE_ELF +struct elf_info { + /* + * Where the ELF binary contents are kept. + * Memory managed by the user of the struct. + */ + const char *buffer; + + const struct elfhdr *ehdr; + const struct elf_phdr *proghdrs; + struct elf_shdr *sechdrs; +}; + +extern void elf_free_info(struct elf_info *elf_info); +extern int build_elf_exec_info(const char *buf, size_t len, struct elfhdr *ehdr, + struct elf_info *elf_info); +#endif /* CONFIG_KEXEC_FILE_ELF */ #endif /* CONFIG_KEXEC_FILE */ struct kimage { diff --git a/kernel/Makefile b/kernel/Makefile index d5f9748ab19f..d07492eb3804 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_CRASH_CORE) += crash_core.o obj-$(CONFIG_KEXEC_CORE) += kexec_core.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_KEXEC_FILE) += kexec_file.o +obj-$(CONFIG_KEXEC_FILE_ELF) += kexec_file_elf.o obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_CGROUPS) += cgroup/ diff --git a/kernel/kexec_file_elf.c b/kernel/kexec_file_elf.c new file mode 100644 index 000000000000..4fc049e9731b --- /dev/null +++ b/kernel/kexec_file_elf.c @@ -0,0 +1,454 @@ +/* + * Load ELF vmlinux file for the kexec_file_load syscall. + * + * Copyright (C) 2004 Adam Litke (agl@us.ibm.com) + * Copyright (C) 2004 IBM Corp. + * Copyright (C) 2005 R Sharada (sharada@in.ibm.com) + * Copyright (C) 2006 Mohan Kumar M (mohan@in.ibm.com) + * Copyright (C) 2016 IBM Corporation + * + * Based on kexec-tools' kexec-elf-exec.c and kexec-elf-ppc64.c. + * Heavily modified for the kernel by + * Thiago Jung Bauermann . + * Factored out for general use by + * AKASHI Takahiro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "kexec_elf_elf: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#if ELF_CLASS == ELFCLASS32 +#define elf_addr_to_cpu elf32_to_cpu +#else +#define elf_addr_to_cpu elf64_to_cpu +#endif + +/** + * elf_is_ehdr_sane - check that it is safe to use the ELF header + * @buf_len: size of the buffer in which the ELF file is loaded. + */ +static bool elf_is_ehdr_sane(const struct elfhdr *ehdr, size_t buf_len) +{ + if (ehdr->e_phnum > 0 && ehdr->e_phentsize != sizeof(struct elf_phdr)) { + pr_debug("Bad program header size.\n"); + return false; + } else if (ehdr->e_shnum > 0 && + ehdr->e_shentsize != sizeof(struct elf_shdr)) { + pr_debug("Bad section header size.\n"); + return false; + } else if (ehdr->e_ident[EI_VERSION] != EV_CURRENT || + ehdr->e_version != EV_CURRENT) { + pr_debug("Unknown ELF version.\n"); + return false; + } + + if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) { + size_t phdr_size; + + /* + * e_phnum is at most 65535 so calculating the size of the + * program header cannot overflow. + */ + phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum; + + /* Sanity check the program header table location. */ + if (ehdr->e_phoff + phdr_size < ehdr->e_phoff) { + pr_debug("Program headers at invalid location.\n"); + return false; + } else if (ehdr->e_phoff + phdr_size > buf_len) { + pr_debug("Program headers truncated.\n"); + return false; + } + } + + if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) { + size_t shdr_size; + + /* + * e_shnum is at most 65536 so calculating + * the size of the section header cannot overflow. + */ + shdr_size = sizeof(struct elf_shdr) * ehdr->e_shnum; + + /* Sanity check the section header table location. */ + if (ehdr->e_shoff + shdr_size < ehdr->e_shoff) { + pr_debug("Section headers at invalid location.\n"); + return false; + } else if (ehdr->e_shoff + shdr_size > buf_len) { + pr_debug("Section headers truncated.\n"); + return false; + } + } + + return true; +} + +static int elf_read_ehdr(const char *buf, size_t len, struct elfhdr *ehdr) +{ + struct elfhdr *buf_ehdr; + + if (len < sizeof(*buf_ehdr)) { + pr_debug("Buffer is too small to hold ELF header.\n"); + return -ENOEXEC; + } + + memset(ehdr, 0, sizeof(*ehdr)); + memcpy(ehdr->e_ident, buf, sizeof(ehdr->e_ident)); + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { + pr_debug("No ELF header magic.\n"); + return -ENOEXEC; + } + + if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) { + pr_debug("Not a supported ELF class.\n"); + return -ENOEXEC; + } else if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB && + ehdr->e_ident[EI_DATA] != ELFDATA2MSB) { + pr_debug("Not a supported ELF data format.\n"); + return -ENOEXEC; + } + + buf_ehdr = (struct elfhdr *) buf; + if (elf16_to_cpu(ehdr, buf_ehdr->e_ehsize) != sizeof(*buf_ehdr)) { + pr_debug("Bad ELF header size.\n"); + return -ENOEXEC; + } + + ehdr->e_type = elf16_to_cpu(ehdr, buf_ehdr->e_type); + ehdr->e_machine = elf16_to_cpu(ehdr, buf_ehdr->e_machine); + ehdr->e_version = elf32_to_cpu(ehdr, buf_ehdr->e_version); + ehdr->e_entry = elf_addr_to_cpu(ehdr, buf_ehdr->e_entry); + ehdr->e_phoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_phoff); + ehdr->e_shoff = elf_addr_to_cpu(ehdr, buf_ehdr->e_shoff); + ehdr->e_flags = elf32_to_cpu(ehdr, buf_ehdr->e_flags); + ehdr->e_phentsize = elf16_to_cpu(ehdr, buf_ehdr->e_phentsize); + ehdr->e_phnum = elf16_to_cpu(ehdr, buf_ehdr->e_phnum); + ehdr->e_shentsize = elf16_to_cpu(ehdr, buf_ehdr->e_shentsize); + ehdr->e_shnum = elf16_to_cpu(ehdr, buf_ehdr->e_shnum); + ehdr->e_shstrndx = elf16_to_cpu(ehdr, buf_ehdr->e_shstrndx); + + return elf_is_ehdr_sane(ehdr, len) ? 0 : -ENOEXEC; +} + +/** + * elf_is_phdr_sane - check that it is safe to use the program header + * @buf_len: size of the buffer in which the ELF file is loaded. + */ +static bool elf_is_phdr_sane(const struct elf_phdr *phdr, size_t buf_len) +{ + + if (phdr->p_offset + phdr->p_filesz < phdr->p_offset) { + pr_debug("ELF segment location wraps around.\n"); + return false; + } else if (phdr->p_offset + phdr->p_filesz > buf_len) { + pr_debug("ELF segment not in file.\n"); + return false; + } else if (phdr->p_paddr + phdr->p_memsz < phdr->p_paddr) { + pr_debug("ELF segment address wraps around.\n"); + return false; + } + + return true; +} + +static int elf_read_phdr(const char *buf, size_t len, struct elf_info *elf_info, + int idx) +{ + /* Override the const in proghdrs, we are the ones doing the loading. */ + struct elf_phdr *phdr = (struct elf_phdr *) &elf_info->proghdrs[idx]; + const char *pbuf; + struct elf_phdr *buf_phdr; + + pbuf = buf + elf_info->ehdr->e_phoff + (idx * sizeof(*buf_phdr)); + buf_phdr = (struct elf_phdr *) pbuf; + + phdr->p_type = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_type); + phdr->p_offset = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_offset); + phdr->p_paddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_paddr); + phdr->p_vaddr = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_vaddr); + phdr->p_flags = elf32_to_cpu(elf_info->ehdr, buf_phdr->p_flags); + + /* + * The following fields have a type equivalent to Elf_Addr + * both in 32 bit and 64 bit ELF. + */ + phdr->p_filesz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_filesz); + phdr->p_memsz = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_memsz); + phdr->p_align = elf_addr_to_cpu(elf_info->ehdr, buf_phdr->p_align); + + return elf_is_phdr_sane(phdr, len) ? 0 : -ENOEXEC; +} + +/** + * elf_read_phdrs - read the program headers from the buffer + * + * This function assumes that the program header table was checked for sanity. + * Use elf_is_ehdr_sane() if it wasn't. + */ +static int elf_read_phdrs(const char *buf, size_t len, + struct elf_info *elf_info) +{ + size_t phdr_size, i; + const struct elfhdr *ehdr = elf_info->ehdr; + + /* + * e_phnum is at most 65535 so calculating the size of the + * program header cannot overflow. + */ + phdr_size = sizeof(struct elf_phdr) * ehdr->e_phnum; + + elf_info->proghdrs = kzalloc(phdr_size, GFP_KERNEL); + if (!elf_info->proghdrs) + return -ENOMEM; + + for (i = 0; i < ehdr->e_phnum; i++) { + int ret; + + ret = elf_read_phdr(buf, len, elf_info, i); + if (ret) { + kfree(elf_info->proghdrs); + elf_info->proghdrs = NULL; + return ret; + } + } + + return 0; +} + +/** + * elf_is_shdr_sane - check that it is safe to use the section header + * @buf_len: size of the buffer in which the ELF file is loaded. + */ +static bool elf_is_shdr_sane(const struct elf_shdr *shdr, size_t buf_len) +{ + bool size_ok; + + /* SHT_NULL headers have undefined values, so we can't check them. */ + if (shdr->sh_type == SHT_NULL) + return true; + + /* Now verify sh_entsize */ + switch (shdr->sh_type) { + case SHT_SYMTAB: + size_ok = shdr->sh_entsize == sizeof(Elf_Sym); + break; +#ifdef Elf_Rela + case SHT_RELA: + size_ok = shdr->sh_entsize == sizeof(Elf_Rela); + break; +#endif + case SHT_DYNAMIC: + size_ok = shdr->sh_entsize == sizeof(Elf_Dyn); + break; +#ifdef Elf_Rel + case SHT_REL: + size_ok = shdr->sh_entsize == sizeof(Elf_Rel); + break; +#endif + case SHT_NOTE: + case SHT_PROGBITS: + case SHT_HASH: + case SHT_NOBITS: + default: + /* + * This is a section whose entsize requirements + * I don't care about. If I don't know about + * the section I can't care about it's entsize + * requirements. + */ + size_ok = true; + break; + } + + if (!size_ok) { + pr_debug("ELF section with wrong entry size.\n"); + return false; + } else if (shdr->sh_addr + shdr->sh_size < shdr->sh_addr) { + pr_debug("ELF section address wraps around.\n"); + return false; + } + + if (shdr->sh_type != SHT_NOBITS) { + if (shdr->sh_offset + shdr->sh_size < shdr->sh_offset) { + pr_debug("ELF section location wraps around.\n"); + return false; + } else if (shdr->sh_offset + shdr->sh_size > buf_len) { + pr_debug("ELF section not in file.\n"); + return false; + } + } + + return true; +} + +static int elf_read_shdr(const char *buf, size_t len, struct elf_info *elf_info, + int idx) +{ + struct elf_shdr *shdr = &elf_info->sechdrs[idx]; + const struct elfhdr *ehdr = elf_info->ehdr; + const char *sbuf; + struct elf_shdr *buf_shdr; + + sbuf = buf + ehdr->e_shoff + idx * sizeof(*buf_shdr); + buf_shdr = (struct elf_shdr *) sbuf; + + shdr->sh_name = elf32_to_cpu(ehdr, buf_shdr->sh_name); + shdr->sh_type = elf32_to_cpu(ehdr, buf_shdr->sh_type); + shdr->sh_addr = elf_addr_to_cpu(ehdr, buf_shdr->sh_addr); + shdr->sh_offset = elf_addr_to_cpu(ehdr, buf_shdr->sh_offset); + shdr->sh_link = elf32_to_cpu(ehdr, buf_shdr->sh_link); + shdr->sh_info = elf32_to_cpu(ehdr, buf_shdr->sh_info); + + /* + * The following fields have a type equivalent to Elf_Addr + * both in 32 bit and 64 bit ELF. + */ + shdr->sh_flags = elf_addr_to_cpu(ehdr, buf_shdr->sh_flags); + shdr->sh_size = elf_addr_to_cpu(ehdr, buf_shdr->sh_size); + shdr->sh_addralign = elf_addr_to_cpu(ehdr, buf_shdr->sh_addralign); + shdr->sh_entsize = elf_addr_to_cpu(ehdr, buf_shdr->sh_entsize); + + return elf_is_shdr_sane(shdr, len) ? 0 : -ENOEXEC; +} + +/** + * elf_read_shdrs - read the section headers from the buffer + * + * This function assumes that the section header table was checked for sanity. + * Use elf_is_ehdr_sane() if it wasn't. + */ +static int elf_read_shdrs(const char *buf, size_t len, + struct elf_info *elf_info) +{ + size_t shdr_size, i; + + /* + * e_shnum is at most 65536 so calculating + * the size of the section header cannot overflow. + */ + shdr_size = sizeof(struct elf_shdr) * elf_info->ehdr->e_shnum; + + elf_info->sechdrs = kzalloc(shdr_size, GFP_KERNEL); + if (!elf_info->sechdrs) + return -ENOMEM; + + for (i = 0; i < elf_info->ehdr->e_shnum; i++) { + int ret; + + ret = elf_read_shdr(buf, len, elf_info, i); + if (ret) { + kfree(elf_info->sechdrs); + elf_info->sechdrs = NULL; + return ret; + } + } + + return 0; +} + +/** + * elf_read_from_buffer - read ELF file and sets up ELF header and ELF info + * @buf: Buffer to read ELF file from. + * @len: Size of @buf. + * @ehdr: Pointer to existing struct which will be populated. + * @elf_info: Pointer to existing struct which will be populated. + * + * This function allows reading ELF files with different byte order than + * the kernel, byte-swapping the fields as needed. + * + * Return: + * On success returns 0, and the caller should call elf_free_info(elf_info) to + * free the memory allocated for the section and program headers. + */ +static int elf_read_from_buffer(const char *buf, size_t len, + struct elfhdr *ehdr, struct elf_info *elf_info) +{ + int ret; + + ret = elf_read_ehdr(buf, len, ehdr); + if (ret) + return ret; + + elf_info->buffer = buf; + elf_info->ehdr = ehdr; + if (ehdr->e_phoff > 0 && ehdr->e_phnum > 0) { + ret = elf_read_phdrs(buf, len, elf_info); + if (ret) + return ret; + } + if (ehdr->e_shoff > 0 && ehdr->e_shnum > 0) { + ret = elf_read_shdrs(buf, len, elf_info); + if (ret) { + kfree(elf_info->proghdrs); + return ret; + } + } + + return 0; +} + +/** + * elf_free_info - free memory allocated by elf_read_from_buffer + */ +void elf_free_info(struct elf_info *elf_info) +{ + kfree(elf_info->proghdrs); + kfree(elf_info->sechdrs); + memset(elf_info, 0, sizeof(*elf_info)); +} + +/** + * build_elf_exec_info - read ELF executable and check that we can use it + */ +int build_elf_exec_info(const char *buf, size_t len, struct elfhdr *ehdr, + struct elf_info *elf_info) +{ + int i; + int ret; + + ret = elf_read_from_buffer(buf, len, ehdr, elf_info); + if (ret) + return ret; + + /* Big endian vmlinux has type ET_DYN. */ + if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) { + pr_err("Not an ELF executable.\n"); + goto error; + } else if (!elf_info->proghdrs) { + pr_err("No ELF program header.\n"); + goto error; + } + + for (i = 0; i < ehdr->e_phnum; i++) { + /* + * Kexec does not support loading interpreters. + * In addition this check keeps us from attempting + * to kexec ordinary executables. + */ + if (elf_info->proghdrs[i].p_type == PT_INTERP) { + pr_err("Requires an ELF interpreter.\n"); + goto error; + } + } + + return 0; +error: + elf_free_info(elf_info); + return -ENOEXEC; +} From patchwork Thu Aug 24 08:18:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110877 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315551qge; Thu, 24 Aug 2017 01:19:17 -0700 (PDT) X-Received: by 10.84.133.37 with SMTP id 34mr6212876plf.221.1503562757072; Thu, 24 Aug 2017 01:19:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562757; cv=none; d=google.com; s=arc-20160816; b=Bletaf/oNrFri0TNjni/Uim0hXh9LknYx8rclOpjeeOyzaA2wvQCXrMl4sburrcfK1 S2jNIVuG52BDt62GGR5sLahudXNRN4Z7EfUhlDHYtILVTTETn7gI71kn2djYGCGEYGBp o4ZV/zUA1J9Z2oEUXdTzjqHTyxtsFqBLfG9D9Sin5xRB4EzH8l3hEpbMYiEFZvNqNEQZ JBwkQ6gjFeKl0RvyQfPTQ2UxwRsm5bWtLSVug/cmpvo7QD3rOuyM05zGdYdYkuwVuERS HEIJh3Cu5PiaqqyDFiVoP7dV+/xhZbb/0S6vq80Bn5DxLfK+BsivIPLCrzcdUKDYsg+t Z0yw== 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=AZKv9Wlc6lCDXwYmRBQ48YOZgLZCA77heHW8sBlTBT0=; b=NfeMTvW20BPZgnU4otiKDz1dOcaOfsqkSEecqxJkO8PfnKGoyamlpLWpzaPNGYiD/S 9pjavHAlyilN0QWi5uCl6g3CMhvVfO2t/FvAteNxPFuXLvV3QVCJVPfYCaB/UzfkcYJ+ DHrGBD9Bj6BJD7/DOAWsGgKesvGtE7l4YOHEPSGExNBE3x3qHTo85sw7J3FaMGIGvDh7 CWmPfUOknmAIc8rQYs4Z7vb2EzLkwOjDpTwwcOfosAGBLESyG24wO2GlEsxGWVQGApt+ nzpkvIicLgmH5oli8V1JOLtcHcP75aEHMRaXH1Qca/UGHd0rZ7A482EPQCW5Bdz/8BmO cEbQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=N9zdsz4F; 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 w88si2467457pfa.519.2017.08.24.01.19.16; Thu, 24 Aug 2017 01:19:17 -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 header.s=google header.b=N9zdsz4F; 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 S1751944AbdHXITN (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:13 -0400 Received: from mail-pg0-f47.google.com ([74.125.83.47]:37915 "EHLO mail-pg0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751356AbdHXISb (ORCPT ); Thu, 24 Aug 2017 04:18:31 -0400 Received: by mail-pg0-f47.google.com with SMTP id m133so13375843pga.5 for ; Thu, 24 Aug 2017 01:18:31 -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=AZKv9Wlc6lCDXwYmRBQ48YOZgLZCA77heHW8sBlTBT0=; b=N9zdsz4FdfV4G+IGhmgEl4KwgXlPprN8AELOgf34py9x7h9+NUDJ/sEFJ2OfIADKzh 5tTnVuIqiE9JT9z8TtuWLoN2aoUJn0ITN4KwjybM09ue4Z4OFrxjDxD7BJqjT2Vo1rVY LSeF4CPfgK83Jg77tBeXygGE5oi6ebiXi3O+w= 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=AZKv9Wlc6lCDXwYmRBQ48YOZgLZCA77heHW8sBlTBT0=; b=m2NNz6FmCvetQWOIpfov8GXZ0y9KWuz9J9RDFAoH56HwIwAdbWHtzdJbCXlqt17KYa J4rFGrFJisefSjHX6dwbcTA0Y11+QMRIux5no7RavS3TSnLH/80C50J1GX7reiYFiKRT dMfa27i6920M0MWs01AdaTnnTfgWcxjv0wHBC51h7pZ+M8BcZ8HXDesvAnUmKA6dsN4f 3dwp1bw+vLYw9klhvGw/NKIoJpA//TsRMqU/w1qTAMwuqThosnacl2OXVw/9tvadM1yt /ywua8kHIT6TQTvqpWgcH7gOSom3JKoRbvttoVyFXxl9xPUgovdmrzJcbAR+17VB8ymd kgtA== X-Gm-Message-State: AHYfb5hwvuB440zDo2lBFp77zECEp/X1iiXiVO5ZlB6v6nA2JJiYPkiU MlzanPpKGs3/oJVC X-Received: by 10.84.237.15 with SMTP id s15mr6442513plk.100.1503562710838; Thu, 24 Aug 2017 01:18:30 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id o75sm7517713pfa.50.2017.08.24.01.18.29 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:30 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 05/14] kexec_file: factor out crashdump elf header function from x86 Date: Thu, 24 Aug 2017 17:18:02 +0900 Message-Id: <20170824081811.19299-6-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org prepare_elf_headers() can also be useful for other architectures, including arm64. So let it factored out. Signed-off-by: AKASHI Takahiro Cc: Dave Young Cc: Vivek Goyal Cc: Baoquan He --- arch/x86/kernel/crash.c | 324 ---------------------------------------------- include/linux/kexec.h | 19 +++ kernel/crash_core.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 352 insertions(+), 324 deletions(-) -- 2.14.1 diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index 44404e2307bb..3c6b880f6dbf 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include @@ -41,34 +40,6 @@ /* Alignment required for elf header segment */ #define ELF_CORE_HEADER_ALIGN 4096 -/* This primarily represents number of split ranges due to exclusion */ -#define CRASH_MAX_RANGES 16 - -struct crash_mem_range { - u64 start, end; -}; - -struct crash_mem { - unsigned int nr_ranges; - struct crash_mem_range ranges[CRASH_MAX_RANGES]; -}; - -/* Misc data about ram ranges needed to prepare elf headers */ -struct crash_elf_data { - struct kimage *image; - /* - * Total number of ram ranges we have after various adjustments for - * crash reserved region, etc. - */ - unsigned int max_nr_ranges; - - /* Pointer to elf header */ - void *ehdr; - /* Pointer to next phdr */ - void *bufp; - struct crash_mem mem; -}; - /* Used while preparing memory map entries for second kernel */ struct crash_memmap_data { struct boot_params *params; @@ -209,301 +180,6 @@ void native_machine_crash_shutdown(struct pt_regs *regs) } #ifdef CONFIG_KEXEC_FILE -static int get_nr_ram_ranges_callback(u64 start, u64 end, void *arg) -{ - unsigned int *nr_ranges = arg; - - (*nr_ranges)++; - return 0; -} - - -/* Gather all the required information to prepare elf headers for ram regions */ -static void fill_up_crash_elf_data(struct crash_elf_data *ced, - struct kimage *image) -{ - unsigned int nr_ranges = 0; - - ced->image = image; - - walk_system_ram_res(0, -1, &nr_ranges, - get_nr_ram_ranges_callback); - - ced->max_nr_ranges = nr_ranges; - - /* Exclusion of crash region could split memory ranges */ - ced->max_nr_ranges++; - - /* If crashk_low_res is not 0, another range split possible */ - if (crashk_low_res.end) - ced->max_nr_ranges++; -} - -static int exclude_mem_range(struct crash_mem *mem, - unsigned long long mstart, unsigned long long mend) -{ - int i, j; - unsigned long long start, end; - struct crash_mem_range temp_range = {0, 0}; - - for (i = 0; i < mem->nr_ranges; i++) { - start = mem->ranges[i].start; - end = mem->ranges[i].end; - - if (mstart > end || mend < start) - continue; - - /* Truncate any area outside of range */ - if (mstart < start) - mstart = start; - if (mend > end) - mend = end; - - /* Found completely overlapping range */ - if (mstart == start && mend == end) { - mem->ranges[i].start = 0; - mem->ranges[i].end = 0; - if (i < mem->nr_ranges - 1) { - /* Shift rest of the ranges to left */ - for (j = i; j < mem->nr_ranges - 1; j++) { - mem->ranges[j].start = - mem->ranges[j+1].start; - mem->ranges[j].end = - mem->ranges[j+1].end; - } - } - mem->nr_ranges--; - return 0; - } - - if (mstart > start && mend < end) { - /* Split original range */ - mem->ranges[i].end = mstart - 1; - temp_range.start = mend + 1; - temp_range.end = end; - } else if (mstart != start) - mem->ranges[i].end = mstart - 1; - else - mem->ranges[i].start = mend + 1; - break; - } - - /* If a split happend, add the split to array */ - if (!temp_range.end) - return 0; - - /* Split happened */ - if (i == CRASH_MAX_RANGES - 1) { - pr_err("Too many crash ranges after split\n"); - return -ENOMEM; - } - - /* Location where new range should go */ - j = i + 1; - if (j < mem->nr_ranges) { - /* Move over all ranges one slot towards the end */ - for (i = mem->nr_ranges - 1; i >= j; i--) - mem->ranges[i + 1] = mem->ranges[i]; - } - - mem->ranges[j].start = temp_range.start; - mem->ranges[j].end = temp_range.end; - mem->nr_ranges++; - return 0; -} - -/* - * Look for any unwanted ranges between mstart, mend and remove them. This - * might lead to split and split ranges are put in ced->mem.ranges[] array - */ -static int elf_header_exclude_ranges(struct crash_elf_data *ced, - unsigned long long mstart, unsigned long long mend) -{ - struct crash_mem *cmem = &ced->mem; - int ret = 0; - - memset(cmem->ranges, 0, sizeof(cmem->ranges)); - - cmem->ranges[0].start = mstart; - cmem->ranges[0].end = mend; - cmem->nr_ranges = 1; - - /* Exclude crashkernel region */ - ret = exclude_mem_range(cmem, crashk_res.start, crashk_res.end); - if (ret) - return ret; - - if (crashk_low_res.end) { - ret = exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end); - if (ret) - return ret; - } - - return ret; -} - -static int prepare_elf64_ram_headers_callback(u64 start, u64 end, void *arg) -{ - struct crash_elf_data *ced = arg; - Elf64_Ehdr *ehdr; - Elf64_Phdr *phdr; - unsigned long mstart, mend; - struct kimage *image = ced->image; - struct crash_mem *cmem; - int ret, i; - - ehdr = ced->ehdr; - - /* Exclude unwanted mem ranges */ - ret = elf_header_exclude_ranges(ced, start, end); - if (ret) - return ret; - - /* Go through all the ranges in ced->mem.ranges[] and prepare phdr */ - cmem = &ced->mem; - - for (i = 0; i < cmem->nr_ranges; i++) { - mstart = cmem->ranges[i].start; - mend = cmem->ranges[i].end; - - phdr = ced->bufp; - ced->bufp += sizeof(Elf64_Phdr); - - phdr->p_type = PT_LOAD; - phdr->p_flags = PF_R|PF_W|PF_X; - phdr->p_offset = mstart; - - /* - * If a range matches backup region, adjust offset to backup - * segment. - */ - if (mstart == image->arch.backup_src_start && - (mend - mstart + 1) == image->arch.backup_src_sz) - phdr->p_offset = image->arch.backup_load_addr; - - phdr->p_paddr = mstart; - phdr->p_vaddr = (unsigned long long) __va(mstart); - phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; - phdr->p_align = 0; - ehdr->e_phnum++; - pr_debug("Crash PT_LOAD elf header. phdr=%p vaddr=0x%llx, paddr=0x%llx, sz=0x%llx e_phnum=%d p_offset=0x%llx\n", - phdr, phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, - ehdr->e_phnum, phdr->p_offset); - } - - return ret; -} - -static int prepare_elf64_headers(struct crash_elf_data *ced, - void **addr, unsigned long *sz) -{ - Elf64_Ehdr *ehdr; - Elf64_Phdr *phdr; - unsigned long nr_cpus = num_possible_cpus(), nr_phdr, elf_sz; - unsigned char *buf, *bufp; - unsigned int cpu; - unsigned long long notes_addr; - int ret; - - /* extra phdr for vmcoreinfo elf note */ - nr_phdr = nr_cpus + 1; - nr_phdr += ced->max_nr_ranges; - - /* - * kexec-tools creates an extra PT_LOAD phdr for kernel text mapping - * area on x86_64 (ffffffff80000000 - ffffffffa0000000). - * I think this is required by tools like gdb. So same physical - * memory will be mapped in two elf headers. One will contain kernel - * text virtual addresses and other will have __va(physical) addresses. - */ - - nr_phdr++; - elf_sz = sizeof(Elf64_Ehdr) + nr_phdr * sizeof(Elf64_Phdr); - elf_sz = ALIGN(elf_sz, ELF_CORE_HEADER_ALIGN); - - buf = vzalloc(elf_sz); - if (!buf) - return -ENOMEM; - - bufp = buf; - ehdr = (Elf64_Ehdr *)bufp; - bufp += sizeof(Elf64_Ehdr); - memcpy(ehdr->e_ident, ELFMAG, SELFMAG); - ehdr->e_ident[EI_CLASS] = ELFCLASS64; - ehdr->e_ident[EI_DATA] = ELFDATA2LSB; - ehdr->e_ident[EI_VERSION] = EV_CURRENT; - ehdr->e_ident[EI_OSABI] = ELF_OSABI; - memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD); - ehdr->e_type = ET_CORE; - ehdr->e_machine = ELF_ARCH; - ehdr->e_version = EV_CURRENT; - ehdr->e_phoff = sizeof(Elf64_Ehdr); - ehdr->e_ehsize = sizeof(Elf64_Ehdr); - ehdr->e_phentsize = sizeof(Elf64_Phdr); - - /* Prepare one phdr of type PT_NOTE for each present cpu */ - for_each_present_cpu(cpu) { - phdr = (Elf64_Phdr *)bufp; - bufp += sizeof(Elf64_Phdr); - phdr->p_type = PT_NOTE; - notes_addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpu)); - phdr->p_offset = phdr->p_paddr = notes_addr; - phdr->p_filesz = phdr->p_memsz = sizeof(note_buf_t); - (ehdr->e_phnum)++; - } - - /* Prepare one PT_NOTE header for vmcoreinfo */ - phdr = (Elf64_Phdr *)bufp; - bufp += sizeof(Elf64_Phdr); - phdr->p_type = PT_NOTE; - phdr->p_offset = phdr->p_paddr = paddr_vmcoreinfo_note(); - phdr->p_filesz = phdr->p_memsz = VMCOREINFO_NOTE_SIZE; - (ehdr->e_phnum)++; - -#ifdef CONFIG_X86_64 - /* Prepare PT_LOAD type program header for kernel text region */ - phdr = (Elf64_Phdr *)bufp; - bufp += sizeof(Elf64_Phdr); - phdr->p_type = PT_LOAD; - phdr->p_flags = PF_R|PF_W|PF_X; - phdr->p_vaddr = (Elf64_Addr)_text; - phdr->p_filesz = phdr->p_memsz = _end - _text; - phdr->p_offset = phdr->p_paddr = __pa_symbol(_text); - (ehdr->e_phnum)++; -#endif - - /* Prepare PT_LOAD headers for system ram chunks. */ - ced->ehdr = ehdr; - ced->bufp = bufp; - ret = walk_system_ram_res(0, -1, ced, - prepare_elf64_ram_headers_callback); - if (ret < 0) - return ret; - - *addr = buf; - *sz = elf_sz; - return 0; -} - -/* Prepare elf headers. Return addr and size */ -static int prepare_elf_headers(struct kimage *image, void **addr, - unsigned long *sz) -{ - struct crash_elf_data *ced; - int ret; - - ced = kzalloc(sizeof(*ced), GFP_KERNEL); - if (!ced) - return -ENOMEM; - - fill_up_crash_elf_data(ced, image); - - /* By default prepare 64bit headers */ - ret = prepare_elf64_headers(ced, addr, sz); - kfree(ced); - return ret; -} - static int add_e820_entry(struct boot_params *params, struct e820_entry *entry) { unsigned int nr_e820_entries; diff --git a/include/linux/kexec.h b/include/linux/kexec.h index db98e3459e90..acaecd72b134 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -163,6 +163,25 @@ int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *)); extern int kexec_add_buffer(struct kexec_buf *kbuf); int kexec_locate_mem_hole(struct kexec_buf *kbuf); +#ifdef CONFIG_CRASH_CORE +extern int prepare_elf_headers(struct kimage *image, void **addr, + unsigned long *sz); + +/* This primarily represents number of split ranges due to exclusion */ +#define CRASH_MAX_RANGES 16 + +struct crash_mem_range { + u64 start, end; +}; + +struct crash_mem { + unsigned int nr_ranges; + struct crash_mem_range ranges[CRASH_MAX_RANGES]; +}; + +extern int exclude_mem_range(struct crash_mem *mem, + unsigned long long mstart, unsigned long long mend); +#endif #ifdef CONFIG_KEXEC_FILE_ELF struct elf_info { diff --git a/kernel/crash_core.c b/kernel/crash_core.c index 6db80fc0810b..f2385590e94b 100644 --- a/kernel/crash_core.c +++ b/kernel/crash_core.c @@ -7,6 +7,11 @@ */ #include +#include +#include +#include +#include +#include #include #include @@ -469,3 +474,331 @@ static int __init crash_save_vmcoreinfo_init(void) } subsys_initcall(crash_save_vmcoreinfo_init); + +#ifdef CONFIG_KEXEC_FILE +/* + * The following definitions are for local use only. + */ + +/* Alignment required for elf header segment */ +#define ELF_CORE_HEADER_ALIGN 4096 + +/* Misc data about ram ranges needed to prepare elf headers */ +struct crash_elf_data { + struct kimage *image; + /* + * Total number of ram ranges we have after various adjustments for + * crash reserved region, etc. + */ + unsigned int max_nr_ranges; + + /* Pointer to elf header */ + void *ehdr; + /* Pointer to next phdr */ + void *bufp; + struct crash_mem mem; +}; + +static int get_nr_ram_ranges_callback(u64 start, u64 end, void *arg) +{ + unsigned int *nr_ranges = arg; + + (*nr_ranges)++; + return 0; +} + + +/* Gather all the required information to prepare elf headers for ram regions */ +static void fill_up_crash_elf_data(struct crash_elf_data *ced, + struct kimage *image) +{ + unsigned int nr_ranges = 0; + + ced->image = image; + + walk_system_ram_res(0, -1, &nr_ranges, + get_nr_ram_ranges_callback); + + ced->max_nr_ranges = nr_ranges; + + /* Exclusion of crash region could split memory ranges */ + ced->max_nr_ranges++; + +#ifdef CONFIG_X86_64 + /* If crashk_low_res is not 0, another range split possible */ + if (crashk_low_res.end) + ced->max_nr_ranges++; +#endif +} + +int exclude_mem_range(struct crash_mem *mem, + unsigned long long mstart, unsigned long long mend) +{ + int i, j; + unsigned long long start, end; + struct crash_mem_range temp_range = {0, 0}; + + for (i = 0; i < mem->nr_ranges; i++) { + start = mem->ranges[i].start; + end = mem->ranges[i].end; + + if (mstart > end || mend < start) + continue; + + /* Truncate any area outside of range */ + if (mstart < start) + mstart = start; + if (mend > end) + mend = end; + + /* Found completely overlapping range */ + if (mstart == start && mend == end) { + mem->ranges[i].start = 0; + mem->ranges[i].end = 0; + if (i < mem->nr_ranges - 1) { + /* Shift rest of the ranges to left */ + for (j = i; j < mem->nr_ranges - 1; j++) { + mem->ranges[j].start = + mem->ranges[j+1].start; + mem->ranges[j].end = + mem->ranges[j+1].end; + } + } + mem->nr_ranges--; + return 0; + } + + if (mstart > start && mend < end) { + /* Split original range */ + mem->ranges[i].end = mstart - 1; + temp_range.start = mend + 1; + temp_range.end = end; + } else if (mstart != start) + mem->ranges[i].end = mstart - 1; + else + mem->ranges[i].start = mend + 1; + break; + } + + /* If a split happened, add the split to array */ + if (!temp_range.end) + return 0; + + /* Split happened */ + if (i == CRASH_MAX_RANGES - 1) { + pr_err("Too many crash ranges after split\n"); + return -ENOMEM; + } + + /* Location where new range should go */ + j = i + 1; + if (j < mem->nr_ranges) { + /* Move over all ranges one slot towards the end */ + for (i = mem->nr_ranges - 1; i >= j; i--) + mem->ranges[i + 1] = mem->ranges[i]; + } + + mem->ranges[j].start = temp_range.start; + mem->ranges[j].end = temp_range.end; + mem->nr_ranges++; + return 0; +} + +/* + * Look for any unwanted ranges between mstart, mend and remove them. This + * might lead to split and split ranges are put in ced->mem.ranges[] array + */ +static int elf_header_exclude_ranges(struct crash_elf_data *ced, + unsigned long long mstart, unsigned long long mend) +{ + struct crash_mem *cmem = &ced->mem; + int ret = 0; + + memset(cmem->ranges, 0, sizeof(cmem->ranges)); + + cmem->ranges[0].start = mstart; + cmem->ranges[0].end = mend; + cmem->nr_ranges = 1; + + /* Exclude crashkernel region */ + ret = exclude_mem_range(cmem, crashk_res.start, crashk_res.end); + if (ret) + return ret; + +#ifdef CONFIG_X86_64 + if (crashk_low_res.end) { + ret = exclude_mem_range(cmem, crashk_low_res.start, + crashk_low_res.end); + if (ret) + return ret; + } +#endif + + return ret; +} + +static int prepare_elf64_ram_headers_callback(u64 start, u64 end, void *arg) +{ + struct crash_elf_data *ced = arg; + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + unsigned long mstart, mend; +#ifdef CONFIG_X86_64 + struct kimage *image = ced->image; +#endif + struct crash_mem *cmem; + int ret, i; + + ehdr = ced->ehdr; + + /* Exclude unwanted mem ranges */ + ret = elf_header_exclude_ranges(ced, start, end); + if (ret) + return ret; + + /* Go through all the ranges in ced->mem.ranges[] and prepare phdr */ + cmem = &ced->mem; + + for (i = 0; i < cmem->nr_ranges; i++) { + mstart = cmem->ranges[i].start; + mend = cmem->ranges[i].end; + + phdr = ced->bufp; + ced->bufp += sizeof(Elf64_Phdr); + + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_offset = mstart; + +#ifdef CONFIG_X86_64 + /* + * If a range matches backup region, adjust offset to backup + * segment. + */ + if (mstart == image->arch.backup_src_start && + (mend - mstart + 1) == image->arch.backup_src_sz) + phdr->p_offset = image->arch.backup_load_addr; +#endif + + phdr->p_paddr = mstart; + phdr->p_vaddr = (unsigned long long) __va(mstart); + phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; + phdr->p_align = 0; + ehdr->e_phnum++; + pr_debug("Crash PT_LOAD elf header. phdr=%p vaddr=0x%llx, paddr=0x%llx, sz=0x%llx e_phnum=%d p_offset=0x%llx\n", + phdr, phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, + ehdr->e_phnum, phdr->p_offset); + } + + return ret; +} + +static int prepare_elf64_headers(struct crash_elf_data *ced, + void **addr, unsigned long *sz) +{ + Elf64_Ehdr *ehdr; + Elf64_Phdr *phdr; + unsigned long nr_cpus = num_possible_cpus(), nr_phdr, elf_sz; + unsigned char *buf, *bufp; + unsigned int cpu; + unsigned long long notes_addr; + int ret; + + /* extra phdr for vmcoreinfo elf note */ + nr_phdr = nr_cpus + 1; + nr_phdr += ced->max_nr_ranges; + + /* + * kexec-tools creates an extra PT_LOAD phdr for kernel text mapping + * area on x86_64 (ffffffff80000000 - ffffffffa0000000). + * I think this is required by tools like gdb. So same physical + * memory will be mapped in two elf headers. One will contain kernel + * text virtual addresses and other will have __va(physical) addresses. + */ + + nr_phdr++; + elf_sz = sizeof(Elf64_Ehdr) + nr_phdr * sizeof(Elf64_Phdr); + elf_sz = ALIGN(elf_sz, ELF_CORE_HEADER_ALIGN); + + buf = vzalloc(elf_sz); + if (!buf) + return -ENOMEM; + + bufp = buf; + ehdr = (Elf64_Ehdr *)bufp; + bufp += sizeof(Elf64_Ehdr); + memcpy(ehdr->e_ident, ELFMAG, SELFMAG); + ehdr->e_ident[EI_CLASS] = ELFCLASS64; + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELF_OSABI; + memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD); + ehdr->e_type = ET_CORE; + ehdr->e_machine = ELF_ARCH; + ehdr->e_version = EV_CURRENT; + ehdr->e_phoff = sizeof(Elf64_Ehdr); + ehdr->e_ehsize = sizeof(Elf64_Ehdr); + ehdr->e_phentsize = sizeof(Elf64_Phdr); + + /* Prepare one phdr of type PT_NOTE for each present cpu */ + for_each_present_cpu(cpu) { + phdr = (Elf64_Phdr *)bufp; + bufp += sizeof(Elf64_Phdr); + phdr->p_type = PT_NOTE; + notes_addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpu)); + phdr->p_offset = phdr->p_paddr = notes_addr; + phdr->p_filesz = phdr->p_memsz = sizeof(note_buf_t); + (ehdr->e_phnum)++; + } + + /* Prepare one PT_NOTE header for vmcoreinfo */ + phdr = (Elf64_Phdr *)bufp; + bufp += sizeof(Elf64_Phdr); + phdr->p_type = PT_NOTE; + phdr->p_offset = phdr->p_paddr = paddr_vmcoreinfo_note(); + phdr->p_filesz = phdr->p_memsz = VMCOREINFO_NOTE_SIZE; + (ehdr->e_phnum)++; + +#ifdef CONFIG_X86_64 + /* Prepare PT_LOAD type program header for kernel text region */ + phdr = (Elf64_Phdr *)bufp; + bufp += sizeof(Elf64_Phdr); + phdr->p_type = PT_LOAD; + phdr->p_flags = PF_R|PF_W|PF_X; + phdr->p_vaddr = (Elf64_Addr)_text; + phdr->p_filesz = phdr->p_memsz = _end - _text; + phdr->p_offset = phdr->p_paddr = __pa_symbol(_text); + (ehdr->e_phnum)++; +#endif + + /* Prepare PT_LOAD headers for system ram chunks. */ + ced->ehdr = ehdr; + ced->bufp = bufp; + ret = walk_system_ram_res(0, -1, ced, + prepare_elf64_ram_headers_callback); + if (ret < 0) + return ret; + + *addr = buf; + *sz = elf_sz; + return 0; +} + +/* Prepare elf headers. Return addr and size */ +int prepare_elf_headers(struct kimage *image, void **addr, unsigned long *sz) +{ + struct crash_elf_data *ced; + int ret; + + ced = kzalloc(sizeof(*ced), GFP_KERNEL); + if (!ced) + return -ENOMEM; + + fill_up_crash_elf_data(ced, image); + + /* By default prepare 64bit headers */ + ret = prepare_elf64_headers(ced, addr, sz); + kfree(ced); + return ret; +} +#endif /* CONFIG_KEXEC_FILE */ From patchwork Thu Aug 24 08:18:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110885 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5317871qge; Thu, 24 Aug 2017 01:21:36 -0700 (PDT) X-Received: by 10.98.152.77 with SMTP id q74mr5651855pfd.40.1503562896171; Thu, 24 Aug 2017 01:21:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562896; cv=none; d=google.com; s=arc-20160816; b=oFiDKF74fk2eOHCCxZPLh+++bGcTtS/zPxrjmDKHNm0rM3b+jVXftDnobov3jtfXSG HBxPpa+IHTxilSrisy9gUQDRHYp0Jhc2OoqYTsdbBzue+fsViXbeYjR38AoxPmZCxKCr F/Z/Zs5ybJt8rpaHYDxmWzyYl8vzLhTO5TyRitjSxJXGTclQwesDoeTNNxttH4O6TOdF 4F6CYQUSjbuGcdOtJ4PcWW6FMqE2Rn4UsK7gokSmJ/d/k1YUews32Pjq9mIF56Flc2ah dvEov8UTGxeSgaP/Pmjse8WByf9PM2PTtjcJ1/clB4hhnIcq0d72XtDrEOyetXtXD4wL 13IQ== 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=l/Cr37RnrKeUy/7oVwyiQ7k3V/jjYM1O6XUt3JP3jVg=; b=IA6C9BLvyMbdQiSGnIrZ3aV0cBS9YV5TrIJ9Fowd71nsoy/KmqZ3OCOrNXOKTza1D0 4w7Rrb0Fxuygslb5mcsr3NIm9/F7kDAeKcUmNziPvAoim4oPgvjm4udnKbsrV62gDYAR XiL546wp0qxiXGDUj+Ni3Uk978gsLf3q/AN+1rDiXGp4qfPeS3b985uY3VzQTBnqfqug LFjcKvCHpUfS+MFog3GqmbKjSNOdlZSrJR2uxsQ3wbFtWvoFNDF49SX6xAIaNOUeMjVk rS+QYQ/kLX5HDpneuaZ4cokgHr7ZucGEoS1qyINKE92JkrG1PP+CTbs522qSOQMUhMYE HWEg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=BkIqPASS; 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 j23si2739677pli.275.2017.08.24.01.21.35; Thu, 24 Aug 2017 01:21:36 -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 header.s=google header.b=BkIqPASS; 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 S1751858AbdHXITM (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:12 -0400 Received: from mail-pg0-f48.google.com ([74.125.83.48]:33838 "EHLO mail-pg0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751253AbdHXISg (ORCPT ); Thu, 24 Aug 2017 04:18:36 -0400 Received: by mail-pg0-f48.google.com with SMTP id s14so13470727pgs.1 for ; Thu, 24 Aug 2017 01:18:36 -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=l/Cr37RnrKeUy/7oVwyiQ7k3V/jjYM1O6XUt3JP3jVg=; b=BkIqPASSps5+FI55sagFyNSywIgqshk98g0+zITac8XY+2K1X8fKvrZ1Pe6yHlS8qq XsZ+5zGk5nWSc05fYf0gprP0/s3hHcnjjRc+hcfNeb2fzp6U18sn05RIey4oa8qTPGd5 4lKrjudL4+TFQf+NZwwHeYE4gUEd48snwXwqo= 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=l/Cr37RnrKeUy/7oVwyiQ7k3V/jjYM1O6XUt3JP3jVg=; b=CpoAYgTocnnPSdnO8OudS9MiyAx1A1eT7oEfvbQhdF2JTTQczAkXxB0jHIGcPNMEs4 oRy1e+x5Oy/F//43kKxhTGsqpsMVDJ7G2RDGMrVFRYKnPbejlbVOlGJEXZOwxById3VZ mylisiNuWlYxsIH1jBjQmwAJIpDn8XTNoUYqkZEpCojUBoSbPmamZXBPg6Rz6She/y+W niMjlPvzX+ZfT0OiqxZZp3p5f+2J1sSSuou+OHu9NtJuyVDPb9AI7dxpe/hSRS6/VsPk 6e+0/b3PPhu0t9ejZGwe+ItTBN7nDKQ7Yn7Djp6+0pyH153tb2mUXxF5txrcQ1Ra5cwQ hHEg== X-Gm-Message-State: AHYfb5jZ0+FzayWSxveqRp16AIoGz+CO84f58Mqxf4kdRYbQDaMoyn1S wtEkNzYBDec/E6Th X-Received: by 10.99.120.200 with SMTP id t191mr5598289pgc.191.1503562715830; Thu, 24 Aug 2017 01:18:35 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id o25sm6481038pfj.117.2017.08.24.01.18.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:35 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 06/14] kexec_file: add kexec_add_segment() Date: Thu, 24 Aug 2017 17:18:03 +0900 Message-Id: <20170824081811.19299-7-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org In contrast to kexec_add_buffer(), this function assumes that kbuf->mem is already assigned by caller. This type of allocation is commonly used in kexec-tools. This function will be used on arm64 in loading vmlinux(elf) binary. Signed-off-by: AKASHI Takahiro Cc: Dave Young Cc: Vivek Goyal Cc: Baoquan He --- include/linux/kexec.h | 1 + kernel/kexec_file.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) -- 2.14.1 diff --git a/include/linux/kexec.h b/include/linux/kexec.h index acaecd72b134..be5e99afaf77 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -162,6 +162,7 @@ struct kexec_buf { int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *)); extern int kexec_add_buffer(struct kexec_buf *kbuf); +extern int kexec_add_segment(struct kexec_buf *kbuf); int kexec_locate_mem_hole(struct kexec_buf *kbuf); #ifdef CONFIG_CRASH_CORE extern int prepare_elf_headers(struct kimage *image, void **addr, diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 9f48f4412297..d898dec37816 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -519,6 +519,53 @@ int kexec_add_buffer(struct kexec_buf *kbuf) return 0; } +/** + * kexec_add_segment - place a buffer in a kexec segment + * @kbuf: Buffer contents and memory parameters. + * + * In contrast to kexec_add_buffer(), this function assumes + * that kbuf->mem is already assigned by caller. + * + * Return: 0 on success, negative errno on error. + */ +int kexec_add_segment(struct kexec_buf *kbuf) +{ + + struct kexec_segment *ksegment; + + /* Currently adding segment this way is allowed only in file mode */ + if (!kbuf->image->file_mode) + return -EINVAL; + + if (kbuf->image->nr_segments >= KEXEC_SEGMENT_MAX) + return -EINVAL; + + /* + * Make sure we are not trying to add buffer after allocating + * control pages. All segments need to be placed first before + * any control pages are allocated. As control page allocation + * logic goes through list of segments to make sure there are + * no destination overlaps. + */ + if (!list_empty(&kbuf->image->control_pages)) { + WARN_ON(1); + return -EINVAL; + } + + /* Ensure minimum alignment needed for segments. */ + kbuf->memsz = ALIGN(kbuf->memsz, PAGE_SIZE); + + /* Found a suitable memory range */ + ksegment = &kbuf->image->segment[kbuf->image->nr_segments]; + ksegment->kbuf = kbuf->buffer; + ksegment->bufsz = kbuf->bufsz; + ksegment->mem = kbuf->mem; + ksegment->memsz = kbuf->memsz; + kbuf->image->nr_segments++; + + return 0; +} + /* Calculate and store the digest of segments */ static int kexec_calculate_store_digests(struct kimage *image) { From patchwork Thu Aug 24 08:18:04 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110887 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5319236qge; Thu, 24 Aug 2017 01:23:02 -0700 (PDT) X-Received: by 10.98.23.74 with SMTP id 71mr5725130pfx.151.1503562982757; Thu, 24 Aug 2017 01:23:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562982; cv=none; d=google.com; s=arc-20160816; b=eu4+CWK7j2OE3QzUVHCVoY3Mbx1d7UaOwe4M4qjwAcKHZ/r1QPlM2VkZPJSpHBaoKT r0yMgniWK0uLHDsffi1UjmpXwTIZ6gHRvk9N/ofDjyUNx4lwRNdY6BqucNAj/Zc+8rfP YMxiKu8LAPqMC/K7o086lY2jRpHcXwPXtvdLEMbHCXvzfUsJsepXZvfr1hWdoJTDgJSt h7oQevrFCKrtgPUGd8ExaER9tDCqjt1RMg2c/ENHCDAgOQCjjUnAXNjPCiwCUt1uKB1R ZEY0FAWmjFd2NLE85A5lzJDR3tzntsVsEWantEDWdQx8FhrKiGpdOzobdp8iisx4sVbS cqgA== 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=7DMnNxx5FymJLkO3/mxMplUl8irrbJPrVAuUpGGl77c=; b=N488URhx9xTFMMRr4qMWcQH2htZ1i1Q/f0UL0t601Itk8hV/XWybRhnZen0AncuaW8 Dpx7CJZDq4NRzwjWiikndLFD/CQJHjTVnTRwQ6B+AKdx4DJY0jLR3xfvQZ8/aSXG0REW 5rjVR8O+5OCPTji2vN14KlurNEY3DK0h5RXaOVrku5kzLqDGnsnhOmzCMxDm9pwoqEid sL24zugTKkZCEtkDtAIxsoh77GBTzhKWBzRqAAlD91bdStxAB97O3qDWY5tUEwOh0Q6q lSzhmPpaucGy8V/Z+XFgrFjKJ8AXV83mo5eXPnCHbp2YkB/N4FCv2LjWPBoz/iXHc3Sb Vm+Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Ned5YBPn; 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 k131si2447774pgc.233.2017.08.24.01.23.02; Thu, 24 Aug 2017 01:23:02 -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 header.s=google header.b=Ned5YBPn; 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 S1751804AbdHXITJ (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:09 -0400 Received: from mail-pg0-f44.google.com ([74.125.83.44]:37960 "EHLO mail-pg0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751348AbdHXISk (ORCPT ); Thu, 24 Aug 2017 04:18:40 -0400 Received: by mail-pg0-f44.google.com with SMTP id m133so13377659pga.5 for ; Thu, 24 Aug 2017 01:18:40 -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=7DMnNxx5FymJLkO3/mxMplUl8irrbJPrVAuUpGGl77c=; b=Ned5YBPnt+KLGShWuOwLLSSwGh0Xr9toSPVZMcIr3NuYK9bQICZ042jTDYheMlrIW/ g7fVsPls2iSajwBU3bsudqaCSzOopFjmVIlgqp1emtp25ZihGnIB1su07l213dnzecsW qs3YbQwPZU5BzUKvzhpdHVuIGw0Foh2wo7LAg= 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=7DMnNxx5FymJLkO3/mxMplUl8irrbJPrVAuUpGGl77c=; b=LVgwyb/oAEt+3vrDpDZaZFOrTwzE8MypTVAc0tM1v/wwZoDHmo9sOmmoS4Xgu/2shy 1RnmnHAumV7xuYKNCH+YDsHf+mH50x5iKXoAR41itb9UQ9cNu+gsFgWRWm81v8CIFfW6 8bkfXvS8RZzXd9Wql6zPh4UQVZvoTjBiS/taRba+c5WGmzY/PG6n77TvExzuapvCP7WJ WB6ZQAHERBOY2j8e8bIGVXlw6Zhh4y2fILLML14EUao/WY6BFiGi+KXprtfP/GBPuePv 6C1cBC+BzLsECEgKeY1iUOZApvxVsCdc44CSirDk5vVyGbcfLKthVncYy1ziHGYoUHMH 1XrQ== X-Gm-Message-State: AHYfb5gHlk7S4I+LYrW4ES3auWpA4szndtkXwc2SsQGuAAVE9/G94Z9L cepJNsojSMAaH0He X-Received: by 10.84.231.204 with SMTP id g12mr6265443pln.131.1503562720157; Thu, 24 Aug 2017 01:18:40 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id v9sm7015493pgo.39.2017.08.24.01.18.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:39 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 07/14] asm-generic: add kexec_file_load system call to unistd.h Date: Thu, 24 Aug 2017 17:18:04 +0900 Message-Id: <20170824081811.19299-8-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The initial user of this system call number is arm64. Signed-off-by: AKASHI Takahiro Cc: Arnd Bergmann --- include/uapi/asm-generic/unistd.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) -- 2.14.1 Acked-by:Arnd Bergmann diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 061185a5eb51..086697fe3917 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -731,9 +731,11 @@ __SYSCALL(__NR_pkey_alloc, sys_pkey_alloc) __SYSCALL(__NR_pkey_free, sys_pkey_free) #define __NR_statx 291 __SYSCALL(__NR_statx, sys_statx) +#define __NR_kexec_file_load 292 +__SYSCALL(__NR_kexec_file_load, sys_kexec_file_load) #undef __NR_syscalls -#define __NR_syscalls 292 +#define __NR_syscalls 293 /* * All syscalls below here should go away really, From patchwork Thu Aug 24 08:18:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110876 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315399qge; Thu, 24 Aug 2017 01:19:07 -0700 (PDT) X-Received: by 10.99.174.6 with SMTP id q6mr5347872pgf.331.1503562747692; Thu, 24 Aug 2017 01:19:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562747; cv=none; d=google.com; s=arc-20160816; b=Vw3JFm+fzaJK3T66Cur58bX8J6pQs91jD8PZDsEI2KBefTlctv5eEbviQUjYl2LPCr 9fLJO6Mf6Kq4YAFD7a6cDCkBGVA2PGFzUj+QHLAkPdCVr8iD6LznndzBzDFGN3bSyGFY s6X61P8EmFfkco+7I5F3XGRuT8HvtHBH/pgFi+oDL2Iniuc4DiZQoRuD90w4U8CMEB6s qfzfL03Qg8eOeza/icm56prKi78NlVbCHuniaqnPl26oKxzFEe/vAqfjyFb1swQLXLuU rRI7riACV/CjC982k00MVGUJgbAuSVzi7BkzUVhzBMzhuNKjdNeOLXJcPbJ4hbjEs2hm 7v0A== 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=eQYwYlkVT/OpBbZqyLVQ8xMt5FVlB2XLU5cwIMjTWyo=; b=rEri5I/+vJy5P1cFkTJQJZiq+PgLAXX7iKSGIRffjhPPKug4QRB80LYO43dgtOAUyH WBELm/WyBjqpwhpoh/DKTNxR/d1udimu2TKVEitjffpehKj/bzvA68VMBDy0GJaSt7AS h6mB/JahOmHdY3UKwC7s+ShTSiwA+S+WLjdmKobEu2WNSox6LgReK1vjf7X2s/BTiHE7 JIce8qzRETMPiAxM4NYEkdf7JokppdsA1+fLmbCpZ6t7H2WoMsjN0l1pniAt/8Xoh+qF SgvqJHKa9UpfoA6nrh6pMrjrSddXI6LcTOz9HlrMPdNLdMZSyTkUhLmQka6O7AQ7A9t0 2u5Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=LqDt5R6l; 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 c124si2434964pfa.353.2017.08.24.01.19.07; Thu, 24 Aug 2017 01:19:07 -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 header.s=google header.b=LqDt5R6l; 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 S1751757AbdHXITG (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:06 -0400 Received: from mail-pg0-f46.google.com ([74.125.83.46]:37983 "EHLO mail-pg0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751475AbdHXISp (ORCPT ); Thu, 24 Aug 2017 04:18:45 -0400 Received: by mail-pg0-f46.google.com with SMTP id m133so13378538pga.5 for ; Thu, 24 Aug 2017 01:18:45 -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=eQYwYlkVT/OpBbZqyLVQ8xMt5FVlB2XLU5cwIMjTWyo=; b=LqDt5R6lyH/cgHG9exjQdpXi3YisIupJK85bOJe36xdlx7P8DnyiX9IVsRnykDkx0v T43GK/iK2X46F2o8cyTo1GQ5GlRwXjxG9hEv6CEHpb7WRp2OIATPefVq3teh6FrYdPuh DGXE1ei//CjvpuBuXWlUuC6u+wlAfsYL04qe4= 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=eQYwYlkVT/OpBbZqyLVQ8xMt5FVlB2XLU5cwIMjTWyo=; b=GWv8m/8zeBMJULQr0mAzuv8h77tGZJkGxOV1jrj4YjKCFZGunaAbqXbEu7wR8Uw3QL 0ZBkA+5dyu15TFWDid+D+eWE5A8duatPJFQdBYgHfzuDZLkR+GlKBHIgY/nqmLsoAOdn eUUHVMsGYx1Tq4j37xY7IeGMN+QbkUn3q04Vo/KfFEbvn0uNcu4NsOrq+n1p9m02Pz1f DfDpkOZd5by6h/lFsg+fb+hQ31Pui+Orlv1RmIaeD9Sq0GPKCh9jb0duNzU5MOzphYYR VfYlKG86cMDf4zMsjZnLXreWlpTefFr+EMR3DqKPg2aPBCZfF5a7RvyK25uXoJfzSXlD mtUA== X-Gm-Message-State: AHYfb5imryDCVpI/KIG2XdEKRlqfGcoWyHOkCoFQQyht8wTj8EZmJEer xgfpUaKHip3xGvgZ X-Received: by 10.101.85.7 with SMTP id f7mr5653123pgr.131.1503562724729; Thu, 24 Aug 2017 01:18:44 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id j6sm3023725pgn.43.2017.08.24.01.18.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:44 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 08/14] arm64: kexec_file: create purgatory Date: Thu, 24 Aug 2017 17:18:05 +0900 Message-Id: <20170824081811.19299-9-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-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 is a basic purgtory, or a kind of glue code between the two kernel, for arm64. We will later add a feature of verifying a digest check against loaded memory segments. arch_kexec_apply_relocations_add() is responsible for re-linking any relative symbols in purgatory. Please note that the purgatory is not an executable, but a non-linked archive of binaries so relative symbols contained here must be resolved at kexec load time. Despite that arm64_kernel_start and arm64_dtb_addr are only such global variables now, arch_kexec_apply_relocations_add() can manage more various types of relocations. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/Makefile | 1 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/machine_kexec_file.c | 199 +++++++++++++++++++++++++++++++++ arch/arm64/purgatory/Makefile | 24 ++++ arch/arm64/purgatory/entry.S | 28 +++++ 5 files changed, 253 insertions(+) create mode 100644 arch/arm64/kernel/machine_kexec_file.c create mode 100644 arch/arm64/purgatory/Makefile create mode 100644 arch/arm64/purgatory/entry.S -- 2.14.1 diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 9b41f1e3b1a0..429f60728c0a 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -105,6 +105,7 @@ core-$(CONFIG_XEN) += arch/arm64/xen/ core-$(CONFIG_CRYPTO) += arch/arm64/crypto/ libs-y := arch/arm64/lib/ $(libs-y) core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a +core-$(CONFIG_KEXEC_FILE) += arch/arm64/purgatory/ # Default target when executing plain make boot := arch/arm64/boot diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index f2b4e816b6de..16e9f56b536a 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -50,6 +50,7 @@ arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ cpu-reset.o +arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c new file mode 100644 index 000000000000..183f7776d6dd --- /dev/null +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -0,0 +1,199 @@ +/* + * kexec_file for arm64 + * + * Copyright (C) 2017 Linaro Limited + * Author: AKASHI Takahiro + * + * Most code is derived from arm64 port of kexec-tools + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "kexec_file: " fmt + +#include +#include +#include +#include +#include + +/* + * Apply purgatory relocations. + * + * ehdr: Pointer to elf headers + * sechdrs: Pointer to section headers. + * relsec: section index of SHT_RELA section. + * + * Note: + * Currently R_AARCH64_ABS64, R_AARCH64_LD_PREL_LO19 and R_AARCH64_CALL26 + * are the only types to be generated from purgatory code. + * If we add more functionalities, other types may also be used. + */ +int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, + Elf64_Shdr *sechdrs, unsigned int relsec) +{ + Elf64_Rela *rel; + Elf64_Shdr *section, *symtabsec; + Elf64_Sym *sym; + const char *strtab, *name, *shstrtab; + unsigned long address, sec_base, value; + void *location; + u64 *loc64; + u32 *loc32, imm; + unsigned int i; + + /* + * ->sh_offset has been modified to keep the pointer to section + * contents in memory + */ + rel = (void *)sechdrs[relsec].sh_offset; + + /* Section to which relocations apply */ + section = &sechdrs[sechdrs[relsec].sh_info]; + + pr_debug("reloc: Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + /* Associated symbol table */ + symtabsec = &sechdrs[sechdrs[relsec].sh_link]; + + /* String table */ + if (symtabsec->sh_link >= ehdr->e_shnum) { + /* Invalid strtab section number */ + pr_err("reloc: Invalid string table section index %d\n", + symtabsec->sh_link); + return -ENOEXEC; + } + + strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset; + + /* section header string table */ + shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset; + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + + /* + * rel[i].r_offset contains byte offset from beginning + * of section to the storage unit affected. + * + * This is location to update (->sh_offset). This is temporary + * buffer where section is currently loaded. This will finally + * be loaded to a different address later, pointed to by + * ->sh_addr. kexec takes care of moving it + * (kexec_load_segment()). + */ + location = (void *)(section->sh_offset + rel[i].r_offset); + + /* Final address of the location */ + address = section->sh_addr + rel[i].r_offset; + + /* + * rel[i].r_info contains information about symbol table index + * w.r.t which relocation must be made and type of relocation + * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get + * these respectively. + */ + sym = (Elf64_Sym *)symtabsec->sh_offset + + ELF64_R_SYM(rel[i].r_info); + + if (sym->st_name) + name = strtab + sym->st_name; + else + name = shstrtab + sechdrs[sym->st_shndx].sh_name; + + pr_debug("Symbol: %-16s info: %02x shndx: %02x value=%llx size: %llx reloc type:%d\n", + name, sym->st_info, sym->st_shndx, sym->st_value, + sym->st_size, (int)ELF64_R_TYPE(rel[i].r_info)); + + if (sym->st_shndx == SHN_UNDEF) { + pr_err("reloc: Undefined symbol: %s\n", name); + return -ENOEXEC; + } + + if (sym->st_shndx == SHN_COMMON) { + pr_err("reloc: symbol '%s' in common section\n", name); + return -ENOEXEC; + } + + if (sym->st_shndx == SHN_ABS) { + sec_base = 0; + } else if (sym->st_shndx < ehdr->e_shnum) { + sec_base = sechdrs[sym->st_shndx].sh_addr; + } else { + pr_err("reloc: Invalid section %d for symbol %s\n", + sym->st_shndx, name); + return -ENOEXEC; + } + + value = sym->st_value; + value += sec_base; + value += rel[i].r_addend; + + switch (ELF64_R_TYPE(rel[i].r_info)) { + case R_AARCH64_ABS64: + loc64 = location; + *loc64 = cpu_to_elf64(ehdr, + elf64_to_cpu(ehdr, *loc64) + value); + break; + case R_AARCH64_PREL32: + loc32 = location; + *loc32 = cpu_to_elf32(ehdr, + elf32_to_cpu(ehdr, *loc32) + value + - address); + break; + case R_AARCH64_LD_PREL_LO19: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) << 3) & 0xffffe0)); + break; + case R_AARCH64_ADR_PREL_LO21: + if (value & 3) { + pr_err("reloc: Unaligned value: %lx\n", value); + return -ENOEXEC; + } + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) << 3) & 0xffffe0)); + break; + case R_AARCH64_ADR_PREL_PG_HI21: + imm = ((value & ~0xfff) - (address & ~0xfff)) >> 12; + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + ((imm & 3) << 29) + + ((imm & 0x1ffffc) << (5 - 2))); + break; + case R_AARCH64_ADD_ABS_LO12_NC: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + ((value & 0xfff) << 10)); + break; + case R_AARCH64_JUMP26: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) >> 2) & 0x3ffffff)); + break; + case R_AARCH64_CALL26: + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + (((value - address) >> 2) & 0x3ffffff)); + break; + case R_AARCH64_LDST64_ABS_LO12_NC: + if (value & 7) { + pr_err("reloc: Unaligned value: %lx\n", value); + return -ENOEXEC; + } + loc32 = location; + *loc32 = cpu_to_le32(le32_to_cpu(*loc32) + + ((value & 0xff8) << (10 - 3))); + break; + default: + pr_err("reloc: Unknown relocation type: %llu\n", + ELF64_R_TYPE(rel[i].r_info)); + return -ENOEXEC; + } + } + + return 0; +} diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile new file mode 100644 index 000000000000..c2127a2cbd51 --- /dev/null +++ b/arch/arm64/purgatory/Makefile @@ -0,0 +1,24 @@ +OBJECT_FILES_NON_STANDARD := y + +purgatory-y := entry.o + +targets += $(purgatory-y) +PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) + +LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \ + -nostdlib -z nodefaultlib +targets += purgatory.ro + +$(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE + $(call if_changed,ld) + +targets += kexec_purgatory.c + +CMD_BIN2C = $(objtree)/scripts/basic/bin2c +quiet_cmd_bin2c = BIN2C $@ + cmd_bin2c = $(CMD_BIN2C) kexec_purgatory < $< > $@ + +$(obj)/kexec_purgatory.c: $(obj)/purgatory.ro FORCE + $(call if_changed,bin2c) + +obj-${CONFIG_KEXEC_FILE} += kexec_purgatory.o diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S new file mode 100644 index 000000000000..bc4e6b3bf8a1 --- /dev/null +++ b/arch/arm64/purgatory/entry.S @@ -0,0 +1,28 @@ +/* + * kexec core purgatory + */ +#include + +.text + +ENTRY(purgatory_start) + /* Start new image. */ + ldr x17, arm64_kernel_entry + ldr x0, arm64_dtb_addr + mov x1, xzr + mov x2, xzr + mov x3, xzr + br x17 +END(purgatory_start) + +.data + +.align 3 + +ENTRY(arm64_kernel_entry) + .quad 0 +END(arm64_kernel_entry) + +ENTRY(arm64_dtb_addr) + .quad 0 +END(arm64_dtb_addr) From patchwork Thu Aug 24 08:18: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: 110888 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5321276qge; Thu, 24 Aug 2017 01:25:20 -0700 (PDT) X-Received: by 10.84.232.11 with SMTP id h11mr6276669plk.126.1503563120557; Thu, 24 Aug 2017 01:25:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503563120; cv=none; d=google.com; s=arc-20160816; b=t3oc5/mJeaukUT1nIlN5p6As3H00VWbPfha+7DuMRolEVT5qsWAr16XwQlWBFGQBTb j1zTJAf3TWGXIA+m/YxK+WHeWGJTahF/Fk4tGl4RLED7RlmnmfwjLoBPmbil4Eyrlr1o OBDFyY7PVb5hfeTXxSevptq4Q0dbrwwVzLJ1JaKbVVE8L0zG0rf6yZhUWf4UqbOfuuvU 5qk7nTTTYkDaduOWlONmnymxTRZLJZRAhph4psf/ERbp3V5XZdM/lGHPsM97Z8iaq6es 0TnTQ341S04xG5n2JpaEY86qLfBN5jk8aYLNEs2a49xlHXZN3dAAcmpF12KTLIiXkLS1 1r8A== 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=mRBcSxdmyk/0X4RhkEisw7WceyZiGDUl+28BUWc39r8=; b=uVZInd7bgLAA8FDynSLPXjtM2GGWmoTUcjTaEGd8kptIe9wbqtx+4L0l8/olNHP/eC mQtnV8e8N4ObAkPNQDKH2VjE31QT/szEqfua9dR3mXV+SdYGpca9No36soGaefdbNezg Z7LpiCDstO8hcLezgV3UmYXExJXN8IuPtKTUAZXhXZ90NdSFipgQUlKD+1AvRYzWm8DB Yusjxm9r1dm5ArOlPjlDU4MfK9jS9w4itsS3tegmvvXnbrjiV63qzenqmVnCMnbUN6uX rnFpQKUouhGIfIijzTFIKzda+VIOqd4eHRGe30V7dyFh3cg5ENRxKzFL96G6gxgSegR7 HnZQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=X6YV4sMf; 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 b14si2271006pga.562.2017.08.24.01.25.20; Thu, 24 Aug 2017 01:25:20 -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 header.s=google header.b=X6YV4sMf; 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 S1751693AbdHXITE (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:04 -0400 Received: from mail-pg0-f47.google.com ([74.125.83.47]:33909 "EHLO mail-pg0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751484AbdHXISu (ORCPT ); Thu, 24 Aug 2017 04:18:50 -0400 Received: by mail-pg0-f47.google.com with SMTP id s14so13473498pgs.1 for ; Thu, 24 Aug 2017 01:18:50 -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=mRBcSxdmyk/0X4RhkEisw7WceyZiGDUl+28BUWc39r8=; b=X6YV4sMfHWPqW8A90Xl/xIDYet4Q5Tbp95XIJG6oPWf1kEQA7sd1W57b2lIJeMxhrL eJyrusL5EOC4s/X0DwUbWdPuarEcbynt6+Hs7Gi8rtqUjFUvXZ2L3qNekHchHLVyfegS u6l3/5wLtcJxR2RBwKEvWrW6L+IBBVDNkSxp0= 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=mRBcSxdmyk/0X4RhkEisw7WceyZiGDUl+28BUWc39r8=; b=LGNuYQZGhMNvTbZWW6cvslQ4JidNRPqacTz/5QrPCbc7oMDdfBqku4PA2DBntlTC+O 6iz7lQouNVg+pplSLXU6eWYQF3ZIQin8b/WJD+o7GTzX+bFmY3ZQzuw7+ovACMqOGLiW gI6VYgkEs79AsUiUK0wP6MvajBeNW7crectZ04Ut9aSH9ZKyT3KoHRVmpWjUofTYbUP0 mNhxuw1uaucAD8J1rWVOwI19MG9MNb7MoEN8nQwNYrOHAugsu8evhQnpID8ak0lYC+Yf JaJ6LithuueDQkSO1msEwIEzMdIxKH03UZ5yp+cMsc4jqo0xgkWaYtElYNpDxC8Ac//L KYHQ== X-Gm-Message-State: AHYfb5inkZwGacYLjxkpCfTsNt/gpZECTpABJ+kGnqMVJhHVbLJOMYaA XkLoQnLcxxwxNBUL X-Received: by 10.99.117.68 with SMTP id f4mr5334183pgn.379.1503562729689; Thu, 24 Aug 2017 01:18:49 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id b7sm5872694pgr.11.2017.08.24.01.18.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:49 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 09/14] arm64: kexec_file: add sha256 digest check in purgatory Date: Thu, 24 Aug 2017 17:18:06 +0900 Message-Id: <20170824081811.19299-10-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Most of sha256 code is based on crypto/sha256-glue.c, particularly using non-neon version. Please note that we won't be able to re-use lib/mem*.S for purgatory because unaligned memory access is not allowed in purgatory where mmu is turned off. Since purgatory is not linked with the other part of kernel, care must be taken of selecting an appropriate set of compiler options in order to prevent undefined symbol references from being generated. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon Cc: Ard Biesheuvel --- arch/arm64/crypto/sha256-core.S_shipped | 2 + arch/arm64/purgatory/Makefile | 21 ++++++++- arch/arm64/purgatory/entry.S | 13 ++++++ arch/arm64/purgatory/purgatory.c | 20 +++++++++ arch/arm64/purgatory/sha256-core.S | 1 + arch/arm64/purgatory/sha256.c | 79 +++++++++++++++++++++++++++++++++ arch/arm64/purgatory/sha256.h | 1 + arch/arm64/purgatory/string.c | 32 +++++++++++++ arch/arm64/purgatory/string.h | 5 +++ 9 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/purgatory/purgatory.c create mode 100644 arch/arm64/purgatory/sha256-core.S create mode 100644 arch/arm64/purgatory/sha256.c create mode 100644 arch/arm64/purgatory/sha256.h create mode 100644 arch/arm64/purgatory/string.c create mode 100644 arch/arm64/purgatory/string.h -- 2.14.1 diff --git a/arch/arm64/crypto/sha256-core.S_shipped b/arch/arm64/crypto/sha256-core.S_shipped index 3ce82cc860bc..9ce7419c9152 100644 --- a/arch/arm64/crypto/sha256-core.S_shipped +++ b/arch/arm64/crypto/sha256-core.S_shipped @@ -1210,6 +1210,7 @@ sha256_block_armv8: ret .size sha256_block_armv8,.-sha256_block_armv8 #endif +#ifndef __PURGATORY__ #ifdef __KERNEL__ .globl sha256_block_neon #endif @@ -2056,6 +2057,7 @@ sha256_block_neon: add sp,sp,#16*4+16 ret .size sha256_block_neon,.-sha256_block_neon +#endif #ifndef __KERNEL__ .comm OPENSSL_armcap_P,4,4 #endif diff --git a/arch/arm64/purgatory/Makefile b/arch/arm64/purgatory/Makefile index c2127a2cbd51..d9b38be31e0a 100644 --- a/arch/arm64/purgatory/Makefile +++ b/arch/arm64/purgatory/Makefile @@ -1,14 +1,33 @@ OBJECT_FILES_NON_STANDARD := y -purgatory-y := entry.o +purgatory-y := entry.o purgatory.o sha256.o sha256-core.o string.o targets += $(purgatory-y) PURGATORY_OBJS = $(addprefix $(obj)/,$(purgatory-y)) +# Purgatory is expected to be ET_REL, not an executable LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined \ -nostdlib -z nodefaultlib + targets += purgatory.ro +GCOV_PROFILE := n +KASAN_SANITIZE := n +KCOV_INSTRUMENT := n + +# Some kernel configurations may generate additional code containing +# undefined symbols, like _mcount for ftrace and __stack_chk_guard +# for stack-protector. Those should be removed from purgatory. + +CFLAGS_REMOVE_purgatory.o = -pg +CFLAGS_REMOVE_sha256.o = -pg +CFLAGS_REMOVE_string.o = -pg + +NO_PROTECTOR := $(call cc-option, -fno-stack-protector) +KBUILD_CFLAGS += $(NO_PROTECTOR) + +KBUILD_AFLAGS += -D__PURGATORY__ + $(obj)/purgatory.ro: $(PURGATORY_OBJS) FORCE $(call if_changed,ld) diff --git a/arch/arm64/purgatory/entry.S b/arch/arm64/purgatory/entry.S index bc4e6b3bf8a1..74d028b838bd 100644 --- a/arch/arm64/purgatory/entry.S +++ b/arch/arm64/purgatory/entry.S @@ -6,6 +6,11 @@ .text ENTRY(purgatory_start) + adr x19, .Lstack + mov sp, x19 + + bl purgatory + /* Start new image. */ ldr x17, arm64_kernel_entry ldr x0, arm64_dtb_addr @@ -15,6 +20,14 @@ ENTRY(purgatory_start) br x17 END(purgatory_start) +.ltorg + +.align 4 + .rept 256 + .quad 0 + .endr +.Lstack: + .data .align 3 diff --git a/arch/arm64/purgatory/purgatory.c b/arch/arm64/purgatory/purgatory.c new file mode 100644 index 000000000000..7fcbefa786bc --- /dev/null +++ b/arch/arm64/purgatory/purgatory.c @@ -0,0 +1,20 @@ +/* + * purgatory: Runs between two kernels + * + * Copyright (c) 2017 Linaro Limited + * Author: AKASHI Takahiro + */ + +#include "sha256.h" + +void purgatory(void) +{ + int ret; + + ret = verify_sha256_digest(); + if (ret) { + /* loop forever */ + for (;;) + ; + } +} diff --git a/arch/arm64/purgatory/sha256-core.S b/arch/arm64/purgatory/sha256-core.S new file mode 100644 index 000000000000..24f5ce25b61e --- /dev/null +++ b/arch/arm64/purgatory/sha256-core.S @@ -0,0 +1 @@ +#include "../crypto/sha256-core.S_shipped" diff --git a/arch/arm64/purgatory/sha256.c b/arch/arm64/purgatory/sha256.c new file mode 100644 index 000000000000..5d20d81767e3 --- /dev/null +++ b/arch/arm64/purgatory/sha256.c @@ -0,0 +1,79 @@ +#include +#include +#include + +/* + * Under KASAN, those are defined as un-instrumented version, __memxxx() + */ +#undef memcmp +#undef memcpy +#undef memset + +#include "string.h" +#include +#include +#include + +u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory); +struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX] + __section(.kexec-purgatory); + +asmlinkage void sha256_block_data_order(u32 *digest, const void *data, + unsigned int num_blks); + +static int sha256_init(struct shash_desc *desc) +{ + return sha256_base_init(desc); +} + +static int sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + return sha256_base_do_update(desc, data, len, + (sha256_block_fn *)sha256_block_data_order); +} + +static int __sha256_base_finish(struct shash_desc *desc, u8 *out) +{ + /* we can't do crypto_shash_digestsize(desc->tfm) */ + unsigned int digest_size = 32; + struct sha256_state *sctx = shash_desc_ctx(desc); + __be32 *digest = (__be32 *)out; + int i; + + for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be32)) + put_unaligned_be32(sctx->state[i], digest++); + + *sctx = (struct sha256_state){}; + return 0; +} + +static int sha256_final(struct shash_desc *desc, u8 *out) +{ + sha256_base_do_finalize(desc, + (sha256_block_fn *)sha256_block_data_order); + + return __sha256_base_finish(desc, out); +} + +int verify_sha256_digest(void) +{ + char __sha256_desc[sizeof(struct shash_desc) + + sizeof(struct sha256_state)] CRYPTO_MINALIGN_ATTR; + struct shash_desc *desc = (struct shash_desc *)__sha256_desc; + struct kexec_sha_region *ptr, *end; + u8 digest[SHA256_DIGEST_SIZE]; + + sha256_init(desc); + + end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions); + for (ptr = purgatory_sha_regions; ptr < end; ptr++) + sha256_update(desc, (uint8_t *)(ptr->start), ptr->len); + + sha256_final(desc, digest); + + if (memcmp(digest, purgatory_sha256_digest, sizeof(digest))) + return 1; + + return 0; +} diff --git a/arch/arm64/purgatory/sha256.h b/arch/arm64/purgatory/sha256.h new file mode 100644 index 000000000000..54dc3c33c469 --- /dev/null +++ b/arch/arm64/purgatory/sha256.h @@ -0,0 +1 @@ +extern int verify_sha256_digest(void); diff --git a/arch/arm64/purgatory/string.c b/arch/arm64/purgatory/string.c new file mode 100644 index 000000000000..33233a210a65 --- /dev/null +++ b/arch/arm64/purgatory/string.c @@ -0,0 +1,32 @@ +#include + +void *memcpy(void *dst, const void *src, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + ((u8 *)dst)[i] = ((u8 *)src)[i]; + + return NULL; +} + +void *memset(void *dst, int c, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + ((u8 *)dst)[i] = (u8)c; + + return NULL; +} + +int memcmp(const void *src, const void *dst, size_t len) +{ + int i; + + for (i = 0; i < len; i++) + if (*(char *)src != *(char *)dst) + return 1; + + return 0; +} diff --git a/arch/arm64/purgatory/string.h b/arch/arm64/purgatory/string.h new file mode 100644 index 000000000000..cb5f68dd84ef --- /dev/null +++ b/arch/arm64/purgatory/string.h @@ -0,0 +1,5 @@ +#include + +int memcmp(const void *s1, const void *s2, size_t len); +void *memcpy(void *dst, const void *src, size_t len); +void *memset(void *dst, int c, size_t len); From patchwork Thu Aug 24 08:18: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: 110875 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315343qge; Thu, 24 Aug 2017 01:19:04 -0700 (PDT) X-Received: by 10.101.89.69 with SMTP id g5mr5505907pgu.270.1503562744879; Thu, 24 Aug 2017 01:19:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562744; cv=none; d=google.com; s=arc-20160816; b=MRZ6mgyc63rNZuMx8N2JSpXVU4Tz2aKKrh8zVq9huvUNaY5EqwreuzdF5Ibilges0t UKgWsgWQ+wVx9eJyh5mJ4BazHM48d3QbbLfq7BA/ao8fG+yOgz+qBBz6JMK0ds4jTh8i kY5hJXNELUSdb4sIB1s1aKtbJWOgB1fXqhsjppBSqCHmOnqIEzbQQ8nfIreQ+/bzJoaZ pq86mUDOcpCv2qcBN4APgf5bRqou1ptzI6qXbTty5hV42Yszy1/tmFSsVI0ksh8SI0HK e1PjdqW+NemkeZz2kL/NBGowC7EEEkzvOaws0gQtogwZOleyKPsWHZHvGuwp6EunhCXv G4Yg== 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=uqKoSDMIWbaLWAO0eT8my6xMoFpoIw7wvO568M5PEzQ=; b=Cj1t9Hu1KBYAVFIohwj9yqSOQfrt6yaUlBMluDtm1H2bpRTLJM+BLTGcDtYzxos06L J6eU+CxjZznlu5qmdchg2IJtC55rcD0JDcAaFCzKhWZ0lb77OLcSMCH4FPkJG84yfihb BgrBjLL2hMlTZU6Ka53NofNwlZVsWKuEX2G4RxaekxnUS8jp8cmAMV8aAMt2OBWjgrzu CgogXq+QIApW0HQVepyBturgi+ieqc8QZNH0Ih4GBk2w6OMNdUtKk2QQDjESjLSxiNzq iX7qCsDjzzUzDCvMyuW1P33/kBMTy6L3wfV4pQRuOMrA/10+TBuX2Xg9DDms38X5oPFR iuig== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=RatDrfJi; 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 c124si2434964pfa.353.2017.08.24.01.19.04; Thu, 24 Aug 2017 01:19:04 -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 header.s=google header.b=RatDrfJi; 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 S1751632AbdHXITB (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:01 -0400 Received: from mail-pg0-f41.google.com ([74.125.83.41]:37885 "EHLO mail-pg0-f41.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751519AbdHXIS7 (ORCPT ); Thu, 24 Aug 2017 04:18:59 -0400 Received: by mail-pg0-f41.google.com with SMTP id y129so13400384pgy.4 for ; Thu, 24 Aug 2017 01:18:58 -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=uqKoSDMIWbaLWAO0eT8my6xMoFpoIw7wvO568M5PEzQ=; b=RatDrfJig5BBfZUGDyjcqZKbjh6DdUbith6Q2L3vzE8n/MSJjTYxVgax1FVegG6z4l My9x9KNZxeMLy+lKSVxK9sc6kPW1sz3Ked6cQlxKD4RU4o33mbpUQ8r8ITIfTC6dPvMf M8XaurM+7/VNKmant3xIXP3IQ7ZcDxBWCgyeQ= 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=uqKoSDMIWbaLWAO0eT8my6xMoFpoIw7wvO568M5PEzQ=; b=dCzTjbletHLP6fqPyO8MUHrt/NLw1iQecJ9VB57+SrR1DLCsMonAuQbX6Pe479a4j+ gV/3Tv83pe+WzsT9nrzrCSBubV1smn3534qfjGlDj9PQIofUvSeNIAZF+o6v2qYAMiFQ /K0tBrjRLdmOa0fcKp8fcJJS3Hkk2qHoG+mXDPXCUbsDWE6KvDlLBimi75mo6ojLSbv4 enSv0QpSnu6rlktMSdaVJXgnnLVyBvj1TZ7ee8NEFnsFT9FJ6pX+rb1DZ1SY0Qd5cCxk E7+2e6NWy615kaaYmQrqhjrKi/Ws6XXa0ezcPrjWZjLZHCGP9ID9vZbj4/BoEjJtfHHT 5hiw== X-Gm-Message-State: AHYfb5iYuSIZooPv4fwLjmaP91iCMDftpjJ3olb05ufRrPcJROeqauHD JwAtjIfNQXh6Xa1y X-Received: by 10.99.179.78 with SMTP id x14mr3738135pgt.284.1503562738478; Thu, 24 Aug 2017 01:18:58 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id i187sm6907227pfe.67.2017.08.24.01.18.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:18:58 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 10/14] arm64: kexec_file: load initrd, device-tree and purgatory segments Date: Thu, 24 Aug 2017 17:18:07 +0900 Message-Id: <20170824081811.19299-11-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org load_other_segments() sets up and adds all the memory segments necessary other than kernel, including initrd, device-tree blob and purgatory. Most of the code was borrowed from kexec-tools' counterpart. In addition, arch_kexec_image_probe(), arch_kexec_image_load() and arch_kexec_kernel_verify_sig() are stubs for supporting multiple types of kernel image formats. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/include/asm/kexec.h | 18 +++ arch/arm64/kernel/machine_kexec_file.c | 255 +++++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) -- 2.14.1 diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h index e17f0529a882..ebc4aaa707ae 100644 --- a/arch/arm64/include/asm/kexec.h +++ b/arch/arm64/include/asm/kexec.h @@ -93,6 +93,24 @@ static inline void crash_prepare_suspend(void) {} static inline void crash_post_resume(void) {} #endif +#ifdef CONFIG_KEXEC_FILE +#define ARCH_HAS_KIMAGE_ARCH + +struct kimage_arch { + void *dtb_buf; +}; + +struct kimage; +extern int setup_dtb(struct kimage *image, + unsigned long initrd_load_addr, unsigned long initrd_len, + char *cmdline, unsigned long cmdline_len, + char **dtb_buf, size_t *dtb_buf_len); +extern int load_other_segments(struct kimage *image, + unsigned long kernel_load_addr, + char *initrd, unsigned long initrd_len, + char *cmdline, unsigned long cmdline_len); +#endif + #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index 183f7776d6dd..cd12e451e474 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -16,8 +16,78 @@ #include #include #include +#include +#include +#include +#include #include #include +#include + +static int __dt_root_addr_cells; +static int __dt_root_size_cells; + +static struct kexec_file_ops *kexec_file_loaders[0]; + +int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, + unsigned long buf_len) +{ + struct kexec_file_ops *fops; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(kexec_file_loaders); i++) { + fops = kexec_file_loaders[i]; + if (!fops || !fops->probe) + continue; + + ret = fops->probe(buf, buf_len); + if (!ret) { + image->fops = fops; + return 0; + } + } + + return -ENOEXEC; +} + +void *arch_kexec_kernel_image_load(struct kimage *image) +{ + if (!image->fops || !image->fops->load) + return ERR_PTR(-ENOEXEC); + + return image->fops->load(image, image->kernel_buf, + image->kernel_buf_len, image->initrd_buf, + image->initrd_buf_len, image->cmdline_buf, + image->cmdline_buf_len); +} + +int arch_kimage_file_post_load_cleanup(struct kimage *image) +{ + vfree(image->arch.dtb_buf); + image->arch.dtb_buf = NULL; + + vfree(image->arch.elf_headers); + image->arch.elf_headers = NULL; + image->arch.elf_headers_sz = 0; + + if (!image->fops || !image->fops->cleanup) + return 0; + + return image->fops->cleanup(image->image_loader_data); +} + +#ifdef CONFIG_KEXEC_VERIFY_SIG +int arch_kexec_kernel_verify_sig(struct kimage *image, void *kernel, + unsigned long kernel_len) +{ + if (!image->fops || !image->fops->verify_sig) { + pr_debug("kernel loader does not support signature verification.\n"); + return -EKEYREJECTED; + } + + return image->fops->verify_sig(kernel, kernel_len); +} +#endif /* * Apply purgatory relocations. @@ -197,3 +267,188 @@ int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, return 0; } + +int arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *)) +{ + if (kbuf->image->type == KEXEC_TYPE_CRASH) + return walk_iomem_res_desc(crashk_res.desc, + IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY, + crashk_res.start, crashk_res.end, + kbuf, func); + else if (kbuf->top_down) + return walk_system_ram_res_rev(0, ULONG_MAX, kbuf, func); + else + return walk_system_ram_res(0, ULONG_MAX, kbuf, func); +} + +int setup_dtb(struct kimage *image, + unsigned long initrd_load_addr, unsigned long initrd_len, + char *cmdline, unsigned long cmdline_len, + char **dtb_buf, size_t *dtb_buf_len) +{ + char *buf = NULL; + size_t buf_size; + int nodeoffset; + u64 value; + int range_len; + int ret; + + /* duplicate dt blob */ + buf_size = fdt_totalsize(initial_boot_params); + range_len = (__dt_root_addr_cells + __dt_root_size_cells) * sizeof(u32); + + if (initrd_load_addr) + buf_size += fdt_prop_len("initrd-start", sizeof(u64)) + + fdt_prop_len("initrd-end", sizeof(u64)); + + if (cmdline) + buf_size += fdt_prop_len("bootargs", cmdline_len + 1); + + buf = vmalloc(buf_size); + if (!buf) { + ret = -ENOMEM; + goto out_err; + } + + ret = fdt_open_into(initial_boot_params, buf, buf_size); + if (ret) + goto out_err; + + nodeoffset = fdt_path_offset(buf, "/chosen"); + if (nodeoffset < 0) + goto out_err; + + /* add bootargs */ + if (cmdline) { + ret = fdt_setprop(buf, nodeoffset, "bootargs", + cmdline, cmdline_len + 1); + if (ret) + goto out_err; + } + + /* add initrd-* */ + if (initrd_load_addr) { + value = cpu_to_fdt64(initrd_load_addr); + ret = fdt_setprop(buf, nodeoffset, "initrd-start", + &value, sizeof(value)); + if (ret) + goto out_err; + + value = cpu_to_fdt64(initrd_load_addr + initrd_len); + ret = fdt_setprop(buf, nodeoffset, "initrd-end", + &value, sizeof(value)); + if (ret) + goto out_err; + } + + /* trim a buffer */ + fdt_pack(buf); + *dtb_buf = buf; + *dtb_buf_len = fdt_totalsize(buf); + + return 0; + +out_err: + vfree(buf); + return ret; +} + +int load_other_segments(struct kimage *image, unsigned long kernel_load_addr, + char *initrd, unsigned long initrd_len, + char *cmdline, unsigned long cmdline_len) +{ + struct kexec_buf kbuf; + unsigned long initrd_load_addr = 0; + unsigned long purgatory_load_addr, dtb_load_addr; + char *dtb = NULL; + unsigned long dtb_len; + int ret = 0; + + kbuf.image = image; + + /* Load initrd */ + if (initrd) { + kbuf.buffer = initrd; + kbuf.bufsz = initrd_len; + kbuf.memsz = initrd_len; + kbuf.buf_align = PAGE_SIZE; + /* within 1GB-aligned window of up to 32GB in size */ + kbuf.buf_min = kernel_load_addr; + kbuf.buf_max = round_down(kernel_load_addr, SZ_1G) + + (unsigned long)SZ_1G * 31; + kbuf.top_down = 0; + + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out_err; + initrd_load_addr = kbuf.mem; + + pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + initrd_load_addr, initrd_len, initrd_len); + } + + /* Load dtb blob */ + ret = setup_dtb(image, initrd_load_addr, initrd_len, + cmdline, cmdline_len, &dtb, &dtb_len); + if (ret) { + pr_err("Preparing for new dtb failed\n"); + goto out_err; + } + + kbuf.buffer = dtb; + kbuf.bufsz = dtb_len; + kbuf.memsz = dtb_len; + /* not across 2MB boundary */ + kbuf.buf_align = SZ_2M; + /* + * Note for backporting: + * On kernel prior to v4.2, fdt must reside within 512MB block + * where the kernel also resides. So + * kbuf.buf_min = round_down(kernel_load_addr, SZ_512M); + * kbuf.buf_max = round_up(kernel_load_addr, SZ_512M); + * would be required. + */ + kbuf.buf_min = kernel_load_addr; + kbuf.buf_max = ULONG_MAX; + kbuf.top_down = 1; + + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out_err; + dtb_load_addr = kbuf.mem; + image->arch.dtb_buf = dtb; + + pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + dtb_load_addr, dtb_len, dtb_len); + + /* Load purgatory */ + ret = kexec_load_purgatory(image, kernel_load_addr, ULONG_MAX, 1, + &purgatory_load_addr); + if (ret) { + pr_err("Loading purgatory failed\n"); + goto out_err; + } + + ret = kexec_purgatory_get_set_symbol(image, "arm64_kernel_entry", + &kernel_load_addr, sizeof(kernel_load_addr), 0); + if (ret) { + pr_err("Relocating symbol (arm64_kernel_entry) failed.\n"); + goto out_err; + } + + ret = kexec_purgatory_get_set_symbol(image, "arm64_dtb_addr", + &dtb_load_addr, sizeof(dtb_load_addr), 0); + if (ret) { + pr_err("Relocating symbol (arm64_dtb_addr) failed.\n"); + goto out_err; + } + + pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); + + return 0; + +out_err: + vfree(dtb); + image->arch.dtb_buf = NULL; + return ret; +} From patchwork Thu Aug 24 08:18: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: 110889 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5321326qge; Thu, 24 Aug 2017 01:25:24 -0700 (PDT) X-Received: by 10.84.232.137 with SMTP id i9mr6245342plk.240.1503563124589; Thu, 24 Aug 2017 01:25:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503563124; cv=none; d=google.com; s=arc-20160816; b=pi2N3LMxiQDmTdxwYqI0jvJdoOp4S+c1z+0I64lCFuB1X92AYfJdRRsVpp9rvh8mMK b+kNJSNDK6dr5h1JlDdxdpuiISaO6TF/fsJ3Io9ZrxZPs+QCkHGOtzcmljq58lds75a3 +BzbOCNtwr4U0tIejciaR1RNhxqMvNzZV0W/oVjCr+7j+lPK3TIUlA3P8N0mu4KPHwkI gkqVO1A+KOAf8hvZcLCH5LvRsObxnXgXnhO/ya/RVYV9W69PNyFbf9H9/g6RUQFkVYtN HqHKRvRjUcE6OXuQSgEe1gtw9QKQUlSrz8OiT5VTj84iN6Juj/zwjim3cJc0hFuq4Hze ET1g== 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=5ObHuYfLHgQhQMhvEhRdQESvV4pllmIw9h/uQrBNm+o=; b=NifQP5nI90NH5FJkPi0g/jp0zX3rmMQnmruJsqNTcjakut8RqwW9lTG0/HV0sBkf+K U3ZzWJZ3bFH/p7OacBDTj4ucT+jf6093QYod1caHaiyyOVATXFzg9i1TlV/723uZ9xUR e9TmJZ7XZH4qxwUmwQ2+dU8X1ZFuVOWHxq7piC967DSsgogMtBqyp0JvPkFrnoR4JGTa oaUAkzniOBHCn3sJLkbBtPNwz19cl7rJkj3IvsRYD4DTzjOGlCOvkirt6q8qsW1NKxdg W+r3BEfUZwZiBD5Na2J+GCBF1D6VXruuDz0lEP849xcK6vpjYfJ8R02pJpDRIg05VzNH oM5g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=im8Qioyh; 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 b14si2271006pga.562.2017.08.24.01.25.24; Thu, 24 Aug 2017 01:25:24 -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 header.s=google header.b=im8Qioyh; 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 S1752443AbdHXIZU (ORCPT + 26 others); Thu, 24 Aug 2017 04:25:20 -0400 Received: from mail-pg0-f44.google.com ([74.125.83.44]:36030 "EHLO mail-pg0-f44.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751484AbdHXITE (ORCPT ); Thu, 24 Aug 2017 04:19:04 -0400 Received: by mail-pg0-f44.google.com with SMTP id 83so13455830pgb.3 for ; Thu, 24 Aug 2017 01:19:04 -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=5ObHuYfLHgQhQMhvEhRdQESvV4pllmIw9h/uQrBNm+o=; b=im8Qioyhfr8JYgzVEV0n0vSkBLL+jpmuLUhiyfJ4KTOnDEqY+x3A1ayuw0mHVR7ZT9 x5bZeKRYV6V5eNCNqRhMGivk7fmzprFiPdYaQAJZNDVHb/M3bss1t7MVHYk/7uMHf4C3 i/ZT5RJzjWlRtXU8DbBHd5bL5DQ1XitxYoUag= 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=5ObHuYfLHgQhQMhvEhRdQESvV4pllmIw9h/uQrBNm+o=; b=qUh+f22QUFe8k5liE8908LZAKEMFIGvwgHoQJ61d3e74DPiohg/4vdfjOrciPw/QJU gP0dFWbMvDhzFzF1l5eK9YQ+pS0tIEbZuU4j1BUkWed1GIekUXu1hiX3BPhDxRznv2G9 fVG1bPMm6nkFGAUXiBuCsv63pCjGbi912DulnGEOGzXH6Vrzm3WikPi++YHbZYo/AWX4 VmWKRIbqoNZ3Rpvu29unCxeUWbf7H+UAlNkLDc4NyG50GFF/CjNeQcqM3ZwXfyOe3CQi JlmgCoGIzEGuHREpgSKvcy3j+7AtGAxxpPxzlu0bMcROtYYSkVLo8/a1KoMwAZyWtuRY 7nqw== X-Gm-Message-State: AHYfb5gLDZ23OPm6lF+h+f0mNiZ82ig7i/Ufzdw/9ISFVSisnaaDFBjp gXUZsgW7JTGjRb1T X-Received: by 10.101.76.140 with SMTP id m12mr5414687pgt.160.1503562743533; Thu, 24 Aug 2017 01:19:03 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id b9sm7323929pfl.13.2017.08.24.01.19.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:19:03 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 11/14] arm64: kexec_file: set up for crash dump adding elf core header Date: Thu, 24 Aug 2017 17:18:08 +0900 Message-Id: <20170824081811.19299-12-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org load_crashdump_segments() creates and loads a memory segment of elf core header for crash dump. "linux,usable-memory-range" and "linux,elfcorehdr" will add to the 2nd kernel's device-tree blob. The logic of this cod is also from kexec-tools. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/include/asm/kexec.h | 5 ++ arch/arm64/kernel/machine_kexec_file.c | 145 +++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) -- 2.14.1 diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h index ebc4aaa707ae..46b21512efbe 100644 --- a/arch/arm64/include/asm/kexec.h +++ b/arch/arm64/include/asm/kexec.h @@ -98,6 +98,10 @@ static inline void crash_post_resume(void) {} struct kimage_arch { void *dtb_buf; + /* Core ELF header buffer */ + void *elf_headers; + unsigned long elf_headers_sz; + unsigned long elf_load_addr; }; struct kimage; @@ -109,6 +113,7 @@ extern int load_other_segments(struct kimage *image, unsigned long kernel_load_addr, char *initrd, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len); +extern int load_crashdump_segments(struct kimage *image); #endif #endif /* __ASSEMBLY__ */ diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index cd12e451e474..012063307001 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -281,6 +281,77 @@ int arch_kexec_walk_mem(struct kexec_buf *kbuf, int (*func)(u64, u64, void *)) return walk_system_ram_res(0, ULONG_MAX, kbuf, func); } +static int __init arch_kexec_file_init(void) +{ + /* Those values are used later on loading the kernel */ + __dt_root_addr_cells = dt_root_addr_cells; + __dt_root_size_cells = dt_root_size_cells; + + return 0; +} +late_initcall(arch_kexec_file_init); + +#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) + +static int fdt_prop_len(const char *prop_name, int len) +{ + return (strlen(prop_name) + 1) + + sizeof(struct fdt_property) + + FDT_TAGALIGN(len); +} + +static bool cells_size_fitted(unsigned long base, unsigned long size) +{ + /* if *_cells >= 2, cells can hold 64-bit values anyway */ + if ((__dt_root_addr_cells == 1) && (base >= (1ULL << 32))) + return false; + + if ((__dt_root_size_cells == 1) && (size >= (1ULL << 32))) + return false; + + return true; +} + +static void fill_property(void *buf, u64 val64, int cells) +{ + u32 val32; + int i; + + if (cells == 1) { + val32 = cpu_to_fdt32((u32)val64); + memcpy(buf, &val32, sizeof(val32)); + } else { + for (i = 0; i < (cells * sizeof(u32) - sizeof(u64)); i++) + *(char *)buf++ = 0; + + val64 = cpu_to_fdt64(val64); + memcpy(buf, &val64, sizeof(val64)); + } +} + +static int fdt_setprop_range(void *fdt, int nodeoffset, const char *name, + unsigned long addr, unsigned long size) +{ + u64 range[2]; + void *prop; + size_t buf_size; + int result; + + prop = range; + buf_size = (__dt_root_addr_cells + __dt_root_size_cells) * sizeof(u32); + + fill_property(prop, addr, __dt_root_addr_cells); + prop += __dt_root_addr_cells * sizeof(u32); + + fill_property(prop, size, __dt_root_size_cells); + prop += __dt_root_size_cells * sizeof(u32); + + result = fdt_setprop(fdt, nodeoffset, name, range, buf_size); + + return result; +} + int setup_dtb(struct kimage *image, unsigned long initrd_load_addr, unsigned long initrd_len, char *cmdline, unsigned long cmdline_len, @@ -293,10 +364,26 @@ int setup_dtb(struct kimage *image, int range_len; int ret; + /* check ranges against root's #address-cells and #size-cells */ + if (image->type == KEXEC_TYPE_CRASH && + (!cells_size_fitted(image->arch.elf_load_addr, + image->arch.elf_headers_sz) || + !cells_size_fitted(crashk_res.start, + crashk_res.end - crashk_res.start + 1))) { + pr_err("Crash memory region doesn't fit into DT's root cell sizes.\n"); + ret = -EINVAL; + goto out_err; + } + /* duplicate dt blob */ buf_size = fdt_totalsize(initial_boot_params); range_len = (__dt_root_addr_cells + __dt_root_size_cells) * sizeof(u32); + if (image->type == KEXEC_TYPE_CRASH) + buf_size += fdt_prop_len("linux,elfcorehdr", range_len) + + fdt_prop_len("linux,usable-memory-range", + range_len); + if (initrd_load_addr) buf_size += fdt_prop_len("initrd-start", sizeof(u64)) + fdt_prop_len("initrd-end", sizeof(u64)); @@ -318,6 +405,23 @@ int setup_dtb(struct kimage *image, if (nodeoffset < 0) goto out_err; + if (image->type == KEXEC_TYPE_CRASH) { + /* add linux,elfcorehdr */ + ret = fdt_setprop_range(buf, nodeoffset, "linux,elfcorehdr", + image->arch.elf_load_addr, + image->arch.elf_headers_sz); + if (ret) + goto out_err; + + /* add linux,usable-memory-range */ + ret = fdt_setprop_range(buf, nodeoffset, + "linux,usable-memory-range", + crashk_res.start, + crashk_res.end - crashk_res.start + 1); + if (ret) + goto out_err; + } + /* add bootargs */ if (cmdline) { ret = fdt_setprop(buf, nodeoffset, "bootargs", @@ -452,3 +556,44 @@ int load_other_segments(struct kimage *image, unsigned long kernel_load_addr, image->arch.dtb_buf = NULL; return ret; } + +int load_crashdump_segments(struct kimage *image) +{ + void *elf_addr; + unsigned long elf_sz; + struct kexec_buf kbuf; + int ret; + + if (image->type != KEXEC_TYPE_CRASH) + return 0; + + /* Prepare elf headers and add a segment */ + ret = prepare_elf_headers(image, &elf_addr, &elf_sz); + if (ret) { + pr_err("Preparing elf core header failed\n"); + return ret; + } + + kbuf.image = image; + kbuf.buffer = elf_addr; + kbuf.bufsz = elf_sz; + kbuf.memsz = elf_sz; + kbuf.buf_align = PAGE_SIZE; + kbuf.buf_min = crashk_res.start; + kbuf.buf_max = crashk_res.end + 1; + kbuf.top_down = 1; + + ret = kexec_add_buffer(&kbuf); + if (ret) { + vfree(elf_addr); + return ret; + } + image->arch.elf_headers = elf_addr; + image->arch.elf_headers_sz = elf_sz; + image->arch.elf_load_addr = kbuf.mem; + + pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + image->arch.elf_load_addr, elf_sz, elf_sz); + + return ret; +} From patchwork Thu Aug 24 08:18: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: 110886 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5318035qge; Thu, 24 Aug 2017 01:21:45 -0700 (PDT) X-Received: by 10.98.7.68 with SMTP id b65mr1203780pfd.300.1503562905733; Thu, 24 Aug 2017 01:21:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562905; cv=none; d=google.com; s=arc-20160816; b=oBT1Z+OhK4ds3KgpzKXRljKRQBuDfEeLYF3AQJQSubOF/AsSRvpPUlmd3/dwtKR+y2 S5YwXnHPj0mDcmjTExYKNfL9H3Mwlq2cvovYydHSmxP1XRU7fCKpcUhf7BtMpbT/8trk RVn8HYuSNXGVmcLix8FQ+5rGE5ATcdUzhpBd4ee3QseiMtLNMAOmXs8bUg98k8/YXwn1 a9frKXGOS4PaDLfZCilsR6li7THaDYmhmlGWWPAK80cIhkEU9Lv8BtEGyS9BGaDzHMPb QX4RNty+1TtGNFGE2d7yBgirySDN8WMaNpIWMLdGoi47v7skpogmenHxlIlicF4RV4+U 4gMg== 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=HrLA7tpjFuXpGS1Tanwppqlf3IonHvzSfSi0k3QziJw=; b=bwI8nW9y9fqAg8uGxB7wq5c9l/N/n6uieWUJEIZviZJhXcjfrqwYXeLqdgsfjEPSM+ cVRBcXpDFtRUiJ7TXkmoiNzKiP4dCxwzc+wxhRmZLKQvdRDpPL6cP+T9MVgxZOk9Xp4R Ooc8U81FfKmruBXZXuT3x80jeF11ejLvAyDMRf3nZk+ehLlF2d+VJsMK52AenOkGeNge SIl5CB2UPF/y5bF0OCxvtC06F0kpKWvkdRSp39GlW2duWu0iqsGBvotG7rE6015fLCBA YRMRBh/ioKw5pXX6Vej9WFhwYGUY6gTydp3FPRui9JRxvyad2lG2Rx8ym4P3oyg79xLv cHjg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Ozr1Sb98; 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 j23si2739677pli.275.2017.08.24.01.21.45; Thu, 24 Aug 2017 01:21:45 -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 header.s=google header.b=Ozr1Sb98; 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 S1752463AbdHXIVn (ORCPT + 26 others); Thu, 24 Aug 2017 04:21:43 -0400 Received: from mail-pg0-f45.google.com ([74.125.83.45]:34021 "EHLO mail-pg0-f45.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751815AbdHXITL (ORCPT ); Thu, 24 Aug 2017 04:19:11 -0400 Received: by mail-pg0-f45.google.com with SMTP id s14so13477933pgs.1 for ; Thu, 24 Aug 2017 01:19:11 -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=HrLA7tpjFuXpGS1Tanwppqlf3IonHvzSfSi0k3QziJw=; b=Ozr1Sb98op2s/U+xd1YKGyIob+AfcIHuSSx92oYaeH7yZ9VoshedPdze0bX1wchf7s EtgIaubvEgVAZnW1d7dIWdu+tULBsPMdHF0IYG79Miu/YZNiCyKzlsWDKDjW/Hf9A97/ RyjEdDlmm81kGT45lQmh7Fw/8PomnZwbZKgdE= 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=HrLA7tpjFuXpGS1Tanwppqlf3IonHvzSfSi0k3QziJw=; b=bgpSiajxKlb5BLb0DM2Em6rDP5FkQhGE0/K6Sx8A+QPFv+cg6ie4EfaJQH360V9oAX 27QS9lIS3aoUT3omr3GQ453QCvFEktgvAENaS5PDGTer5OPO5M5Z25nVzjVCJRGC1Llq 5yhjbAQWd/h3EiZW7ZzLkv2G9muGHt0dL3J62bZeBhG5xhwNnhqFk3IjFnuVOxhwwv/I oNsoEEKlxlxRZNr49oHRLshBEVImXYn90W9k0/QOwgmm+cZteZ9Yo/NmsawJ8vfRV/l2 gmFwmaBpf39ehRVZBNqQl6BC075El4Z+Hb47+uNthDWDfWTBhrfWffv6JFgihAdE4O+C 9VKQ== X-Gm-Message-State: AHYfb5hvZf4DPuVv2IvZdpJBa4AxVoWezCJcTRYVYGfelx1J3ndMXGJk gVdHr5r/1uSTRHQs X-Received: by 10.84.132.106 with SMTP id 97mr5960127ple.105.1503562750835; Thu, 24 Aug 2017 01:19:10 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id w66sm6420622pfi.63.2017.08.24.01.19.10 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:19:10 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 12/14] arm64: enable KEXEC_FILE config Date: Thu, 24 Aug 2017 17:18:09 +0900 Message-Id: <20170824081811.19299-13-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Modify arm64/Kconfig and Makefile to enable kexec_file_load support. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/Kconfig | 22 ++++++++++++++++++++++ arch/arm64/kernel/Makefile | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) -- 2.14.1 diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index dfd908630631..cf10bc720d9e 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -756,6 +756,28 @@ config KEXEC but it is independent of the system firmware. And like a reboot you can start any kernel with it, not just Linux. +config KEXEC_FILE + bool "kexec file based system call" + select KEXEC_CORE + select BUILD_BIN2C + ---help--- + This is new version of kexec system call. This system call is + file based and takes file descriptors as system call argument + for kernel and initramfs as opposed to list of segments as + accepted by previous system call. + +config KEXEC_VERIFY_SIG + bool "Verify kernel signature during kexec_file_load() syscall" + depends on KEXEC_FILE + select SYSTEM_DATA_VERIFICATION + ---help--- + This option makes kernel signature verification mandatory for + the kexec_file_load() syscall. + + In addition to that option, you need to enable signature + verification for the corresponding kernel image type being + loaded in order for this to work. + config CRASH_DUMP bool "Build kdump crash kernel" help diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 16e9f56b536a..5df003d6157c 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -48,7 +48,7 @@ arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o arm64-obj-$(CONFIG_PARAVIRT) += paravirt.o arm64-obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o -arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ +arm64-obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o \ cpu-reset.o arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o From patchwork Thu Aug 24 08:18:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110883 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5316751qge; Thu, 24 Aug 2017 01:20:30 -0700 (PDT) X-Received: by 10.99.227.81 with SMTP id o17mr5371755pgj.41.1503562830858; Thu, 24 Aug 2017 01:20:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562830; cv=none; d=google.com; s=arc-20160816; b=nTJ87a+au0SW45uFoF5xS4IdqFgVEnighvyTnpbqosIO+IHCbAQWGar7vpHgtyoHve 1GXpPzRgTKPKNdcW2yYbPgWAjgbNTX280Tna4Ezd6Kw07KKzMV17IFXrBzwyCnk/BL27 KoeLoRPxcIN+qLYtpttQIHcwlo5HSbddvPYHp575caVDzZ18pBq0cDT1J7nIjF0lmzEU RGbwvcckFEc9Iy1iwYiURXxVoLU/nkrMrSN22TLmrXpcUQ2jtKOBTn8IfFCdDEJ0tn7Q ZTfvFawZUAS3q0ZQ46MsXrlHOh9H1cvr5fn2EbxudvE7w9cpmJW59Rpzv0mpGqFsjgYq M51w== 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=nXCTzT89ngL8ia15oriGI1voVBCekvnoQZ4T/c5BG0E=; b=b8iPzyoStPqXDTtjzChPM3H4ccnXV13BtO4dw6DuofM+gh0zk5XyWfSQaC4ZTiRD0J /YIqD8etfnlbkiKl5urHiBgEro1kUfABZYx1nSzPEjJyN2jObj7yV2D3thqh8+nOpYKK 0ZVMKWbwVpaSTWIQjFFEnBl0UG3WtPS6sHD7gGPBxf5S8Mb5iOSA6xdGHXHFV7cvTJ2a t5oBpzQTH1Yl22SLCtB9H2Gop4yT/la+HYCOigaRUvIRLeM/oPPD8Do3La6grYZdrxCq K+Umb7rPMRhR1zhn+ZEWYoS8fYtwBcNwAoOWcgUZwgozt03H7jsuGl9ys7LNreqPHAsF JlvA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=axUB/f3z; 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 91si2576914ply.126.2017.08.24.01.20.30; Thu, 24 Aug 2017 01:20:30 -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 header.s=google header.b=axUB/f3z; 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 S1752549AbdHXIU1 (ORCPT + 26 others); Thu, 24 Aug 2017 04:20:27 -0400 Received: from mail-pg0-f47.google.com ([74.125.83.47]:34984 "EHLO mail-pg0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751372AbdHXITP (ORCPT ); Thu, 24 Aug 2017 04:19:15 -0400 Received: by mail-pg0-f47.google.com with SMTP id u191so13500943pgc.2 for ; Thu, 24 Aug 2017 01:19:15 -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=nXCTzT89ngL8ia15oriGI1voVBCekvnoQZ4T/c5BG0E=; b=axUB/f3zivM3Of4hWgr+YKXuuHDmdvUwZKEk4Ckivkws/Gw5zkTHiuUSpCnxiRR1io HwvalzDWRFhHor4RMBHhzMUxlSCecGjWCcWU+VSFtBuHtf937MGoNKXTYEfT8LX3xb13 Nqbb4ypjBH/9+Tlez6NA6eOwTB5EF7PR+mdo4= 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=nXCTzT89ngL8ia15oriGI1voVBCekvnoQZ4T/c5BG0E=; b=tmWZF7u1ipV/Bho/3uZdY7JrYNK477Wxa7C5a7+V92AUP2ELVZw8ylYVRYP4jWSuFH C/C4ngnXhSCJ0e7apWPgPKHiquY6D2gkEr74AvVKYOw5jghNFSoZm2Zf/oWF6xhMofBN w2irfcLYfkEBu+5wJxOtzqWKV2jBeZ1c9y9SeWAzw9Ae1oreRC7PV9r0EnvwABIJqUuI KS5ocvfqD2ZjjnkJ+I4bxJhO/l/R8dO6pYg0ttZUAbEgQ8J78+vEk8BKyujxTbNC63ml eFRvpn6AXyI3ftQNUsS2XVrkMhM4DGIFxeUIx+gl1D0uxVlo30Yh55+IJF5h94tP4AFU 7jPA== X-Gm-Message-State: AHYfb5j7S6SYv6hA3YqFY1ZZTbBTZ0iXSOCFc04lKVLWSXwe0T4bTDoz HglqBN/7+KTyF6jx X-Received: by 10.84.232.12 with SMTP id h12mr6011157plk.362.1503562755232; Thu, 24 Aug 2017 01:19:15 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id z28sm726816pfl.153.2017.08.24.01.19.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:19:14 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 13/14] arm64: kexec_file: add Image format support Date: Thu, 24 Aug 2017 17:18:10 +0900 Message-Id: <20170824081811.19299-14-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The "Image" binary will be loaded at the offset of TEXT_OFFSET from the start of system memory. TEXT_OFFSET is basically determined from the header of the image. Regarding kernel verification, it will be done through verify_pefile_signature() as arm64's "Image" binary can be seen as in PE format. This approach is consistent with x86 implementation. we can sign it with sbsign command. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/Kconfig | 11 ++-- arch/arm64/include/asm/kexec_file.h | 83 ++++++++++++++++++++++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/kexec_image.c | 112 +++++++++++++++++++++++++++++++++ arch/arm64/kernel/machine_kexec_file.c | 6 +- 5 files changed, 208 insertions(+), 5 deletions(-) create mode 100644 arch/arm64/include/asm/kexec_file.h create mode 100644 arch/arm64/kernel/kexec_image.c -- 2.14.1 diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index cf10bc720d9e..c8f603700bdd 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -766,18 +766,21 @@ config KEXEC_FILE for kernel and initramfs as opposed to list of segments as accepted by previous system call. +config KEXEC_FILE_IMAGE_FMT + bool "Enable Image support" + depends on KEXEC_FILE + ---help--- + Select this option to enable 'Image' kernel loading. + config KEXEC_VERIFY_SIG bool "Verify kernel signature during kexec_file_load() syscall" depends on KEXEC_FILE select SYSTEM_DATA_VERIFICATION + select SIGNED_PE_FILE_VERIFICATION if KEXEC_FILE_IMAGE_FMT ---help--- This option makes kernel signature verification mandatory for the kexec_file_load() syscall. - In addition to that option, you need to enable signature - verification for the corresponding kernel image type being - loaded in order for this to work. - config CRASH_DUMP bool "Build kdump crash kernel" help diff --git a/arch/arm64/include/asm/kexec_file.h b/arch/arm64/include/asm/kexec_file.h new file mode 100644 index 000000000000..5df899aa0d2e --- /dev/null +++ b/arch/arm64/include/asm/kexec_file.h @@ -0,0 +1,83 @@ +#ifndef _ASM_KEXEC_FILE_H +#define _ASM_KEXEC_FILE_H + +extern struct kexec_file_ops kexec_image_ops; + +/** + * struct arm64_image_header - arm64 kernel image header. + * + * @pe_sig: Optional PE format 'MZ' signature. + * @branch_code: Reserved for instructions to branch to stext. + * @text_offset: The image load offset in LSB byte order. + * @image_size: An estimated size of the memory image size in LSB byte order. + * @flags: Bit flags: + * Bit 7.0: Image byte order, 1=MSB. + * @reserved_1: Reserved. + * @magic: Magic number, "ARM\x64". + * @pe_header: Optional offset to a PE format header. + **/ + +struct arm64_image_header { + u8 pe_sig[2]; + u16 branch_code[3]; + u64 text_offset; + u64 image_size; + u8 flags[8]; + u64 reserved_1[3]; + u8 magic[4]; + u32 pe_header; +}; + +static const u8 arm64_image_magic[4] = {'A', 'R', 'M', 0x64U}; +static const u8 arm64_image_pe_sig[2] = {'M', 'Z'}; +static const u64 arm64_image_flag_7_be = 0x01U; + +/** + * arm64_header_check_magic - Helper to check the arm64 image header. + * + * Returns non-zero if header is OK. + */ + +static inline int arm64_header_check_magic(const struct arm64_image_header *h) +{ + if (!h) + return 0; + + if (!h->text_offset) + return 0; + + return (h->magic[0] == arm64_image_magic[0] + && h->magic[1] == arm64_image_magic[1] + && h->magic[2] == arm64_image_magic[2] + && h->magic[3] == arm64_image_magic[3]); +} + +/** + * arm64_header_check_pe_sig - Helper to check the arm64 image header. + * + * Returns non-zero if 'MZ' signature is found. + */ + +static inline int arm64_header_check_pe_sig(const struct arm64_image_header *h) +{ + if (!h) + return 0; + + return (h->pe_sig[0] == arm64_image_pe_sig[0] + && h->pe_sig[1] == arm64_image_pe_sig[1]); +} + +/** + * arm64_header_check_msb - Helper to check the arm64 image header. + * + * Returns non-zero if the image was built as big endian. + */ + +static inline int arm64_header_check_msb(const struct arm64_image_header *h) +{ + if (!h) + return 0; + + return !!(h->flags[7] & arm64_image_flag_7_be); +} +#endif /* _ASM_KEXE_FILE_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 5df003d6157c..a1161bab6810 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -51,6 +51,7 @@ arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o arm64-obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o \ cpu-reset.o arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o +arm64-obj-$(CONFIG_KEXEC_FILE_IMAGE_FMT) += kexec_image.o arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c new file mode 100644 index 000000000000..db4aa1379fec --- /dev/null +++ b/arch/arm64/kernel/kexec_image.c @@ -0,0 +1,112 @@ +/* + * Kexec image loader + + * Copyright (C) 2017 Linaro Limited + * Authors: AKASHI Takahiro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "kexec_file(Image): " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +static int image_probe(const char *kernel_buf, unsigned long kernel_len) +{ + const struct arm64_image_header *h; + + h = (const struct arm64_image_header *)(kernel_buf); + + if ((kernel_len < sizeof(*h)) || !arm64_header_check_magic(h)) + return -EINVAL; + + pr_debug("%s: PE format: %s\n", __func__, + (arm64_header_check_pe_sig(h) ? "yes" : "no")); + + return 0; +} + +static void *image_load(struct kimage *image, char *kernel, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + struct kexec_buf kbuf; + struct arm64_image_header *h = (struct arm64_image_header *)kernel; + unsigned long text_offset, kernel_load_addr; + int ret; + + /* Create elf core header segment */ + ret = load_crashdump_segments(image); + if (ret) + goto out; + + /* Load the kernel */ + kbuf.image = image; + if (image->type == KEXEC_TYPE_CRASH) { + kbuf.buf_min = crashk_res.start; + kbuf.buf_max = crashk_res.end + 1; + } else { + kbuf.buf_min = 0; + kbuf.buf_max = ULONG_MAX; + } + kbuf.top_down = 0; + + kbuf.buffer = kernel; + kbuf.bufsz = kernel_len; + if (h->image_size) { + kbuf.memsz = le64_to_cpu(h->image_size); + text_offset = le64_to_cpu(h->text_offset); + } else { + /* v3.16 or older */ + kbuf.memsz = kbuf.bufsz; /* NOTE: not including BSS */ + text_offset = 0x80000; + } + kbuf.buf_align = SZ_2M; + + /* Adjust kernel segment with TEXT_OFFSET */ + kbuf.memsz += text_offset; + + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out; + + image->segment[image->nr_segments - 1].mem += text_offset; + image->segment[image->nr_segments - 1].memsz -= text_offset; + kernel_load_addr = kbuf.mem + text_offset; + + pr_debug("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kernel_load_addr, kbuf.bufsz, kbuf.memsz); + + /* Load additional data */ + ret = load_other_segments(image, kernel_load_addr, + initrd, initrd_len, cmdline, cmdline_len); + +out: + return ERR_PTR(ret); +} + +#ifdef CONFIG_KEXEC_VERIFY_SIG +static int image_verify_sig(const char *kernel, unsigned long kernel_len) +{ + return verify_pefile_signature(kernel, kernel_len, NULL, + VERIFYING_KEXEC_PE_SIGNATURE); +} +#endif + +struct kexec_file_ops kexec_image_ops = { + .probe = image_probe, + .load = image_load, +#ifdef CONFIG_KEXEC_VERIFY_SIG + .verify_sig = image_verify_sig, +#endif +}; diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index 012063307001..ab3b19d51727 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -27,7 +27,11 @@ static int __dt_root_addr_cells; static int __dt_root_size_cells; -static struct kexec_file_ops *kexec_file_loaders[0]; +static struct kexec_file_ops *kexec_file_loaders[] = { +#ifdef CONFIG_KEXEC_FILE_IMAGE_FMT + &kexec_image_ops, +#endif +}; int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, unsigned long buf_len) From patchwork Thu Aug 24 08:18:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 110882 Delivered-To: patch@linaro.org Received: by 10.140.95.78 with SMTP id h72csp5315920qge; Thu, 24 Aug 2017 01:19:40 -0700 (PDT) X-Received: by 10.84.174.129 with SMTP id r1mr5908586plb.55.1503562780263; Thu, 24 Aug 2017 01:19:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1503562780; cv=none; d=google.com; s=arc-20160816; b=e9tBtgTb7P+lYIgW08BNW11ylnFi5PZSvQjMUuM9GzUveeERRxcqSi4MAkwxBJ46j2 pLIVmLkEWbPh2AXb/DT5Gx9jFIAMX4572IN7h23EQDfFNq6Fadvq+Sz9NTj2a+se2UNl cwi7HZHWLEKrU3fa90QfWxKkYxguNvx7OmO7ZpDqQvIu7ihudMVHtJDd/Mz6qAF0LXen a/pjkSFL8gSiGJJeEH+CUaX8QbRwIJDo+pNnNLl9oblRPUVtCb77a8BoOJTUO3XAaB/E /rhwl2kkFzrtOVDQET/Rw2DFmNJEU2GXbyeqMqD/KMKqmAJeKb6hgo2RnOVHqJfICR9V DSuQ== 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=oWx+DDmp+fCylEpyN4dHca6RbYai8lu7RxLXeTLs1NA=; b=FRP1Zv37bCch96E4poZXu2NjEHk4/I8gqzXHrLUP9MX/R9u6ble1pGsehGPZ2fvkNa 6X6/OWrUCu+f5jZU9zXsXjw9T4CLy87FcnoEmhBs4sZMb9HZ3dfYkyesJ+q0ClTLW8HL R/8sacbQbKHUqn0gNDmemYfVe0emhMTgaAUHjiCMUBJX4W9EZKM0TIEokfRjejaniO0B cuB8Fomb57i7tDIS/dZLpb00acP+wcxwmcJB4qRAoBM5yMUJ8+xYbA9NUIjizOQVYEmE 63k6tc5FJRO8cyljhQve/nfzYijo3nncq5xqgPv3PMESrFKEQZmSjlYzZKr7vnmaBO0h OGfg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Mj2AIQh1; 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 m2si2397789pgt.892.2017.08.24.01.19.39; Thu, 24 Aug 2017 01:19:40 -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 header.s=google header.b=Mj2AIQh1; 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 S1752421AbdHXITi (ORCPT + 26 others); Thu, 24 Aug 2017 04:19:38 -0400 Received: from mail-pg0-f42.google.com ([74.125.83.42]:36112 "EHLO mail-pg0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751368AbdHXITU (ORCPT ); Thu, 24 Aug 2017 04:19:20 -0400 Received: by mail-pg0-f42.google.com with SMTP id 83so13459099pgb.3 for ; Thu, 24 Aug 2017 01:19:20 -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=oWx+DDmp+fCylEpyN4dHca6RbYai8lu7RxLXeTLs1NA=; b=Mj2AIQh1ZXco4f66i2c439rKto6+M14tPZoqjS9v2fdiHw4lcy5YdN/xsxWXNrQVd2 Y9to3QELN2JtbKn0ZwS/0l9PW4GyMNzTUEnzy0oszZu3zrMi0WX3FELxotiGMb6+8Ond wailb7kPU0OR/Kt2zCkKaWg94ZADIFbnSkB2c= 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=oWx+DDmp+fCylEpyN4dHca6RbYai8lu7RxLXeTLs1NA=; b=a3S23sJTd+MKKxMmmkqdxBbtzBc96lIU+zjfnWQHyxhqGi4XGwEVVxqqQrrex5xZrv cTFdN5b9VvvDkNvq9HoUzuyEcD+iYaq+gdhzP0U6TiYCiFFMcORxYDxNiLCx8eHw8+v+ fLGNz2vv/C0PQYoMvtG6J6WgZ86z7U5Lbvlt1Y9UHun5F2GyT2aCNBFIe7/kWDlpyorG cD8ce+5vIvDw6/1Fi41u0pYiZ/JQMcjWYfCper5po2GKKFIk7IHRWkd84xgB5gNbq83d 7IQCYtSfRfb6Hi3IOT/oXtGL8yf5/yFY35Hop8fACnmtbsq7r11Pi1JQoKc12jHoTHt0 NwoA== X-Gm-Message-State: AHYfb5gaczjaoZ1FyCDRjUuwqrsimxR+jtEzEnNH2Jt9fJtkGyZi6i2x m2EOXHt4SlPR5UbV X-Received: by 10.98.80.131 with SMTP id g3mr5815720pfj.156.1503562759742; Thu, 24 Aug 2017 01:19:19 -0700 (PDT) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id b68sm6401230pfd.33.2017.08.24.01.19.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 24 Aug 2017 01:19:19 -0700 (PDT) From: AKASHI Takahiro To: catalin.marinas@arm.com, will.deacon@arm.com, bauerman@linux.vnet.ibm.com, dhowells@redhat.com, vgoyal@redhat.com, herbert@gondor.apana.org.au, davem@davemloft.net, akpm@linux-foundation.org, mpe@ellerman.id.au, dyoung@redhat.com, bhe@redhat.com, arnd@arndb.de, ard.biesheuvel@linaro.org Cc: kexec@lists.infradead.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, AKASHI Takahiro Subject: [PATCH 14/14] arm64: kexec_file: add vmlinux format support Date: Thu, 24 Aug 2017 17:18:11 +0900 Message-Id: <20170824081811.19299-15-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20170824081811.19299-1-takahiro.akashi@linaro.org> References: <20170824081811.19299-1-takahiro.akashi@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The first PT_LOAD segment, which is assumed to be "text" code, in vmlinux will be loaded at the offset of TEXT_OFFSET from the begining of system memory. The other PT_LOAD segments are placed relative to the first one. Regarding kernel verification, since there is no standard way to contain a signature within elf binary, we follow PowerPC's (not yet upstreamed) approach, that is, appending a signature right after the kernel binary itself like module signing. This way, the signature can be easily retrieved and verified with verify_pkcs7_signature(). We can sign the kernel with sign-file command. Unlike PowerPC, we don't support ima-based kexec for now since arm64 doesn't have any secure solution for system appraisal at this moment. Signed-off-by: AKASHI Takahiro Cc: Catalin Marinas Cc: Will Deacon --- arch/arm64/Kconfig | 8 ++ arch/arm64/include/asm/kexec_file.h | 1 + arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/kexec_elf.c | 216 +++++++++++++++++++++++++++++++++ arch/arm64/kernel/machine_kexec_file.c | 3 + 5 files changed, 229 insertions(+) create mode 100644 arch/arm64/kernel/kexec_elf.c -- 2.14.1 diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index c8f603700bdd..94021e66b826 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -772,11 +772,19 @@ config KEXEC_FILE_IMAGE_FMT ---help--- Select this option to enable 'Image' kernel loading. +config KEXEC_FILE_ELF_FMT + bool "Enable vmlinux/elf support" + depends on KEXEC_FILE + select KEXEC_FILE_ELF + ---help--- + Select this option to enable 'vmlinux' kernel loading. + config KEXEC_VERIFY_SIG bool "Verify kernel signature during kexec_file_load() syscall" depends on KEXEC_FILE select SYSTEM_DATA_VERIFICATION select SIGNED_PE_FILE_VERIFICATION if KEXEC_FILE_IMAGE_FMT + select MODULE_SIG_FORMAT if KEXEC_FILE_ELF_FMT ---help--- This option makes kernel signature verification mandatory for the kexec_file_load() syscall. diff --git a/arch/arm64/include/asm/kexec_file.h b/arch/arm64/include/asm/kexec_file.h index 5df899aa0d2e..eaf2adc1121c 100644 --- a/arch/arm64/include/asm/kexec_file.h +++ b/arch/arm64/include/asm/kexec_file.h @@ -2,6 +2,7 @@ #define _ASM_KEXEC_FILE_H extern struct kexec_file_ops kexec_image_ops; +extern struct kexec_file_ops kexec_elf64_ops; /** * struct arm64_image_header - arm64 kernel image header. diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index a1161bab6810..1463337160ea 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -52,6 +52,7 @@ arm64-obj-$(CONFIG_KEXEC_CORE) += machine_kexec.o relocate_kernel.o \ cpu-reset.o arm64-obj-$(CONFIG_KEXEC_FILE) += machine_kexec_file.o arm64-obj-$(CONFIG_KEXEC_FILE_IMAGE_FMT) += kexec_image.o +arm64-obj-$(CONFIG_KEXEC_FILE_ELF_FMT) += kexec_elf.o arm64-obj-$(CONFIG_ARM64_RELOC_TEST) += arm64-reloc-test.o arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o diff --git a/arch/arm64/kernel/kexec_elf.c b/arch/arm64/kernel/kexec_elf.c new file mode 100644 index 000000000000..7bd3c1e1f65a --- /dev/null +++ b/arch/arm64/kernel/kexec_elf.c @@ -0,0 +1,216 @@ +/* + * Kexec vmlinux loader + + * Copyright (C) 2017 Linaro Limited + * Authors: AKASHI Takahiro + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define pr_fmt(fmt) "kexec_file(elf): " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int elf64_probe(const char *buf, unsigned long len) +{ + struct elfhdr ehdr; + + /* Check for magic and architecture */ + memcpy(&ehdr, buf, sizeof(ehdr)); + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) || + (elf16_to_cpu(&ehdr, ehdr.e_machine) != EM_AARCH64)) + return -ENOEXEC; + + return 0; +} + +static int elf_exec_load(struct kimage *image, struct elfhdr *ehdr, + struct elf_info *elf_info, + unsigned long *kernel_load_addr) +{ + struct kexec_buf kbuf; + const struct elf_phdr *phdr; + const struct arm64_image_header *h; + unsigned long text_offset, rand_offset; + unsigned long page_offset, phys_offset; + int first_segment, i, ret = -ENOEXEC; + + kbuf.image = image; + if (image->type == KEXEC_TYPE_CRASH) { + kbuf.buf_min = crashk_res.start; + kbuf.buf_max = crashk_res.end + 1; + } else { + kbuf.buf_min = 0; + kbuf.buf_max = ULONG_MAX; + } + kbuf.top_down = 0; + + /* Load PT_LOAD segments. */ + for (i = 0, first_segment = 1; i < ehdr->e_phnum; i++) { + phdr = &elf_info->proghdrs[i]; + if (phdr->p_type != PT_LOAD) + continue; + + kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset; + kbuf.bufsz = min(phdr->p_filesz, phdr->p_memsz); + kbuf.memsz = phdr->p_memsz; + kbuf.buf_align = phdr->p_align; + + if (first_segment) { + /* + * Identify TEXT_OFFSET: + * When CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET=y the image + * header could be offset in the elf segment. The linker + * script sets ehdr->e_entry to the start of text. + * + * NOTE: In v3.16 or older, h->text_offset is 0, + * so use the default, 0x80000 + */ + rand_offset = ehdr->e_entry - phdr->p_vaddr; + h = (struct arm64_image_header *) + (elf_info->buffer + phdr->p_offset + + rand_offset); + + if (!arm64_header_check_magic(h)) + goto out; + + if (h->image_size) + text_offset = le64_to_cpu(h->text_offset); + else + text_offset = 0x80000; + + /* Adjust kernel segment with TEXT_OFFSET */ + kbuf.memsz += text_offset - rand_offset; + + ret = kexec_add_buffer(&kbuf); + if (ret) + goto out; + + image->segment[image->nr_segments - 1].mem + += text_offset - rand_offset; + image->segment[image->nr_segments - 1].memsz + -= text_offset - rand_offset; + + *kernel_load_addr = kbuf.mem + text_offset; + + /* for succeeding segmemts */ + page_offset = ALIGN_DOWN(phdr->p_vaddr, SZ_2M); + phys_offset = kbuf.mem; + + first_segment = 0; + } else { + /* Calculate physical address */ + kbuf.mem = phdr->p_vaddr - page_offset + phys_offset; + + ret = kexec_add_segment(&kbuf); + if (ret) + goto out; + } + } + +out: + return ret; +} + +static void *elf64_load(struct kimage *image, char *kernel_buf, + unsigned long kernel_len, char *initrd, + unsigned long initrd_len, char *cmdline, + unsigned long cmdline_len) +{ + struct elfhdr ehdr; + struct elf_info elf_info; + unsigned long kernel_load_addr; + int ret; + + /* Create elf core header segment */ + ret = load_crashdump_segments(image); + if (ret) + goto out; + + /* Load the kernel */ + ret = build_elf_exec_info(kernel_buf, kernel_len, &ehdr, &elf_info); + if (ret) + goto out; + + ret = elf_exec_load(image, &ehdr, &elf_info, &kernel_load_addr); + if (ret) + goto out; + pr_debug("Loaded the kernel at 0x%lx\n", kernel_load_addr); + + /* Load additional data */ + ret = load_other_segments(image, kernel_load_addr, + initrd, initrd_len, cmdline, cmdline_len); + +out: + elf_free_info(&elf_info); + + return ERR_PTR(ret); +} + +#ifdef CONFIG_KEXEC_VERIFY_SIG +/* + * The file format is the exact same as module signing: + * := + + + * := + + */ +static int elf64_verify_sig(const char *kernel, unsigned long kernel_len) +{ + const size_t marker_len = sizeof(MODULE_SIG_STRING) - 1; + const struct module_signature *sig; + size_t file_len = kernel_len; + size_t sig_len; + const void *p; + int rc; + + if (kernel_len <= marker_len + sizeof(*sig)) + return -ENOENT; + + /* Check for marker */ + p = kernel + kernel_len - marker_len; + if (memcmp(p, MODULE_SIG_STRING, marker_len)) { + pr_err("probably the kernel is not signed.\n"); + return -ENOENT; + } + + /* Validate signature */ + sig = (const struct module_signature *) (p - sizeof(*sig)); + file_len -= marker_len; + + rc = validate_module_sig(sig, kernel_len - marker_len); + if (rc) { + pr_err("signature is not valid\n"); + return rc; + } + + /* Verify kernel with signature */ + sig_len = be32_to_cpu(sig->sig_len); + p -= sig_len + sizeof(*sig); + file_len -= sig_len + sizeof(*sig); + + rc = verify_pkcs7_signature(kernel, p - (void *)kernel, p, sig_len, + NULL, VERIFYING_MODULE_SIGNATURE, + NULL, NULL); + + return rc; +} +#endif + +struct kexec_file_ops kexec_elf64_ops = { + .probe = elf64_probe, + .load = elf64_load, +#ifdef CONFIG_KEXEC_VERIFY_SIG + .verify_sig = elf64_verify_sig, +#endif +}; diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index ab3b19d51727..cb1f24d98f87 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -31,6 +31,9 @@ static struct kexec_file_ops *kexec_file_loaders[] = { #ifdef CONFIG_KEXEC_FILE_IMAGE_FMT &kexec_image_ops, #endif +#ifdef CONFIG_KEXEC_FILE_ELF_FMT + &kexec_elf64_ops, +#endif }; int arch_kexec_kernel_image_probe(struct kimage *image, void *buf,