From patchwork Mon Apr 4 20:36:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jorge Lopez X-Patchwork-Id: 12800856 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 30659C35276 for ; Mon, 4 Apr 2022 21:37:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1382581AbiDDVb0 (ORCPT ); Mon, 4 Apr 2022 17:31:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49132 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380587AbiDDUi0 (ORCPT ); Mon, 4 Apr 2022 16:38:26 -0400 Received: from mail-oa1-x34.google.com (mail-oa1-x34.google.com [IPv6:2001:4860:4864:20::34]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DD1526AC8 for ; Mon, 4 Apr 2022 13:36:29 -0700 (PDT) Received: by mail-oa1-x34.google.com with SMTP id 586e51a60fabf-df0940c4eeso12142903fac.8 for ; Mon, 04 Apr 2022 13:36:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=jdzqjbj+EXZVpnQGFjZafV4mVPSJl+K5k7xong2l9Eg=; b=FGCTflOqdYUNvmEUMkts7jMAYyFuqoAJKERt/B3inw/iHmbD3cPEwHveIezEmwygCE lw3Vigxj9Ag85APhvAEipzWaCIA4APWhfwnIHc/Bd3rx0wu1eOFp0xr8VBv2CPr9LZQV aZ92Jw1wlbMp5Jw/UJF79Ci1tzN7HaunywDgGWBVdBE9WsOL63APxcAUYFUm5zRD46pP KhN2R5tSwomdEfLGcDc9cFnC8O6rnRp2k/xKpwnU15h9CUjNAds/aphiFRF2DsL+zQG2 YTpzEdljowdnv/UE5Yr2OWZu9q1UrLYBeqsuxyZSr7Nrj/nzzu3oHxQmW9L0KlprR6Lq KAvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=jdzqjbj+EXZVpnQGFjZafV4mVPSJl+K5k7xong2l9Eg=; b=heGeK15J8Be4+VgrhlxLSkegMMbVpQ2sCWoxbU2Oa6nx+HO3XsYQelKJYTEWGMtCnH X2ZlwtuNxZxQfegFdwdiLpBZGqo9GCoMvNMockqDMPPfqZfKLOPIuivDKSNO2/RuHJeX A+yrJsRMIGZ2mDMUwjX4YiPn5GJsguHfkJctbTUSyuq1immq9vOgzNeGchpHm+wlA9is fKDQOOL6q+JKf58N0Qr+YqTLfCgFrMVLuRoQBxSd2sTt209LbD62a4YOPUD/u5pQNFSu 4q0PGxjJatqET/2OswhKIN+s5wBSfVP6K94+cIZcKE2G4ofrgohOr7bxo/VXAIycj5GK 2bSA== X-Gm-Message-State: AOAM531CnLJ9OMhsHeJ28w5vvB/WhsVhq6bCnqdjSQu7P17I7zQfAnfC V3jSs9dK0CVdI3Gjn7b1y2MTfWGJPGE= X-Google-Smtp-Source: ABdhPJwXBKs7TFjMvM29bqSZlBckiP4/wr0A0tAlVHz5zVLgmJVBr0gBNLry2D8I7vMTuQ02MZ3ZSA== X-Received: by 2002:a05:6870:58aa:b0:dd:a976:5e8f with SMTP id be42-20020a05687058aa00b000dda9765e8fmr2783oab.112.1649104588185; Mon, 04 Apr 2022 13:36:28 -0700 (PDT) Received: from grumpy-vm.hsd1.tx.comcast.net ([2601:2c3:480:7390:c57b:f63e:33f5:caed]) by smtp.gmail.com with ESMTPSA id u20-20020a4a9e94000000b003291f6ac4b2sm3765786ook.28.2022.04.04.13.36.27 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Apr 2022 13:36:27 -0700 (PDT) From: Jorge Lopez X-Google-Original-From: Jorge Lopez To: platform-driver-x86@vger.kernel.org Subject: [PATCH v1 1/6] Correct code style related issues in hp-wmi Date: Mon, 4 Apr 2022 15:36:21 -0500 Message-Id: <20220404203626.4311-2-jorge.lopez2@hp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220404203626.4311-1-jorge.lopez2@hp.com> References: <20220404203626.4311-1-jorge.lopez2@hp.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Update hp-wmi driver to address all code style issues reported by checkpatch.pl script. All changes were validated on a HP ZBook Workstation, HP EliteBook x360, and HP EliteBook 850 G8 notebooks. Signed-off-by: Jorge Lopez --- Based on the latest platform-drivers-x86.git/for-next v1-0001-Update-hp_wmi_group-to-simplify-feature-addition patch was broken in two separate patches. This patch is patch 1 of 2 --- drivers/platform/x86/hp-wmi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 0e9a25b56e0e..667f94bba905 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -605,6 +605,7 @@ static int hp_wmi_rfkill2_refresh(void) for (i = 0; i < rfkill2_count; i++) { int num = rfkill2[i].num; struct bios_rfkill2_device_state *devstate; + devstate = &state.device[num]; if (num >= state.count || @@ -625,6 +626,7 @@ static ssize_t display_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY); + if (value < 0) return value; return sprintf(buf, "%d\n", value); @@ -634,6 +636,7 @@ static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY); + if (value < 0) return value; return sprintf(buf, "%d\n", value); @@ -643,6 +646,7 @@ static ssize_t als_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_read_int(HPWMI_ALS_QUERY); + if (value < 0) return value; return sprintf(buf, "%d\n", value); @@ -652,6 +656,7 @@ static ssize_t dock_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_get_dock_state(); + if (value < 0) return value; return sprintf(buf, "%d\n", value); @@ -661,6 +666,7 @@ static ssize_t tablet_show(struct device *dev, struct device_attribute *attr, char *buf) { int value = hp_wmi_get_tablet_mode(); + if (value < 0) return value; return sprintf(buf, "%d\n", value); @@ -671,6 +677,7 @@ static ssize_t postcode_show(struct device *dev, struct device_attribute *attr, { /* Get the POST error code of previous boot failure. */ int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY); + if (value < 0) return value; return sprintf(buf, "0x%x\n", value); @@ -1013,6 +1020,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device) struct rfkill *rfkill; enum rfkill_type type; char *name; + switch (state.device[i].radio_type) { case HPWMI_WIFI: type = RFKILL_TYPE_WLAN; From patchwork Mon Apr 4 20:36:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jorge Lopez X-Patchwork-Id: 12800848 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4D279C4167B for ; Mon, 4 Apr 2022 21:29:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1382543AbiDDVbF (ORCPT ); Mon, 4 Apr 2022 17:31:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49118 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380586AbiDDUi0 (ORCPT ); Mon, 4 Apr 2022 16:38:26 -0400 Received: from mail-oa1-x34.google.com (mail-oa1-x34.google.com [IPv6:2001:4860:4864:20::34]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D2FFB387AD for ; Mon, 4 Apr 2022 13:36:29 -0700 (PDT) Received: by mail-oa1-x34.google.com with SMTP id 586e51a60fabf-deb9295679so12148209fac.6 for ; Mon, 04 Apr 2022 13:36:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=RFWauzAcxF9+f2KuUsBcynERWFeESDCqiR4hYHgGVl8=; b=LTXPTSHaYS6wDtSlv5vTcZrbAmBWDYs8NKXkUEpDDe2EHjy1/6PjkKaW2lcWQcDHEi 8CmI1TmTQbd4g/vRkH5bQY3WjQV5lsk2Jv5zMuFaFEhqrcb/nSz9sEfnhuZYMkU9Zpad rNdJANe5YT71u4Y93qty6wFojJkR7/J/hGVTAO4IzJkIAD/9AqHKDDZIMYCeYhq/5CNv z1DqPo4r16aTYCbdJdGnE3U8thy2dwz4+J4TEgrzeuJpLLvmE96CritY4+AJmju0L9Mi DW9VqIyin2xO3sQinP6CfcK3xN9hO7tpV6PGvTlPv/O+8LIcU0fBgyy09eKjDpB97T6t +Y0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RFWauzAcxF9+f2KuUsBcynERWFeESDCqiR4hYHgGVl8=; b=o6fMCZ2gXwxSIrs8SrLbGd8Axm1mQTq4aO54Xp6Uj8uw5NIu+bEVKgVp3T+vYvLN1q bnwm1wovk75MMq50q6XEvtDhwJ09li8SiEaaC4Auh354xz0SeR8GQRgF/A8pr9JYSJ0d QJADrM9iR4eDn+2fO3UFLFjrOpzRVHP2U12m7HTwpe9j3SkX/CQofqD0cGF7wqCvnFpT +4NCD9GMkMjvzORRxR3odogqDUbX+6Xcm28BmslrQuyx/YRo0TLpiE3fc/HeHElpEQ9T +xL/MeyBdkfVVsB20tiRXn4grQjEE3fdZr5nic+OUwjghe0v5+WKo/u5S0+OSCiOI/V3 c4+w== X-Gm-Message-State: AOAM531HrucvlNFWhLkxNJdTiYiM4MegYhNQNgV0MejEKSQSIaDEU/He NUn7b5lo6kmN7uIgyyx1ykS4LF5wY0o= X-Google-Smtp-Source: ABdhPJygdWKaULElKzyMlFcE3G7defgDYa0Zd1HlU/rDldSXOCU32rM2IFLX4unj3M1mK8jmJ3AskQ== X-Received: by 2002:a05:6870:c142:b0:dd:d5a3:767c with SMTP id g2-20020a056870c14200b000ddd5a3767cmr548184oad.291.1649104589076; Mon, 04 Apr 2022 13:36:29 -0700 (PDT) Received: from grumpy-vm.hsd1.tx.comcast.net ([2601:2c3:480:7390:c57b:f63e:33f5:caed]) by smtp.gmail.com with ESMTPSA id u20-20020a4a9e94000000b003291f6ac4b2sm3765786ook.28.2022.04.04.13.36.28 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Apr 2022 13:36:28 -0700 (PDT) From: Jorge Lopez X-Google-Original-From: Jorge Lopez To: platform-driver-x86@vger.kernel.org Subject: [PATCH v1 2/6] Update hp_wmi_group to simplify feature addition Date: Mon, 4 Apr 2022 15:36:22 -0500 Message-Id: <20220404203626.4311-3-jorge.lopez2@hp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220404203626.4311-1-jorge.lopez2@hp.com> References: <20220404203626.4311-1-jorge.lopez2@hp.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Introduction of hp_wmi_groups to simplify the integration of driver security features with sysfs. All changes were validated on a HP ZBook Workstation, HP EliteBook x360, and HP EliteBook 850 G8 notebooks. Signed-off-by: Jorge Lopez --- Based on the latest platform-drivers-x86.git/for-next v1-0001-Update-hp_wmi_group-to-simplify-feature-addition patch was broken in two separate patches. This patch is patch 2 of 2 --- drivers/platform/x86/hp-wmi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 667f94bba905..0c7d863b8aab 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -740,7 +740,15 @@ static struct attribute *hp_wmi_attrs[] = { &dev_attr_postcode.attr, NULL, }; -ATTRIBUTE_GROUPS(hp_wmi); + +static const struct attribute_group hp_wmi_group = { + .attrs = hp_wmi_attrs, +}; + +static const struct attribute_group *hp_wmi_groups[] = { + &hp_wmi_group, + NULL, +}; static void hp_wmi_notify(u32 value, void *context) { From patchwork Mon Apr 4 20:36:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jorge Lopez X-Patchwork-Id: 12800858 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A66B4C3527E for ; Mon, 4 Apr 2022 21:37:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1382612AbiDDVbh (ORCPT ); Mon, 4 Apr 2022 17:31:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49138 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380588AbiDDUi1 (ORCPT ); Mon, 4 Apr 2022 16:38:27 -0400 Received: from mail-oa1-x2d.google.com (mail-oa1-x2d.google.com [IPv6:2001:4860:4864:20::2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BF77825EB8 for ; Mon, 4 Apr 2022 13:36:30 -0700 (PDT) Received: by mail-oa1-x2d.google.com with SMTP id 586e51a60fabf-df0940c4eeso12143006fac.8 for ; Mon, 04 Apr 2022 13:36:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=j7RsaSS0HO0J4CreRPJtBU6FZqHLAY7n1b1AmQqGI4w=; b=BqWImTLHznG78bQ9hSoc1s5ZXJc1zbrzvgKyjBgd8kzKvHlnbOiMI8G8rtmtRCAcX8 h+aEqhXmXckUuj36/sVJGgFAbjyZMVhWZAnB2gS951mJQ0voC0dlKi+xpK6UfpzwqCjS 6/gCXCuJaFn6mC6mnDOTsvbxcaW9bfbOfyFPYui5zCovJJSfuxR4F6ka/An7DzP0YkEy HTbOsddTPklGzZWhCCnW33ejUVH5ndal9bjWJPI7WIlPvikavXT28AOc/Vrr/FzNObya VsOn724UouxuYnN9GC5+dMmT+CgsAM5Zm9a7XgRrdOsx1kjvZebPoHFxXQNTy67g7hnf SfpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=j7RsaSS0HO0J4CreRPJtBU6FZqHLAY7n1b1AmQqGI4w=; b=Ku3EEfrdNqRWoBBmOvVJQcEn1EISaiVcOw4BD/BWG/6D67Z9g4IBLoH9mPMSI9cNBQ fXQjwlDhgQyzs8mfvcyiA4H/oI9d17NdlLUTJxLKJLnWNwVLJmQxjj53c+GQLyFhMdk2 3xzEkkLh3xnRc7HgNBSB7FYXs+gvaSTXKsGNc0tyjkLqK7gl8sAjE23KCRL+j5UN0XfZ TBLExzQB50OVDTVNWd7IxKmhDuFIF1PUAa9BSH77wf6xMVpizJOZeBgTdMVaUD2jNRNZ UtAqebTwVqWsQ7OPc9muB1xrx63TJ4YhjDsFUh+0vK56FA0M+w+Ec8tTpdqVOyZSHkui 9dKw== X-Gm-Message-State: AOAM533uFRZhtcuoGditAkEwAu7iEQfSzZ8G3DQcbj9xyUpkzMARAxAc x6dmi4073ptZG29S1maV8jU7NrStSis= X-Google-Smtp-Source: ABdhPJwPc8qFhbEkel/HEXeCf9EWnQmZYyqsuLjslZqGNqXAs6u63dkH8JbQzLjHUSc7pG44O5mdsw== X-Received: by 2002:a05:6870:a79c:b0:dd:e5ad:ba00 with SMTP id x28-20020a056870a79c00b000dde5adba00mr4632oao.64.1649104589785; Mon, 04 Apr 2022 13:36:29 -0700 (PDT) Received: from grumpy-vm.hsd1.tx.comcast.net ([2601:2c3:480:7390:c57b:f63e:33f5:caed]) by smtp.gmail.com with ESMTPSA id u20-20020a4a9e94000000b003291f6ac4b2sm3765786ook.28.2022.04.04.13.36.29 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Apr 2022 13:36:29 -0700 (PDT) From: Jorge Lopez X-Google-Original-From: Jorge Lopez To: platform-driver-x86@vger.kernel.org Subject: [PATCH v1 3/6] Secure Platform Management Security Feature Date: Mon, 4 Apr 2022 15:36:23 -0500 Message-Id: <20220404203626.4311-4-jorge.lopez2@hp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220404203626.4311-1-jorge.lopez2@hp.com> References: <20220404203626.4311-1-jorge.lopez2@hp.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Many HP Commercial PC’s include a feature called Secure Platform Management (SPM), which replaces older password-based BIOS settings management with public key cryptography. PC secure product management begins when a target system is provisioned with cryptographic keys that are used to ensure the integrity of communications between system management utilities and the BIOS. The private key is used by system management utilities to sign payloads containing configuration changes. The BIOS on a target system uses the associated public key to verify the integrity of the payload and apply the changes. At the end of the PC’s lifecycle a signed deprovisioning command restores the factory default state. KEK Certificate (KEK) and Signing Key (SK) get provisioned, and status can be read either as text from the status file or binary from statusbin. /sys/devices/platform/hp-wmi/spm/kek /sys/devices/platform/hp-wmi/spm/sk /sys/devices/platform/hp-wmi/spm/status /sys/devices/platform/hp-wmi/spm/statusbin 'kek' is a write-only file that can be used to configure the RSA public key that will be used by the BIOS to verify signatures when setting the signing key. When written, the bytes should correspond to the KEK certificate (x509 .DER format containing an OU). The size of the certificate must be less than or equal to 4095 bytes. 'sk' is a write-only file that can be used to configure the RSA public key that will be used by the BIOS to verify signatures when configuring BIOS settings and security features. When written, the bytes should correspond to the modulus of the public key. This feature requires "Update hp_wmi_group to simplify feature addition" patch. All changes were validated on a HP ZBook Workstation, HP EliteBook x360, and HP EliteBook 850 G8 notebooks. Signed-off-by: Jorge Lopez --- Based on the latest platform-drivers-x86.git/for-next --- drivers/platform/x86/hp-wmi.c | 195 ++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 0c7d863b8aab..139dc079c1fa 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -120,6 +120,12 @@ enum hp_wmi_commandtype { HPWMI_THERMAL_PROFILE_QUERY = 0x4c, }; +enum hp_wmi_spm_commandtype { + HPWMI_SECUREPLATFORM_GET_STATE = 0x10, + HPWMI_SECUREPLATFORM_SET_KEK = 0x11, + HPWMI_SECUREPLATFORM_SET_SK = 0x12, +}; + enum hp_wmi_gm_commandtype { HPWMI_FAN_SPEED_GET_QUERY = 0x11, HPWMI_SET_PERFORMANCE_MODE = 0x1A, @@ -133,6 +139,7 @@ enum hp_wmi_command { HPWMI_WRITE = 0x02, HPWMI_ODM = 0x03, HPWMI_GM = 0x20008, + HPWMI_SECUREPLATFORM = 0x20010, }; enum hp_wmi_hardware_mask { @@ -193,6 +200,20 @@ struct bios_rfkill2_device_state { u8 unknown[4]; }; +#pragma pack(1) +struct secureplatform_provisioning_data { + u8 state; + u8 version[2]; + u8 reserved1; + u32 features; + u32 nonce; + u8 reserved2[28]; + u8 sk_mod[256]; + u8 kek_mod[256]; +}; + +#pragma pack() + /* 7 devices fit into the 128 byte buffer */ #define HPWMI_MAX_RFKILL2_DEVICES 7 @@ -724,6 +745,179 @@ static ssize_t postcode_store(struct device *dev, struct device_attribute *attr, return count; } +/* Secure Platform Management (SPM) */ + +/* + * spm_statusbin_show - Reports SPM status in binary format + * + * @kobj: Pointer to a kernel object of things that show up as + * directory in the sysfs filesystem. + * @attr: Pointer to list of attributes for the operation + * @buf: Pointer to buffer + * + * Returns number of bytes read on success. Otherwise, + * an HP WMI query specific error code (which is positive) + * -ENODEV if the query was not successful at all + * + */ +static ssize_t spm_statusbin_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_GET_STATE, + HPWMI_SECUREPLATFORM, buf, 0, + sizeof(struct secureplatform_provisioning_data)); + + return ret ? -ENODEV : sizeof(struct secureplatform_provisioning_data); +} + +/* + * spm_status_show - Reads SPM status + * + * @kobj: Pointer to a kernel object of things that show up as + * directory in the sysfs filesystem. + * @attr: Pointer to list of attributes for the operation + * @buf: Pointer to buffer + * + * Returns number of bytes read on success. Otherwise, + * an HP WMI query specific error code (which is positive) + * -ENODEV if the query was not successful at all + * -ENOMEM if cannot allocate required memory size + * + */ +static ssize_t spm_status_show(struct kobject *kobj, struct kobj_attribute + *attr, char *buf) +{ + int ret, i; + struct secureplatform_provisioning_data *data = NULL; + + data = kmalloc(sizeof(struct secureplatform_provisioning_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = spm_statusbin_show(kobj, attr, (char *)data); + if (ret < 0) { + kfree(data); + return ret; + } + + snprintf(buf, PAGE_SIZE, "%sState: %d\n", buf, data->state); + snprintf(buf, PAGE_SIZE, "%sVersion: %d.%d\n", buf, data->version[0], data->version[1]); + + /* state == 0 means secureplatform feature is not configured in BIOS. */ + if (data->state == 0) + goto status_show_exit; + + snprintf(buf, PAGE_SIZE, "%sNonce: %d\n", buf, data->nonce); + snprintf(buf, PAGE_SIZE, "%sFeaturesInUse: %d\n", buf, data->features); + snprintf(buf, PAGE_SIZE, "%sEndorsementKeyMod: {", buf); + + for (i = 255; i >= 0; i--) + snprintf(buf, PAGE_SIZE, "%s %u", buf, data->kek_mod[i]); + + snprintf(buf, PAGE_SIZE, "%s }\n", buf); + snprintf(buf, PAGE_SIZE, "%sSigningKeyMod: {", buf); + + for (i = 255; i >= 0; i--) + snprintf(buf, PAGE_SIZE, "%s %u", buf, data->sk_mod[i]); + snprintf(buf, PAGE_SIZE, "%s }\n", buf); + +status_show_exit: + kfree(data); + return strnlen(buf, PAGE_SIZE); +} + +/* + * spm_kek_store: + * + * Function used to configure the RSA public key that will be used by + * the BIOS to verify signatures when setting the signing key. When + * written, the bytes should correspond to the KEK certificate (x509 + * .DER format containing an OU). The size of the certificate must be + * less than or equal to 4095 bytes. + * + * @kobj: Pointer to a kernel object of things that show up as + * directory in the sysfs filesystem. + * @attr: Pointer to list of attributes for the operation + * @buf: Pointer to buffer + * @count: buffer size in bytes + * + * Returns number of bytes written on success. Otherwise + * an HP WMI query specific error code (which is positive) + * -EINVAL if the query was not successful at all + * + */ +static ssize_t spm_kek_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK, + HPWMI_SECUREPLATFORM, (void *)buf, count, 0); + return ret ? -EINVAL : count; +} + +/* + * spm_sk_store: + * + * Function used to configure the RSA public key that will be used by the + * BIOS to verify signatures when configuring BIOS settings and security + * features. When written, the bytes should correspond to the modulus of + * the public key. The exponent is assumed to be 0x10001. + * + * @kobj: Pointer to a kernel object of things that show up as + * directory in the sysfs filesystem. + * @attr: Pointer to list of attributes for the operation + * @buf: Pointer to buffer + * @count: buffer size in bytes + * + * Returns number of bytes written on success. Otherwise + * an HP WMI query specific error code (which is positive) + * -EINVAL if the query was not successful at all + * + */ +static ssize_t spm_sk_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_SK, + HPWMI_SECUREPLATFORM, (void *)buf, count, 0); + return ret ? -EINVAL : count; +} + + +#define HPWMI_ATTR_RO(_group, _name) \ +static struct kobj_attribute _group##_##_name = \ +__ATTR(_name, 0444, _group##_##_name##_show, NULL) + +#define HPWMI_BINATTR_RO(_group, _name, _size) \ +static struct bin_attribute _group##_##_name = \ +__BIN_ATTR(_name, 0444, _group##_##_name##_read, NULL, _size) + +#define HPWMI_BINATTR_RW(_group, _name, _size) \ +static struct bin_attribute _group##_##_name = \ +__BIN_ATTR(_name, 0444 | 0200, _group##_##_name##_read, _group##_##_name##_write, _size) + +#define HPWMI_ATTR_WO(_group, _name, _command) \ +static struct kobj_attribute _group##_##_name = \ +__ATTR(_name, 0400 | 0200, NULL, _group##_##_name##_store) + +HPWMI_ATTR_RO(spm, status); +HPWMI_ATTR_RO(spm, statusbin); +HPWMI_ATTR_WO(spm, kek, HPWMI_SECUREPLATFORM_SET_KEK); +HPWMI_ATTR_WO(spm, sk, HPWMI_SECUREPLATFORM_SET_SK); + +static struct attribute *spm_attrs[] = { + &spm_status.attr, + &spm_statusbin.attr, + &spm_kek.attr, + &spm_sk.attr, + NULL, +}; + +struct kobject *spm_kobj; + +static const struct attribute_group spm_group = { + .name = "spm", + .attrs = spm_attrs, +}; + static DEVICE_ATTR_RO(display); static DEVICE_ATTR_RO(hddtemp); static DEVICE_ATTR_RW(als); @@ -747,6 +941,7 @@ static const struct attribute_group hp_wmi_group = { static const struct attribute_group *hp_wmi_groups[] = { &hp_wmi_group, + &spm_group, NULL, }; From patchwork Mon Apr 4 20:36:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jorge Lopez X-Patchwork-Id: 12800857 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 86B75C3527D for ; Mon, 4 Apr 2022 21:37:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1382596AbiDDVbc (ORCPT ); Mon, 4 Apr 2022 17:31:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380589AbiDDUi1 (ORCPT ); Mon, 4 Apr 2022 16:38:27 -0400 Received: from mail-oi1-x236.google.com (mail-oi1-x236.google.com [IPv6:2607:f8b0:4864:20::236]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10CA9387AD for ; Mon, 4 Apr 2022 13:36:31 -0700 (PDT) Received: by mail-oi1-x236.google.com with SMTP id i7so11287923oie.7 for ; Mon, 04 Apr 2022 13:36:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=qk4dHCzq6OS+6wQmPbPKS2u/ZPFPZRiwLoUaUgtocjI=; b=LJN06XJjDnKj1VH389AYLaJljTHjYQNI0eHoJEze1g6O6QFR9zKfDTbr6gaWdms2/t hxIdMj9jeg/w13PQfAsvfNlrkGRlMBRLi2HwmFz57wkmbnSyoirfEDLAN2G9cPu1leGL sGRWyw0IvHIYKy1xZkcRZlyx3Q9EhrSOprXtukOdhjigG+27pVwGt9egscn2nGyrHyli 1VDB9byZzoVE/A8/E0syF2k/FS6RWg+XPp/A1YyHHYQg5KHSrBbetznIaK1vhJJItZK0 w/VLY3KeaEFBbp8L7KLwLjMhG1yN+hezIk9gBYUD3W5US+x+QI0BramTjQUAaDoA/o6K yQsA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=qk4dHCzq6OS+6wQmPbPKS2u/ZPFPZRiwLoUaUgtocjI=; b=W5fOWU9TXsjuSQMKfGsAnCumjTbkB2/RDcLQnC+6ejB+eRrf1C0A0rzAxdh5YuroAQ Ym33yfxnxI7F/GL9EHoxqCufalI/Xa3N3v0uIwWAa/bpnj+lxpGBqKPlVpf8BZ2dc2Bp 1L5jRkQWTAWplQVYytyUzcD/IuktSYuoHlYy6qISZwlIEt3cgBybW32mfmdtF3y70bl/ yqBZDOeielng6uG80pXRfEbpjQauVT36ymXSDEvrciu+zP52TZwSF/B3vdxC/ufDjqYC ChebK4qGun77riqbUUt0vYCFlPcvOHKYpPOD0Y3n4J2pAouFKwqHKb9OOolGoYegP7rG Reiw== X-Gm-Message-State: AOAM530oVDKiqjgN1UcTckdZ0a85gkCZe0hetanUTvjF3vW9mzLTAEq/ 9Si7lsTz4qrcVXmLNDlI28syM4pLv30= X-Google-Smtp-Source: ABdhPJyZWcGB+cMarFwdjQLwvJRkMG8zONjJGzyN4QMPsrVUqZfrviCb8VhABn7TxkoivMPIZJXDjg== X-Received: by 2002:a05:6808:f89:b0:2f9:7676:be3a with SMTP id o9-20020a0568080f8900b002f97676be3amr26080oiw.21.1649104590194; Mon, 04 Apr 2022 13:36:30 -0700 (PDT) Received: from grumpy-vm.hsd1.tx.comcast.net ([2601:2c3:480:7390:c57b:f63e:33f5:caed]) by smtp.gmail.com with ESMTPSA id u20-20020a4a9e94000000b003291f6ac4b2sm3765786ook.28.2022.04.04.13.36.29 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Apr 2022 13:36:29 -0700 (PDT) From: Jorge Lopez X-Google-Original-From: Jorge Lopez To: platform-driver-x86@vger.kernel.org Subject: [PATCH v1 4/6] Sure Start Security Feature Date: Mon, 4 Apr 2022 15:36:24 -0500 Message-Id: <20220404203626.4311-5-jorge.lopez2@hp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220404203626.4311-1-jorge.lopez2@hp.com> References: <20220404203626.4311-1-jorge.lopez2@hp.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Sure Start provides advanced firmware protection and resiliency by identifying and repairing unauthorized BIOS changes. It maintains an audit log of these events and other important system configuration changes. The following sysfs entries can be used to read the contents of the audit log. /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count /sys/devices/platform/hp-wmi/sure_start/audit_log_entries 'audit_log_entry_count' is a read-only file that returns the number of existing audit log events available to be read 'audit_log_entries' is a read-only file that returns the events in the log This feature requires "Update hp_wmi_group to simplify feature addition" patch. All changes were validated on a HP ZBook Workstation, HP EliteBook x360, and HP EliteBook 850 G8 notebooks. Signed-off-by: Jorge Lopez --- Based on the latest platform-drivers-x86.git/for-next --- drivers/platform/x86/hp-wmi.c | 108 ++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 139dc079c1fa..918e3eaf1b67 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -126,6 +126,11 @@ enum hp_wmi_spm_commandtype { HPWMI_SECUREPLATFORM_SET_SK = 0x12, }; +enum hp_wmi_surestart_commandtype { + HPWMI_SURESTART_GET_LOG_COUNT = 0x01, + HPWMI_SURESTART_GET_LOG = 0x02, +}; + enum hp_wmi_gm_commandtype { HPWMI_FAN_SPEED_GET_QUERY = 0x11, HPWMI_SET_PERFORMANCE_MODE = 0x1A, @@ -138,6 +143,7 @@ enum hp_wmi_command { HPWMI_READ = 0x01, HPWMI_WRITE = 0x02, HPWMI_ODM = 0x03, + HPWMI_SURESTART = 0x20006, HPWMI_GM = 0x20008, HPWMI_SECUREPLATFORM = 0x20010, }; @@ -851,6 +857,7 @@ static ssize_t spm_kek_store(struct kobject *kobj, { int ret = hp_wmi_perform_query(HPWMI_SECUREPLATFORM_SET_KEK, HPWMI_SECUREPLATFORM, (void *)buf, count, 0); + return ret ? -EINVAL : count; } @@ -918,6 +925,106 @@ static const struct attribute_group spm_group = { .attrs = spm_attrs, }; +/* Sure Start functions */ + +#define LOG_MAX_ENTRIES 254 +#define LOG_ENTRY_SIZE 16 + +/* + * sure_start_audit_log_entry_count_show - Reports the number of + * existing audit log entries available + * to be read + * + * @kobj: Pointer to a kernel object of things that show up as directory + * in the sysfs filesystem. + * @attr: Pointer to list of attributes for the operation + * @buf: Pointer to buffer + * + * Returns number of existing audit log entries available to be read, + * audit log entry size, and maximum number of entries + * supported. Otherwise, an HP WMI query specific error code + * (which is negative) + * + * [No of entries],[log entry size],[Max number of entries supported] + */ +static ssize_t sure_start_audit_log_entry_count_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int ret; + u32 count = 0; + + ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG_COUNT, HPWMI_SURESTART, + &count, 0, sizeof(count)); + if (ret < 0) + return ret; + + return snprintf(buf, PAGE_SIZE, "%d,%d,%d\n", count, LOG_ENTRY_SIZE, LOG_MAX_ENTRIES); +} + +/* + * sure_start_audit_log_entries_show() - Return all entries found in log file + * + * @kobj: Pointer to a kernel object of things that show up as + * directory in the sysfs filesystem. + * @attr: Pointer to list of attributes for the operation + * @buf: Pointer to buffer + * + * Returns number of bytes needed to read all audit logs entries to be read. + * Otherwise, an HP WMI query specific error code (which is negative) + * -EFAULT if the audit logs size exceeds 4KB + * + */ +static ssize_t sure_start_audit_log_entries_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int ret; + int i; + u32 count = 0; + + // Get the number of event logs + ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG_COUNT, HPWMI_SURESTART, + &count, 1, 4); + + /* + * The show() api will not work if the audit logs ever go + * beyond 4KB + */ + if (count * LOG_ENTRY_SIZE > PAGE_SIZE) + return -EFAULT; + + if (ret < 0) + return ret; + + /* + * We are guaranteed the buffer is 4KB so today all the event + * logs will fit + */ + for (i = 0; ((i < count) & (ret >= 0)); i++) { + *buf = (i + 1); + ret = hp_wmi_perform_query(HPWMI_SURESTART_GET_LOG, + HPWMI_SURESTART, + buf, 1, 128); + if (ret >= 0) + buf += LOG_ENTRY_SIZE; + } + + return (count * LOG_ENTRY_SIZE); +} + +HPWMI_ATTR_RO(sure_start, audit_log_entry_count); +HPWMI_ATTR_RO(sure_start, audit_log_entries); + +static struct attribute *sure_start_attrs[] = { + &sure_start_audit_log_entry_count.attr, + &sure_start_audit_log_entries.attr, + NULL, +}; + +static const struct attribute_group sure_start_group = { + .name = "sure_start", + .attrs = sure_start_attrs, +}; + static DEVICE_ATTR_RO(display); static DEVICE_ATTR_RO(hddtemp); static DEVICE_ATTR_RW(als); @@ -942,6 +1049,7 @@ static const struct attribute_group hp_wmi_group = { static const struct attribute_group *hp_wmi_groups[] = { &hp_wmi_group, &spm_group, + &sure_start_group, NULL, }; From patchwork Mon Apr 4 20:36:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jorge Lopez X-Patchwork-Id: 12800859 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE6C8C35280 for ; Mon, 4 Apr 2022 21:37:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1382605AbiDDVbf (ORCPT ); Mon, 4 Apr 2022 17:31:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49160 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380591AbiDDUia (ORCPT ); Mon, 4 Apr 2022 16:38:30 -0400 Received: from mail-oi1-x234.google.com (mail-oi1-x234.google.com [IPv6:2607:f8b0:4864:20::234]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0344526AC8 for ; Mon, 4 Apr 2022 13:36:32 -0700 (PDT) Received: by mail-oi1-x234.google.com with SMTP id k10so11342366oia.0 for ; Mon, 04 Apr 2022 13:36:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=I6XJfRa3tWy2ZXcKFV/ALuQ/HqSbTiXDfFBkfZV7aQw=; b=ixZ5zNCyG3ntLAXVWwhYPOgCXOf4U+Rp4kCFbHtFgNzzR/2ravEfS9yinnQNcLp5Vb pMgl2qmiwp+jPDlXT/9qUx4C/ktUxdO8ZbKlBetGyrUlQ5DlPnT7rONC5upaqmOQfxmJ u2OYy0GrRkvCECGfCAlUFLka8Vz+wDuCZYAlt92eEKPZ8Xf+Z1u7UZsrJ+KpBEKqipkQ jpbeEQ3AADf8/WkVNFwCKtgEbfka+R9xsbVsNqCsu9hroXMtWB0H0kJKUBddHT6NuAGR YbJttR4W4obG09xVMjZhs//WFH0SL5KlxFmLmhdNaV0G0jYS6xmeCjbeSXZYseIbn43N GeHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=I6XJfRa3tWy2ZXcKFV/ALuQ/HqSbTiXDfFBkfZV7aQw=; b=J3cYCou5gus2fX/3+rBoeRVJNtwAO87pEddhNdc52dJ91BXk5AiIVYS4CglZQAYjAQ k2127QNWJEf0J0exUnhzVtrSdGmtScEUBf+NZbwBDQ5Q38GFjQ1NyL5WvkOi09uwZ5GN Jkjioai4XqEumO1HSefi+MHRb0bGW39sDbYICocR2kQNapaW/kBpjsvsKjlbcwuRHFA2 UYDzUXyZ6oPLnyPqYl88w364cM4bVZBfJ8A894qI6bsfN6pXkXWax9oH3jZ9e9HB0FjV bugE6hoqPenTj2QQB2ZUNCHmFtWdVBxTzm3k5SUzAm7ur7OOIJXS5rv57haszwSjLpuA HFNA== X-Gm-Message-State: AOAM533/A9JVie6vEEnLIKpnPb611+MhgFa26db5NGy8ew6/jbkZbfDk nF/WZOLEts7eu+2duZ32QKRwpXJmq7I= X-Google-Smtp-Source: ABdhPJwWMAGL2dpWNYHVPLr8pWIOw5NN4PDlhFMAbMSHdGQxHAFcMR2s2bIeRXUhCt0Odp75EJvKHQ== X-Received: by 2002:aca:1c0f:0:b0:2ed:22b4:9205 with SMTP id c15-20020aca1c0f000000b002ed22b49205mr5108oic.118.1649104590799; Mon, 04 Apr 2022 13:36:30 -0700 (PDT) Received: from grumpy-vm.hsd1.tx.comcast.net ([2601:2c3:480:7390:c57b:f63e:33f5:caed]) by smtp.gmail.com with ESMTPSA id u20-20020a4a9e94000000b003291f6ac4b2sm3765786ook.28.2022.04.04.13.36.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Apr 2022 13:36:30 -0700 (PDT) From: Jorge Lopez X-Google-Original-From: Jorge Lopez To: platform-driver-x86@vger.kernel.org Subject: [PATCH v1 5/6] Sure Admin Security Feature Date: Mon, 4 Apr 2022 15:36:25 -0500 Message-Id: <20220404203626.4311-6-jorge.lopez2@hp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220404203626.4311-1-jorge.lopez2@hp.com> References: <20220404203626.4311-1-jorge.lopez2@hp.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org HP Commercial PC’s have several BIOS settings that control its behaviour and capabilities, many of which are related to security. To prevent unauthorized changes to these settings, the system can be configured to use a Sure Admin cryptographic signature-based authorization string that the BIOS will use to verify authorization to modify the setting. Behind the scenes, Sure Admin uses Secure Platform Management (SPM) and WMI 'settings' is a file associated with Sure Admin. BIOS settings can be read or written through the Sure Admin settings file in sysfs /sys/devices/platform/hp-wmi/sure_admin/settings Expected data format to update BIOS setting [BIOS setting],[new value],[auth token] Sample settings reported data { "Class": "HPBIOS_BIOSEnumeration", "Name": "USB Storage Boot", "Path": "\\Advanced\\Boot Options", "IsReadOnly": 0, ... "Value": "Enable", "Size": 2, "PossibleValues": [ "Disable", "Enable" ] } This feature requires "Update hp_wmi_group to simplify feature addition" patch. All changes were validated on a HP ZBook Workstation, HP EliteBook x360, and HP EliteBook 850 G8 notebooks. Signed-off-by: Jorge Lopez --- Based on the latest platform-drivers-x86.git/for-next --- drivers/platform/x86/hp-wmi.c | 977 ++++++++++++++++++++++++++++++++++ 1 file changed, 977 insertions(+) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 918e3eaf1b67..b72ca18b77a6 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -27,6 +27,7 @@ #include #include #include +#include MODULE_AUTHOR("Matthew Garrett "); MODULE_DESCRIPTION("HP laptop WMI hotkeys driver"); @@ -37,8 +38,16 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4" + #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95 +#define HPWMI_STRING_GUID "988D08E3-68F4-4c35-AF3E-6A1B8106F83C" +#define HPWMI_INTEGER_GUID "8232DE3D-663D-4327-A8F4-E293ADB9BF05" +#define HPWMI_ENUMERATION_GUID "2D114B49-2DFB-4130-B8FE-4A3C09E75133" +#define HPWMI_ORDEREDLIST_GUID "14EA9746-CE1F-4098-A0E0-7045CB4DA745" +#define HPWMI_PASSWORD_GUID "322F2028-0F84-4901-988E-015176049E2D" +#define HPWMI_SETBIOSSETTING_GUID "1F4C91EB-DC5C-460b-951D-C7CB9B4B8D5E" + /* DMI board names of devices that should use the omen specific path for * thermal profiles. * This was obtained by taking a look in the windows omen command center @@ -1025,6 +1034,973 @@ static const struct attribute_group sure_start_group = { .attrs = sure_start_attrs, }; + +static int convert_hexstr_to_str(char **hex, int input_len, char **str, int *len) +{ + int ret = 0; + int new_len = 0; + char tmp[] = "0x00"; + char *input = *hex; + char *new_str = NULL; + int ch; + int i; + + if (input_len <= 0 || hex == NULL || str == NULL || len == NULL) + return -EINVAL; + + *len = 0; + *str = NULL; + + new_str = kmalloc(input_len, GFP_KERNEL); + if (!new_str) + return -ENOMEM; + + for (i = 0; i < input_len; i += 5) { + strncpy(tmp, input + i, strlen(tmp)); + ret = kstrtoint(tmp, 16, &ch); + if (ret) { + new_len = 0; + break; + } + + if (ch == '\\') + new_str[new_len++] = '\\'; + + new_str[new_len++] = ch; + if (ch == '\0') + break; + } + + if (new_len) { + new_str[new_len] = '\0'; + *str = krealloc(new_str, (new_len + 1) * sizeof(char), GFP_KERNEL); + if (*str) + *len = new_len; + else + ret = -ENOMEM; + } + + if (ret) + kfree(new_str); + return ret; +} + +/* + * hp_wmi_get_setting_object() - Get an ACPI object by GUID and instance + * + * @guid: GUID associated with the ACPI list of managed objects + * @instance: Instance index to query on the ACPI list + * @obj: The output ACPI object of type ACPI_TYPE_PACKAGE + * or ACPI_TYPE_BUFFER (freed by the callee) + * + * Returns zero on success. Otherwise,an error inherited from + * wmi_query_block(). It returns a obj by parameter if + * the query returned object of type buffer or package, + * otherwise, a null obj is returned. + * + * Note: obj should be freed by the callee once it is finished working with it + */ +static int hp_wmi_get_setting_object(char *guid, int instance, + union acpi_object **obj) +{ + struct acpi_buffer output = { ACPI_ALLOCATE_LOCAL_BUFFER, NULL }; + union acpi_object *tmp = NULL; + int ret; + + ret = wmi_query_block(guid, instance, &output); + if (ACPI_SUCCESS(ret) && output.pointer != NULL) { + tmp = output.pointer; + if (tmp->type == ACPI_TYPE_BUFFER || tmp->type == ACPI_TYPE_PACKAGE) + *obj = output.pointer; + else { + kfree(tmp); + *obj = NULL; + } + } + + return ret; +} + + +static int get_string_from_buffer(u16 **buffer, char **str) +{ + u16 *ptr = *buffer; + u16 ptrlen; + + u16 size; + int i; + char *output = NULL; + int escape = 0; + + ptrlen = *(ptr++); + size = ptrlen / 2; + + if (size == 0) + goto cleanup_exit; + + for (i = 0; i < size; i++) + if (ptr[i] == '\\') + escape++; + + size += escape; + *str = kcalloc(size + 1, sizeof(char), GFP_KERNEL); + if (!*str) + return -ENOMEM; + + output = *str; + + /* + * convert from UTF-16 unicode to ASCII + */ + utf16s_to_utf8s(ptr, ptrlen, UTF16_HOST_ENDIAN, output, size); + + if (escape == 0) { + ptr += (ptrlen / 2); + goto cleanup_exit; + } + /* + * Convert escape characters only when found + */ + for (i = 0; i < size; i++) { + if (*ptr == '\\') + output[i++] = '\\'; + output[i] = *ptr; + ptr++; + } + +cleanup_exit: + *buffer = ptr; + return 0; +} + +static int get_integer_from_buffer(int **buffer, int *integer) +{ + int *ptr = PTR_ALIGN(*buffer, 4); + *integer = *(ptr++); + *buffer = ptr; + return 0; +} + + +// Sure Admin functions +enum hp_wmi_data_type { + HPWMI_STRING_TYPE, + HPWMI_INTEGER_TYPE, + HPWMI_ENUMERATION_TYPE, + HPWMI_ORDEREDLIST_TYPE, + HPWMI_PASSWORD_TYPE, +}; + +#define HP_WMI_COMMON_ELEMENTS \ + "Name", \ + "Value", \ + "Path", \ + "IsReadOnly", \ + "DisplayInUI", \ + "RequiresPhysicalPresence", \ + "Sequence", \ + "PrerequisiteSize", \ + "SecurityLevel" + +const char *hp_wmi_string_elements[] = { + HP_WMI_COMMON_ELEMENTS, + "MinLength", + "MaxLength" +}; + +const char *hp_wmi_integer_elements[] = { + HP_WMI_COMMON_ELEMENTS, + "LowerBound", + "UpperBound", + "IntValue" +}; + +const char *hp_wmi_enumeration_elements[] = { + HP_WMI_COMMON_ELEMENTS, + "CurrentValue", + "Size" +}; + +const char *hp_wmi_orderedlist_elements[] = { + HP_WMI_COMMON_ELEMENTS, + "Size" +}; + +const char *hp_wmi_password_elements[] = { + HP_WMI_COMMON_ELEMENTS, + "MinLength", + "MaxLength", + "Size", + "SupportedEncoding", + "IsSet" +}; + +const char **hp_wmi_elements[] = { + hp_wmi_string_elements, + hp_wmi_integer_elements, + hp_wmi_enumeration_elements, + hp_wmi_orderedlist_elements, + hp_wmi_password_elements +}; + +const int hp_wmi_elements_count[] = { + ARRAY_SIZE(hp_wmi_string_elements), + ARRAY_SIZE(hp_wmi_integer_elements), + ARRAY_SIZE(hp_wmi_enumeration_elements), + ARRAY_SIZE(hp_wmi_orderedlist_elements), + ARRAY_SIZE(hp_wmi_password_elements) +}; + +const char *hp_wmi_classes[] = { + "HPBIOS_BIOSString", + "HPBIOS_BIOSInteger", + "HPBIOS_BIOSEnumeration", + "HPBIOS_BIOSOrderedList", + "HPBIOS_BIOSPassword" +}; + +static DEFINE_MUTEX(buf_mutex); +static int settings_buffer_size; +static int buf_alloc_size; +static char *hp_bios_settings_buffer; + + +static int append_package_elements_to_buffer(union acpi_object *obj, + char *buf, int alloc_size, enum hp_wmi_data_type type) +{ + int i; + union acpi_object *pobj = NULL; + char *value = NULL; + int value_len; + char *tmpstr = NULL; + char *part_tmp = NULL; + int tmp_len = 0; + char *part = NULL; + int status = 0; + int size = 0; + int buf_size; + + if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj) + return -EINVAL; + + if (obj->type != ACPI_TYPE_PACKAGE) + return -EINVAL; + + buf_size = snprintf(buf, alloc_size, "%s{\n", buf); + buf_size = snprintf(buf, alloc_size, "%s\t\"Class\": \"%s\",\n", buf, hp_wmi_classes[type]); + + for (i = 0; i < 3; i++) { + pobj = &(obj->package.elements[i]); + if (pobj->type == ACPI_TYPE_STRING) { + status = convert_hexstr_to_str(&pobj->string.pointer, + pobj->string.length, &value, &value_len); + if (ACPI_FAILURE(status)) + continue; + /* + * Skip 'Value' (HP_WMI_COMMON_ELEMENTS) since + * 'CurrentValue' is reported. + */ + if (type != HPWMI_ENUMERATION_TYPE || i != 1) + buf_size = snprintf(buf, alloc_size, + "%s\t\"%s\": \"%s\",\n", + buf, + hp_wmi_elements[type][i], value); + + } + kfree(value); + value = NULL; + } + + for (i = 3; i < hp_wmi_elements_count[type]; i++) { + pobj = &(obj->package.elements[i]); + + if (type == HPWMI_ENUMERATION_TYPE && + i == 9 && + pobj->type == ACPI_TYPE_STRING) { + /* + * Report "CurrentValue" as "Value" + */ + status = convert_hexstr_to_str(&pobj->string.pointer, + pobj->string.length, + &value, &value_len); + if (ACPI_FAILURE(status)) + continue; + + buf_size = snprintf(buf, alloc_size, + "%s\t\"Value\": \"%s\",\n", + buf, value); + kfree(value); + value = NULL; + + } else if (type == HPWMI_PASSWORD_TYPE && + i == 12 && + pobj->type == ACPI_TYPE_STRING) { + /* + * Report list of "SupportEncoding" + * + * "SupportedEncoding": [ + * "utf-16" + * ], + * + */ + + buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n", + buf, hp_wmi_elements[type][i]); + while (size--) { + pobj = &(obj->package.elements[i]); + status = convert_hexstr_to_str(&pobj->string.pointer, + pobj->string.length, + &value, &value_len); + if (ACPI_FAILURE(status)) + continue; + + if (size) { + buf_size = snprintf(buf, alloc_size, + "%s\t\t\"%s\",\n", buf, value); + i++; + } else + buf_size = snprintf(buf, alloc_size, + "%s\t\t\"%s\"\n", buf, value); + + kfree(value); + value = NULL; + + } + buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf); + continue; + + } else if (pobj->type == ACPI_TYPE_INTEGER) { + /* + * Report "PrerequisiteSize" and "Size" values + * ... + * "PrerequisiteSize": 1, + * ... + * "Size": 2, + * ... + */ + if (i == 7) + size = pobj->integer.value; + else if (type == HPWMI_ORDEREDLIST_TYPE && i == 9) + size = pobj->integer.value; + else if (type == HPWMI_ENUMERATION_TYPE && i == 10) + size = pobj->integer.value; + else if (type == HPWMI_PASSWORD_TYPE && i == 11) + size = pobj->integer.value; + + buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": %lld,\n", buf, + hp_wmi_elements[type][i], pobj->integer.value); + } + } + + if (type == HPWMI_ENUMERATION_TYPE) { + buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\": [\n", buf); + for (i = 0; i < size; i++) { + pobj = &(obj->package.elements[i + hp_wmi_elements_count[type]]); + + status = convert_hexstr_to_str(&pobj->string.pointer, + pobj->string.length, + &value, &value_len); + if (ACPI_FAILURE(status)) + break; + + /* + * Report list of "PossibleValues" of size + * "Size" + * ... + * "Size": 2, + * "PossibleValues": [ + * "Disable", + * "Enable"] + */ + if (i == (size - 1)) + buf_size = snprintf(buf, alloc_size, + "%s\t\t\"%s\"\n", buf, value); + else + buf_size = snprintf(buf, alloc_size, + "%s\t\t\"%s\",\n", buf, value); + kfree(value); + value = NULL; + } + buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf); + } + + if (type == HPWMI_ORDEREDLIST_TYPE) { + buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n", buf); + if (size <= 0) + goto finish_ordered_list; + + pobj = &(obj->package.elements[hp_wmi_elements_count[type]]); + status = convert_hexstr_to_str(&pobj->string.pointer, + pobj->string.length, &value, &value_len); + if (ACPI_FAILURE(status)) + goto finish_ordered_list; + + /* + * Ordered list data is stored in hex and comma separated format + * Convert the data and split it to show each element + */ + status = convert_hexstr_to_str(&value, value_len, &tmpstr, &tmp_len); + if (ACPI_FAILURE(status)) + goto finish_ordered_list; + + part_tmp = tmpstr; + part = strsep(&part_tmp, ","); + while (part) { + buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, part); + part = strsep(&part_tmp, ","); + if (part) + buf_size = snprintf(buf, alloc_size, "%s,\n", buf); + else + buf_size = snprintf(buf, alloc_size, "%s\n", buf); + } + } + +finish_ordered_list: + if (type == HPWMI_ORDEREDLIST_TYPE) + buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf); + + /* + * remove trailing comma + */ + if (buf_size > 3) + buf[buf_size - 2] = ' '; + + kfree(tmpstr); + kfree(value); + return snprintf(buf, alloc_size, "%s},\n", buf); +} + +static int append_buffer_elements_to_buffer(union acpi_object *obj, + char *buf, int alloc_size, enum hp_wmi_data_type type) +{ + int buf_size; + int status; + char *str = NULL; + int i; + int j; + int integer; + int size = 0; + + if (type >= ARRAY_SIZE(hp_wmi_classes) || !buf || !obj) + return -EINVAL; + + if (obj->type != ACPI_TYPE_BUFFER) + return -EINVAL; + + buf_size = snprintf(buf, alloc_size, "%s{\n", buf); + buf_size = snprintf(buf, alloc_size, "%s\t\"Class\": \"%s\",\n", buf, hp_wmi_classes[type]); + + for (i = 0; i < 3; i++) { + status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str); + if (ACPI_SUCCESS(status)) { + /* + * Skip 'Value' (HP_WMI_COMMON_ELEMENTS) since + * 'CurrentValue' is reported. + */ + if (type != HPWMI_ENUMERATION_TYPE || i != 1) + buf_size = snprintf(buf, alloc_size, + "%s\t\"%s\": \"%s\",\n", + buf, + hp_wmi_elements[type][i], str); + } + kfree(str); + str = NULL; + + } + + for (i = 3; i < hp_wmi_elements_count[type]; i++) { + if (type == HPWMI_ENUMERATION_TYPE && i == 9) { + status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str); + if (ACPI_SUCCESS(status)) { + /* + * Report "CurrentValue" as "Value" + */ + buf_size = snprintf(buf, alloc_size, + "%s\t\"Value\": \"%s\",\n", buf, str); + } + kfree(str); + str = NULL; + continue; + + } else if (type == HPWMI_PASSWORD_TYPE && i == 12) { + /* + * Report list of "SupportEncoding" + * + * "SupportedEncoding": [ + * "utf-16" + * ], + * + */ + + buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": [\n", + buf, hp_wmi_elements[type][i]); + for (j = 0; j < size; j++) { + status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str); + if (ACPI_SUCCESS(status)) { + if (j == size - 1) + buf_size = snprintf(buf, alloc_size, + "%s\t\t\"%s\"\n", buf, str); + else + buf_size = snprintf(buf, alloc_size, + "%s\t\t\"%s\",\n", buf, str); + } + kfree(str); + str = NULL; + } + buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf); + continue; + } + + size = 0; + status = get_integer_from_buffer((int **)&obj->buffer.pointer, &integer); + if (ACPI_SUCCESS(status)) { + /* + * Report "PrerequisiteSize" and "Size" values + * ... + * "PrerequisiteSize": 1, + * ... + * "Size": 2, + * ... + */ + if (i == 7) + size = integer; + else if (type == HPWMI_ENUMERATION_TYPE && i == 10) + size = integer; + else if (type == HPWMI_ORDEREDLIST_TYPE && i == 9) + size = integer; + else if (type == HPWMI_PASSWORD_TYPE && i == 11) + size = integer; + + buf_size = snprintf(buf, alloc_size, "%s\t\"%s\": %d,\n", buf, + hp_wmi_elements[type][i], integer); + } + + if (size > 20) + pr_warn("%s exceeded the maximum number of elements supported or data may be malformed\n", + hp_wmi_elements[type][i]); + + if (ACPI_SUCCESS(status) && i == 7) { + buf_size = snprintf(buf, alloc_size, "%s\t\"Prerequisites\": [\n", buf); + for (j = 0; j < size; j++) { + status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str); + if (ACPI_SUCCESS(status)) { + buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, str); + + if (j == size - 1) + buf_size = snprintf(buf, alloc_size, "%s\n", buf); + else + buf_size = snprintf(buf, alloc_size, "%s,\n", buf); + + } + kfree(str); + str = NULL; + } + buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf); + } + } + + if (type == HPWMI_ENUMERATION_TYPE || type == HPWMI_ORDEREDLIST_TYPE) { + if (type == HPWMI_ENUMERATION_TYPE) + buf_size = snprintf(buf, alloc_size, "%s\t\"PossibleValues\": [\n", buf); + else + buf_size = snprintf(buf, alloc_size, "%s\t\"Elements\": [\n", buf); + + for (i = 0; i < size; i++) { + status = get_string_from_buffer((u16 **)&obj->buffer.pointer, &str); + if (ACPI_SUCCESS(status)) { + buf_size = snprintf(buf, alloc_size, "%s\t\t\"%s\"", buf, str); + + if (i == size - 1) + buf_size = snprintf(buf, alloc_size, "%s\n", buf); + else + buf_size = snprintf(buf, alloc_size, "%s,\n", buf); + + } + kfree(str); + str = NULL; + } + buf_size = snprintf(buf, alloc_size, "%s\t],\n", buf); + } + + /* + * remove trailing comma + */ + if (buf_size > 3) + buf[buf_size - 2] = ' '; + + return snprintf(buf, alloc_size, "%s},\n", buf); +} + +static int hp_bios_settings_free_buffer(void) +{ + mutex_lock(&buf_mutex); + kfree(hp_bios_settings_buffer); + settings_buffer_size = 0; + buf_alloc_size = 0; + mutex_unlock(&buf_mutex); + + return 0; +} + +static int hp_bios_settings_realloc_buffer(char **buf, int *buf_size, + int *alloc_size, + struct mutex *buf_mutex) +{ + int new_buffer_size; + char *new_buf = NULL; + int ret = 0; + + if (*buf_size + PAGE_SIZE >= *alloc_size) { + new_buffer_size = buf_alloc_size + 2 * PAGE_SIZE; + + mutex_lock(buf_mutex); + new_buf = krealloc(*buf, new_buffer_size, GFP_KERNEL); + mutex_unlock(buf_mutex); + if (new_buf) { + mutex_lock(buf_mutex); + *buf = new_buf; + *alloc_size = ksize(new_buf); + mutex_unlock(buf_mutex); + } else { + hp_bios_settings_free_buffer(); + ret = -ENOMEM; + } + } + + return ret; +} + +static int append_settings_to_buffer(char *guid, int type, char **buf, + int *buf_size, int *alloc_size, + struct mutex *buf_mutex) +{ + union acpi_object *obj = NULL; + int ret = 0; + int status = 0; + int instance = 0; + + /* + * Query all the instances until to receive a AE_BAD_PARAMETER + */ + do { + ret = hp_wmi_get_setting_object(guid, instance++, &obj); + if (ACPI_SUCCESS(ret) && obj != NULL) { + status = 0; + if (obj->type == ACPI_TYPE_PACKAGE) { + mutex_lock(buf_mutex); + status = append_package_elements_to_buffer(obj, + *buf, *alloc_size, type); + if (status > 0) + *buf_size = status; + mutex_unlock(buf_mutex); + + } else if (obj->type == ACPI_TYPE_BUFFER) { + mutex_lock(buf_mutex); + status = append_buffer_elements_to_buffer(obj, + *buf, *alloc_size, type); + if (status > 0) + *buf_size = status; + mutex_unlock(buf_mutex); + + } else + pr_warn("The retrieved object type(%d) is not supported yet\n", + obj->type); + + ret = hp_bios_settings_realloc_buffer(buf, buf_size, alloc_size, buf_mutex); + } + + kfree(obj); + obj = NULL; + + } while (ACPI_SUCCESS(ret)); + + /* + * AE_BAD_PARAMETER means the loop ended by exhaustion + */ + if (ret == AE_BAD_PARAMETER) + ret = 0; + + return ret; +} + +static int hp_bios_settings_fill_buffer(void) +{ + int status = 0; + int initial_buffer_size = 20 * PAGE_SIZE; + + mutex_lock(&buf_mutex); + hp_bios_settings_buffer = kmalloc(initial_buffer_size, GFP_KERNEL); + mutex_unlock(&buf_mutex); + if (!hp_bios_settings_buffer) + return -ENOMEM; + + mutex_lock(&buf_mutex); + buf_alloc_size = ksize(hp_bios_settings_buffer); + settings_buffer_size = snprintf(hp_bios_settings_buffer, + buf_alloc_size, "[\n"); + mutex_unlock(&buf_mutex); + + status = append_settings_to_buffer(HPWMI_STRING_GUID, + HPWMI_STRING_TYPE, &hp_bios_settings_buffer, + &settings_buffer_size, &buf_alloc_size, &buf_mutex); + if (ACPI_FAILURE(status)) + pr_err("error 0x%x occurred retrieving string instances\n", status); + + status = append_settings_to_buffer(HPWMI_INTEGER_GUID, + HPWMI_INTEGER_TYPE, &hp_bios_settings_buffer, + &settings_buffer_size, &buf_alloc_size, &buf_mutex); + if (ACPI_FAILURE(status)) + pr_err("error 0x%x occurred retrieving integer instances\n", status); + + status = append_settings_to_buffer(HPWMI_ENUMERATION_GUID, + HPWMI_ENUMERATION_TYPE, &hp_bios_settings_buffer, + &settings_buffer_size, &buf_alloc_size, &buf_mutex); + if (ACPI_FAILURE(status)) + pr_err("error 0x%x occurred retrieving enumeration instances\n", status); + + status = append_settings_to_buffer(HPWMI_ORDEREDLIST_GUID, + HPWMI_ORDEREDLIST_TYPE, &hp_bios_settings_buffer, + &settings_buffer_size, &buf_alloc_size, &buf_mutex); + if (ACPI_FAILURE(status)) + pr_err("error 0x%x occurred retrieving ordered list instances\n", status); + + status = append_settings_to_buffer(HPWMI_PASSWORD_GUID, + HPWMI_PASSWORD_TYPE, &hp_bios_settings_buffer, + &settings_buffer_size, &buf_alloc_size, &buf_mutex); + if (ACPI_FAILURE(status)) + pr_err("error 0x%x occurred retrieving password list instances\n", status); + + mutex_lock(&buf_mutex); + /* + * remove trailing comma + */ + if (settings_buffer_size >= 3) { + if (hp_bios_settings_buffer[settings_buffer_size - 2] == ',') + hp_bios_settings_buffer[settings_buffer_size - 2] = ' '; + } + settings_buffer_size = snprintf(hp_bios_settings_buffer, + buf_alloc_size, "%s]\n", + hp_bios_settings_buffer); + mutex_unlock(&buf_mutex); + + return settings_buffer_size; +} + +/* + * sure_admin_settings_read - Return a formatted file with settings + * and possible options read from BIOS + * + * @filp: Pointer to file of settings read from BIOS + * @kobj: Pointer to a kernel object of things that show up as directory in the sysfs filesystem. + * @attr: Pointer to list of read attributes + * @buf: Pointer to buffer + * @off: File current offset + * @count: Buffer size + * + * Returns the count of unicode chars read if successful, otherwise + * -ENOMEM unable to allocate memory + * -EINVAL buffer not allocated or too small + * + */ +static ssize_t sure_admin_settings_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t off, size_t count) +{ + ssize_t ret; + + /* clear the buffer when offset is pointing to the last position */ + if (off >= settings_buffer_size && settings_buffer_size > 0) { + hp_bios_settings_free_buffer(); + return 0; + } + + /* clear the buffer whenever the read starts from the first position */ + if (off == 0 && settings_buffer_size > 0) + hp_bios_settings_free_buffer(); + + if (settings_buffer_size == 0) + hp_bios_settings_fill_buffer(); + + mutex_lock(&buf_mutex); + ret = memory_read_from_buffer(buf, count, &off, hp_bios_settings_buffer, + settings_buffer_size); + mutex_unlock(&buf_mutex); + + return ret; +} + + +/* + * ascii_to_utf16_unicode - Convert ascii string to UTF-16 unicode + * + * @p: Unicode buffer address + * @str: string to convert to unicode + * + * Returns a void pointer to the buffer containing unicode string + */ +static void *ascii_to_utf16_unicode(u16 *p, const u8 *str) +{ + int len = strlen(str); + + /* + * Add null character when reading an empty string + */ + if (len == 0) { + *p++ = 2; + *p++ = (u8)0x00; + return p; + } + *p++ = len * 2; + utf8s_to_utf16s(str, strlen(str), UTF16_HOST_ENDIAN, p, len); + p += len; + + return p; +} + +/* + * hp_wmi_set_bios_setting - Set setting's value in BIOS + * + * @input_buffer: Input buffer address + * @input_size: Input buffer size + * + * Returns: Count of unicode characters written to BIOS if successful, otherwise + * -ENOMEM unable to allocate memory + * -EINVAL buffer not allocated or too small + */ +static int hp_wmi_set_bios_setting(u16 *input_buffer, u32 input_size) +{ + union acpi_object *obj; + struct acpi_buffer input = {input_size, input_buffer}; + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; + int ret = 0; + + ret = wmi_evaluate_method(HPWMI_SETBIOSSETTING_GUID, 0, 1, &input, &output); + + obj = output.pointer; + if (!obj) + return -EINVAL; + + if (obj->type != ACPI_TYPE_INTEGER) + ret = -EINVAL; + + ret = obj->integer.value; + kfree(obj); + return ret; +} + +/* Sure Admin Functions */ + +#define UTF_PREFIX ((unsigned char *)"") +#define BEAM_PREFIX ((unsigned char *)"") + +/* + * sure_admin_settings_write - Write the contents of a formatted file + * with settings and performs the logic + * to change any settings in BIOS. + * + * @filp: Pointer to file of settings to be written to BIOS + * @kobj: Pointer to a kernel object of things that show up as directory in the sysfs filesystem. + * @attr: Pointer to list of attributes for the write operation + * @buf: Pointer to buffer + * @off: File current offset + * @count: Buffer size + * + * + * Returns the count of unicode characters written to BIOS if successful, otherwise + * -ENOMEM unable to allocate memory + * -EINVAL buffer not allocated or too small + * + */ +static ssize_t sure_admin_settings_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, loff_t off, size_t count) +{ + int status = 0; + char *part = NULL; + int part_len = 0; + unsigned short *buffer = NULL; + unsigned short *tmpstr = NULL; + int buffer_size = (count + strlen(UTF_PREFIX)) * sizeof(unsigned short); + + buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + tmpstr = buffer; + part = strsep(&buf, ","); + if (!part) { + status = -EINVAL; + goto out_free; + } + tmpstr = ascii_to_utf16_unicode(tmpstr, part); + part = strsep(&buf, ","); + if (!part) { + status = -EINVAL; + goto out_free; + } + + /* Add extra buffer space when encountering an empty string */ + if (!strlen(part)) + buffer_size += sizeof(unsigned short); + tmpstr = ascii_to_utf16_unicode(tmpstr, part); + part = strsep(&buf, ","); + if (!part) { + status = -EINVAL; + goto out_free; + } + part_len = strlen(part) - 1; + part[part_len] = '\0'; + + if (strncmp(part, BEAM_PREFIX, strlen(BEAM_PREFIX)) == 0) { + /* + * BEAM_PREFIX is append to buffer when a signature + * is provided and Sure Admin is enabled in BIOS + */ + // BEAM_PREFIX found, convert part to unicode + tmpstr = ascii_to_utf16_unicode(tmpstr, part); + // decrease buffer size allocated initially for UTF_PREFIX + buffer_size -= strlen(UTF_PREFIX) * sizeof(unsigned short); + } else { + /* + * UTF-16 prefix is append to the * buffer when a BIOS + * admin password is configured in BIOS + */ + + // append UTF_PREFIX to part and then convert it to unicode + part = kasprintf(GFP_KERNEL, "%s%s", UTF_PREFIX, part); + if (!part) + goto out_free; + + tmpstr = ascii_to_utf16_unicode(tmpstr, part); + kfree(part); + } + + part = strsep(&buf, ","); + if (part) { + status = -EINVAL; + goto out_free; + } + status = hp_wmi_set_bios_setting(buffer, buffer_size); + if (ACPI_FAILURE(status)) + status = -EINVAL; + +out_free: + kfree(buffer); + if (ACPI_SUCCESS(status)) + return count; + return status; +} + +HPWMI_BINATTR_RW(sure_admin, settings, 0); + +static struct bin_attribute *sure_admin_binattrs[] = { + &sure_admin_settings, + NULL, +}; + +static const struct attribute_group sure_admin_group = { + .name = "sure_admin", + .bin_attrs = sure_admin_binattrs, +}; + static DEVICE_ATTR_RO(display); static DEVICE_ATTR_RO(hddtemp); static DEVICE_ATTR_RW(als); @@ -1050,6 +2026,7 @@ static const struct attribute_group *hp_wmi_groups[] = { &hp_wmi_group, &spm_group, &sure_start_group, + &sure_admin_group, NULL, }; From patchwork Mon Apr 4 20:36:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jorge Lopez X-Patchwork-Id: 12800852 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8FA40C43217 for ; Mon, 4 Apr 2022 21:37:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1382551AbiDDVbM (ORCPT ); Mon, 4 Apr 2022 17:31:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49158 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1380590AbiDDUi3 (ORCPT ); Mon, 4 Apr 2022 16:38:29 -0400 Received: from mail-oi1-x229.google.com (mail-oi1-x229.google.com [IPv6:2607:f8b0:4864:20::229]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9E65125EB8 for ; Mon, 4 Apr 2022 13:36:32 -0700 (PDT) Received: by mail-oi1-x229.google.com with SMTP id e4so11291189oif.2 for ; Mon, 04 Apr 2022 13:36:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=3DP2VETGu/Iuoa+ea/3r5cjfRcfG1p42JYqwFR3hnwo=; b=ZtxlaAjX5GgEgJhkrCOCdMTYMrcHLZVzGBb8TKg7g/Jz+5dAlDwpD3J9jAvfsRnn5U S+/deJ36qTrvRZSSqqcyhJec2SdmdTmZDLLJjvX+8AFXVbNPqCXAeoUjYYeVJ9wOoZf3 GBoDCogJrDrtNRbwhc7dSix+CtoGIwm5n2uRGrUtI7z6QU2dfeoAauLB3gzPF9+ZO4jT yPMujGnK8PGG2xduTQTtito77lM+aBmy6pQPnhZIZ20XApKI1G0qJKGDCxbfnK4abxd5 j854TYAmSbeMIB1llowmrlZIYXjSqP1Xr4cvweoGpy0sYsiaEOkgnlJLLccmuIcCSzlk K3+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3DP2VETGu/Iuoa+ea/3r5cjfRcfG1p42JYqwFR3hnwo=; b=LQw39RB98Y5f3zSIJwqtlAuoxnOO/DugdYysRjHzLK2DHZA5pnh8zeIs/KoK/Dt2IX L9pnrXs0Uf1LnDSdtcVeMUU05H2rWg5jP4QL6vhqpwhwtPx+NDqFsSnLT5CilZDQ+eKr M0dXA2JRbm5M2B8HHA0T08OwiI/ItMnQSZMiOnD8yCxJgGD3wctYsfin1/VVilD5xpGU 6wZTQejlfzoxbfVd9DjMgPe0IBx6CKCy7ksfwkqSniokFhYArRpE1smh4IilGFddNjgD hckQHL/4LlGXSBp31xP0CDbJu8KSgkwErJWO91UJ9aUaoYvxh0znMXrJ+zcIvzoYqB3N uuXQ== X-Gm-Message-State: AOAM533+VaxHmW3z6EgwYooUPcxgjNPqb+Oz/MxIbpCiodNlpVS//Y+g eMWV7h8krcFd9UTepdsagKUTJwlw4tk= X-Google-Smtp-Source: ABdhPJxD80x8iuaStTrLTDj/9r/YjGdexDobr+r+IkXYXj47hX4egQtA7JGOYSqAOA9jykOv9dI/1A== X-Received: by 2002:aca:aa55:0:b0:2ee:e8e8:cf80 with SMTP id t82-20020acaaa55000000b002eee8e8cf80mr35929oie.64.1649104591361; Mon, 04 Apr 2022 13:36:31 -0700 (PDT) Received: from grumpy-vm.hsd1.tx.comcast.net ([2601:2c3:480:7390:c57b:f63e:33f5:caed]) by smtp.gmail.com with ESMTPSA id u20-20020a4a9e94000000b003291f6ac4b2sm3765786ook.28.2022.04.04.13.36.30 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Apr 2022 13:36:31 -0700 (PDT) From: Jorge Lopez X-Google-Original-From: Jorge Lopez To: platform-driver-x86@vger.kernel.org Subject: [PATCH v1 6/6] HP Security Features Documentation Date: Mon, 4 Apr 2022 15:36:26 -0500 Message-Id: <20220404203626.4311-7-jorge.lopez2@hp.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220404203626.4311-1-jorge.lopez2@hp.com> References: <20220404203626.4311-1-jorge.lopez2@hp.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org Provide documentation for three new security features introduced in the hp-wmi driver. The security features include Secure Platform Management, Sure Admin, and Sure Start. Each documentation section provides security feature description, identifies sysfs directories, and files exposed by the driver. Signed-off-by: Jorge Lopez --- Based on the latest platform-drivers-x86.git/for-next This patch replaces and provides missing ABI/testing file in v1-0001-HP-Security-Features-solutions-Documentation patch. Signed-off-by: Jorge Lopez --- Based on the latest platform-drivers-x86.git/for-next --- .../ABI/testing/sysfs-platform-hp-wmi | 96 ++++++++++++ Documentation/admin-guide/hp_wmi.rst | 141 ++++++++++++++++++ Documentation/admin-guide/index.rst | 1 + 3 files changed, 238 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-platform-hp-wmi create mode 100644 Documentation/admin-guide/hp_wmi.rst diff --git a/Documentation/ABI/testing/sysfs-platform-hp-wmi b/Documentation/ABI/testing/sysfs-platform-hp-wmi new file mode 100644 index 000000000000..836b1cdbc260 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-hp-wmi @@ -0,0 +1,96 @@ + +What: /sys/devices/platform/hp-wmi/spm/kek +Date: March 29 +KernelVersion: 5.18 +Contact: "Jorge Lopez" +Description: 'kek' is a write-only file that can be used to configure the + RSA public key that will be used by the BIOS to verify + signatures when setting the signing key. When written, + the bytes should correspond to the KEK certificate + (x509 .DER format containing an OU). The size of the + certificate must be less than or equal to 4095 bytes. + + +What: /sys/devices/platform/hp-wmi/sk +Date: March 29 +KernelVersion: 5.18 +Contact: "Jorge Lopez" +Description: 'sk' is a write-only file that can be used to configure the RSA + public key that will be used by the BIOS to verify signatures + when configuring BIOS settings and security features. When + written, the bytes should correspond to the modulus of the + public key. The exponent is assumed to be 0x10001. + + +What: /sys/devices/platform/hp-wmi/status +Date: March 29 +KernelVersion: 5.18 +Contact: "Jorge Lopez" +Description: 'status' is a read-only file that returns ASCII text reporting + the status information. + + State: Not Provisioned / Provisioned / Provisioning in progress + Version: Major. Minor + Feature Bit Mask: <16-bit unsigned number display in hex> + SPM Counter: <16-bit unsigned number display in base 10> + Signing Key Public Key Modulus (base64): + KEK Public Key Modulus (base64): + + +What: /sys/devices/platform/hp-wmi/statusbin +Date: March 29 +KernelVersion: 5.18 +Contact: "Jorge Lopez" +Description: 'statusbin' is a read-only file that returns identical status + information reported by 'status' file in binary format. + + +What: /sys/devices/platform/hp-wmi/sure_admin/settings +Date: March 29 +KernelVersion: 5.18 +Contact: "Jorge Lopez" +Description: 'settings' is a file associated with Sure Admin. BIOS settings can + be read or written through the Sure Admin settings file in sysfs. + + Expected data format to update BIOS setting + + [BIOS setting],[new value],[auth token] + + Sample settings reported data + + { + "Class": "HPBIOS_BIOSEnumeration", + "Name": "USB Storage Boot", + "Path": "\\Advanced\\Boot Options", + "IsReadOnly": 0, + ... + "Value": "Enable", + "Size": 2, + "PossibleValues": [ + "Disable", + "Enable" + ] + } + + +What: /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count +Date: March 29 +KernelVersion: 5.18 +Contact: "Jorge Lopez" +Description: audit_log_entry_count is a read-only file that returns the + number of existing audit log events available to be read. + + [No of entries],[log entry size],[Max number of entries supported] + + +What: /sys/devices/platform/hp-wmi/sure_start/audit_log_entries +Date: March 29 +KernelVersion: 5.18 +Contact: "Jorge Lopez" +Description: audit_log_entries is a read-only file that returns the events + in the log. + + Audit log entry format + + Byte 0-15: Requested Audit Log entry (Each Audit log is 16 bytes) + Byte 16-127: Unused diff --git a/Documentation/admin-guide/hp_wmi.rst b/Documentation/admin-guide/hp_wmi.rst new file mode 100644 index 000000000000..4dcb416bbf08 --- /dev/null +++ b/Documentation/admin-guide/hp_wmi.rst @@ -0,0 +1,141 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=========================== +HP Inc. WMI driver (hp_wmi) +=========================== + +Purpose +======= +To document the use of the HP WMI driver to manage BIOS settings & security +solutions on HP Inc.’s commercial platforms + +Scope +===== +This document discusses the functionality of the hp_wmi driver only. +It does not cover the support needed from applications to configure the BIOS +settings and enable the security features. + +Overview +======== +Many features of HP Commercial PC’s can be managed using Windows Management +Instrumentation (WMI). WMI is an implementation of Web-Based Enterprise +Management (WBEM) that provides a standards-based interface for changing and +monitoring system settings. + +The hp-wmi driver enables managing the BIOS settings and security solutions +via sysfs, a virtual filesystem that can be used by usermode applications. + +When the driver loads, it creates the following directories and files in the +/sys file system:: + + /sys/devices/platform/hp-wmi/spm/kek + /sys/devices/platform/hp-wmi/spm/sk + /sys/devices/platform/hp-wmi/spm/status + /sys/devices/platform/hp-wmi/spm/statusbin + /sys/devices/platform/hp-wmi/sure_admin/settings + /sys/devices/platform/hp-wmi/sure_start/audit_log_entries + /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count + +If the driver is unloaded, all the allocated memory is freed and directories +and files in the /sys file system removed. + +Secure Platform Management +========================== +Many HP Commercial PC’s include a feature called Secure Platform Management +(SPM), which replaces older password-based BIOS settings management with public +key cryptography. PC secure product management begins when a target system is +provisioned with cryptographic keys that are used to ensure the integrity of +communications between system management utilities and the BIOS. + +The private key is used by system management utilities to sign payloads +containing configuration changes. The BIOS on a target system uses the +associated public key to verify the integrity of the payload and apply the +changes. + +At the end of the PC’s lifecycle a signed deprovisioning command restores +the factory default state. + +KEK Certificate (KEK) and Signing Key (SK) get provisioned and status can +be read either as text from the status file or binary from statusbin. :: + + /sys/devices/platform/hp-wmi/spm/kek + /sys/devices/platform/hp-wmi/spm/sk + /sys/devices/platform/hp-wmi/spm/status + /sys/devices/platform/hp-wmi/spm/statusbin + +**status** is a read-only file that returns ASCII text reporting the +following information:: + + State: Not Provisioned / Provisioned / Provisioning in progress + Version: Major. Minor + Feature Bit Mask: <16-bit unsigned number display in hex> + SPM Counter: <16-bit unsigned number display in base 10> + Signing Key Public Key Modulus (base64): + KEK Public Key Modulus (base64): + +**kek** is a write-only file that can be used to configure the RSA public +key that will be used by the BIOS to verify signatures when setting the +signing key. When written, the bytes should correspond to the KEK +certificate (x509 .DER format containing an OU). The size of the +certificate must be less than or equal to 4095 bytes. + +**sk** is a write-only file that can be used to configure the RSA public +key that will be used by the BIOS to verify signatures when configuring +BIOS settings and security features. When written, the bytes should +correspond to the modulus of the public key. The exponent is assumed +to be 0x10001. + +Sure Admin +========== +HP Commercial PC’s have several BIOS settings that control its behaviour and +capabilities, many of which are related to security. To prevent unauthorized +changes to these settings, the system can be configured to use a Sure Admin +cryptographic signature-based authorization string that the BIOS will use to +verify authorization to modify the setting. +Behind the scenes, Sure Admin uses Secure Platform Management (SPM) and WMI + +**settings** is a file associated with Sure Admin. BIOS settings can be read +or written through the Sure Admin settings file in sysfs:: + + /sys/devices/platform/hp-wmi/sure_admin/settings + +Expected data format to update BIOS setting:: + + [BIOS setting],[new value],[auth token] + +Sample settings reported data:: + + { + "Class": "HPBIOS_BIOSEnumeration", + "Name": "USB Storage Boot", + "Path": "\\Advanced\\Boot Options", + "IsReadOnly": 0, + ... + "Value": "Enable", + "Size": 2, + "PossibleValues": [ + "Disable", + "Enable" + ] + } + +Sure Start +========== +Sure Start provides advanced firmware protection and resiliency by identifying +and repairing unauthorized BIOS changes. It maintains an audit log of these +events and other important system configuration changes. The following sysfs +entries can be used to read the contents of the audit log. + +**audit_log_entry_count** is a read-only file that returns the number of +existing audit log events available to be read:: + + /sys/devices/platform/hp-wmi/sure_start/audit_log_entry_count + +Reported data format:: + + [No of entries],[log entry size in bytes],[Max number of entries supported] + + +**audit_log_entries** is a read-only file that returns the events in the log:: + + /sys/devices/platform/hp-wmi/sure_start/audit_log_entries diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst index 1bedab498104..58b9b0541cb5 100644 --- a/Documentation/admin-guide/index.rst +++ b/Documentation/admin-guide/index.rst @@ -86,6 +86,7 @@ configure specific aspects of kernel behavior to your liking. nfs/index gpio/index highuid + hp_wmi hw_random initrd iostats