mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 1/4] platform/x86: think-lmi: improve check if BIOS account security enabled
@ 2024-10-21 19:38 Mark Pearson
  2024-10-21 19:38 ` [PATCH 2/4] platform/x86: think-lmi: Add certificate as mechanism Mark Pearson
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Mark Pearson @ 2024-10-21 19:38 UTC (permalink / raw)
  To: mpearson-lenovo
  Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel

Improve determination of whether authentication account is enabled by
checking if either password or certificate is enabled.

Renamed valid to pwd_enabled for better readability.

Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
---
 drivers/platform/x86/think-lmi.c | 26 +++++++++++++-------------
 drivers/platform/x86/think-lmi.h |  2 +-
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
index 4cfb53206cb8..727a9400d406 100644
--- a/drivers/platform/x86/think-lmi.c
+++ b/drivers/platform/x86/think-lmi.c
@@ -391,7 +391,7 @@ static ssize_t is_enabled_show(struct kobject *kobj, struct kobj_attribute *attr
 {
 	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
 
-	return sysfs_emit(buf, "%d\n", setting->valid);
+	return sysfs_emit(buf, "%d\n", setting->pwd_enabled || setting->cert_installed);
 }
 
 static struct kobj_attribute auth_is_pass_set = __ATTR_RO(is_enabled);
@@ -469,7 +469,7 @@ static ssize_t new_password_store(struct kobject *kobj,
 		if (ret)
 			goto out;
 
-		if (tlmi_priv.pwd_admin->valid) {
+		if (tlmi_priv.pwd_admin->pwd_enabled) {
 			ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
 					tlmi_priv.pwd_admin->password);
 			if (ret)
@@ -777,7 +777,7 @@ static ssize_t certificate_store(struct kobject *kobj,
 				new_cert, setting->signature);
 	} else {
 		/* This is a fresh install */
-		if (!setting->valid || !setting->password[0]) {
+		if (!setting->pwd_enabled || !setting->password[0]) {
 			kfree(new_cert);
 			return -EACCES;
 		}
@@ -1019,7 +1019,7 @@ static ssize_t current_value_store(struct kobject *kobj,
 		 * Workstation's require the opcode to be set before changing the
 		 * attribute.
 		 */
-		if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+		if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) {
 			ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
 						  tlmi_priv.pwd_admin->password);
 			if (ret)
@@ -1042,7 +1042,7 @@ static ssize_t current_value_store(struct kobject *kobj,
 		else
 			ret = tlmi_save_bios_settings("");
 	} else { /* old non-opcode based authentication method (deprecated) */
-		if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+		if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) {
 			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
 					tlmi_priv.pwd_admin->password,
 					encoding_options[tlmi_priv.pwd_admin->encoding],
@@ -1215,7 +1215,7 @@ static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute *
 			if (ret)
 				goto out;
 		} else if (tlmi_priv.opcode_support) {
-			if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+			if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) {
 				ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
 							  tlmi_priv.pwd_admin->password);
 				if (ret)
@@ -1223,7 +1223,7 @@ static ssize_t save_settings_store(struct kobject *kobj, struct kobj_attribute *
 			}
 			ret = tlmi_save_bios_settings("");
 		} else { /* old non-opcode based authentication method (deprecated) */
-			if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+			if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) {
 				auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
 						     tlmi_priv.pwd_admin->password,
 						     encoding_options[tlmi_priv.pwd_admin->encoding],
@@ -1273,7 +1273,7 @@ static ssize_t debug_cmd_store(struct kobject *kobj, struct kobj_attribute *attr
 	if (!new_setting)
 		return -ENOMEM;
 
-	if (tlmi_priv.pwd_admin->valid && tlmi_priv.pwd_admin->password[0]) {
+	if (tlmi_priv.pwd_admin->pwd_enabled && tlmi_priv.pwd_admin->password[0]) {
 		auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s;",
 				tlmi_priv.pwd_admin->password,
 				encoding_options[tlmi_priv.pwd_admin->encoding],
@@ -1637,14 +1637,14 @@ static int tlmi_analyze(void)
 		goto fail_clear_attr;
 
 	if (tlmi_priv.pwdcfg.core.password_state & TLMI_PAP_PWD)
-		tlmi_priv.pwd_admin->valid = true;
+		tlmi_priv.pwd_admin->pwd_enabled = true;
 
 	tlmi_priv.pwd_power = tlmi_create_auth("pop", "power-on");
 	if (!tlmi_priv.pwd_power)
 		goto fail_clear_attr;
 
 	if (tlmi_priv.pwdcfg.core.password_state & TLMI_POP_PWD)
-		tlmi_priv.pwd_power->valid = true;
+		tlmi_priv.pwd_power->pwd_enabled = true;
 
 	if (tlmi_priv.opcode_support) {
 		tlmi_priv.pwd_system = tlmi_create_auth("smp", "system");
@@ -1652,7 +1652,7 @@ static int tlmi_analyze(void)
 			goto fail_clear_attr;
 
 		if (tlmi_priv.pwdcfg.core.password_state & TLMI_SMP_PWD)
-			tlmi_priv.pwd_system->valid = true;
+			tlmi_priv.pwd_system->pwd_enabled = true;
 
 		tlmi_priv.pwd_hdd = tlmi_create_auth("hdd", "hdd");
 		if (!tlmi_priv.pwd_hdd)
@@ -1670,7 +1670,7 @@ static int tlmi_analyze(void)
 			/* Check if PWD is configured and set index to first drive found */
 			if (tlmi_priv.pwdcfg.ext.hdd_user_password ||
 					tlmi_priv.pwdcfg.ext.hdd_master_password) {
-				tlmi_priv.pwd_hdd->valid = true;
+				tlmi_priv.pwd_hdd->pwd_enabled = true;
 				if (tlmi_priv.pwdcfg.ext.hdd_master_password)
 					tlmi_priv.pwd_hdd->index =
 						ffs(tlmi_priv.pwdcfg.ext.hdd_master_password) - 1;
@@ -1680,7 +1680,7 @@ static int tlmi_analyze(void)
 			}
 			if (tlmi_priv.pwdcfg.ext.nvme_user_password ||
 					tlmi_priv.pwdcfg.ext.nvme_master_password) {
-				tlmi_priv.pwd_nvme->valid = true;
+				tlmi_priv.pwd_nvme->pwd_enabled = true;
 				if (tlmi_priv.pwdcfg.ext.nvme_master_password)
 					tlmi_priv.pwd_nvme->index =
 						ffs(tlmi_priv.pwdcfg.ext.nvme_master_password) - 1;
diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h
index e1975ffebeb4..4728f40143a3 100644
--- a/drivers/platform/x86/think-lmi.h
+++ b/drivers/platform/x86/think-lmi.h
@@ -65,7 +65,7 @@ struct tlmi_pwdcfg {
 /* password setting details */
 struct tlmi_pwd_setting {
 	struct kobject kobj;
-	bool valid;
+	bool pwd_enabled;
 	char password[TLMI_PWD_BUFSIZE];
 	const char *pwd_type;
 	const char *role;
-- 
2.47.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/4] platform/x86: think-lmi: Add certificate as mechanism
  2024-10-21 19:38 [PATCH 1/4] platform/x86: think-lmi: improve check if BIOS account security enabled Mark Pearson
@ 2024-10-21 19:38 ` Mark Pearson
  2024-10-21 19:38 ` [PATCH 3/4] platform/x86: think-lmi: Allow empty admin password Mark Pearson
  2024-10-21 19:38 ` [PATCH 4/4] platform/x86: think-lmi: Multi-certificate support Mark Pearson
  2 siblings, 0 replies; 8+ messages in thread
From: Mark Pearson @ 2024-10-21 19:38 UTC (permalink / raw)
  To: mpearson-lenovo
  Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel

As both password or certificate authentication are available as mechanisms
update the documentation to add certificate as an option

Update driver to return correct mechanism appropriately.

Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
---
 Documentation/ABI/testing/sysfs-class-firmware-attributes | 2 +-
 drivers/platform/x86/think-lmi.c                          | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
index 9c82c7b42ff8..1a8b59f5d6e3 100644
--- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
+++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
@@ -193,7 +193,7 @@ Description:
 
 		mechanism:
 					The means of authentication.  This attribute is mandatory.
-					Only supported type currently is "password".
+					Supported types are "password" or "certificate".
 
 		max_password_length:
 					A file that can be read to obtain the
diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
index 727a9400d406..46ab82fb2898 100644
--- a/drivers/platform/x86/think-lmi.c
+++ b/drivers/platform/x86/think-lmi.c
@@ -524,6 +524,10 @@ static struct kobj_attribute auth_max_pass_length = __ATTR_RO(max_password_lengt
 static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,
 			 char *buf)
 {
+	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+
+	if (setting->cert_installed)
+		return sysfs_emit(buf, "certificate\n");
 	return sysfs_emit(buf, "password\n");
 }
 static struct kobj_attribute auth_mechanism = __ATTR_RO(mechanism);
-- 
2.47.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/4] platform/x86: think-lmi: Allow empty admin password
  2024-10-21 19:38 [PATCH 1/4] platform/x86: think-lmi: improve check if BIOS account security enabled Mark Pearson
  2024-10-21 19:38 ` [PATCH 2/4] platform/x86: think-lmi: Add certificate as mechanism Mark Pearson
@ 2024-10-21 19:38 ` Mark Pearson
  2024-10-22  7:59   ` Ilpo Järvinen
  2024-10-21 19:38 ` [PATCH 4/4] platform/x86: think-lmi: Multi-certificate support Mark Pearson
  2 siblings, 1 reply; 8+ messages in thread
From: Mark Pearson @ 2024-10-21 19:38 UTC (permalink / raw)
  To: mpearson-lenovo
  Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel

SVP = BIOS Supervisor/Admin password
SMP = BIOS System password

If SMP ACL is enabled in the BIOS then the system allows you to set the
SMP without a SVP password configured. Change code to allow this.
BIOS will return permissions error if SVP is required.

Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
---
 drivers/platform/x86/think-lmi.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
index 46ab82fb2898..751e351dfc42 100644
--- a/drivers/platform/x86/think-lmi.c
+++ b/drivers/platform/x86/think-lmi.c
@@ -469,7 +469,12 @@ static ssize_t new_password_store(struct kobject *kobj,
 		if (ret)
 			goto out;
 
-		if (tlmi_priv.pwd_admin->pwd_enabled) {
+		/*
+		 * Note admin password not always required if SMPControl enabled in BIOS,
+		 * So only set if it's configured.
+		 * Let BIOS figure it out - we'll get an error if operation not permitted
+		 */
+		if (tlmi_priv.pwd_admin->pwd_enabled && strlen(tlmi_priv.pwd_admin->password)) {
 			ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
 					tlmi_priv.pwd_admin->password);
 			if (ret)
-- 
2.47.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 4/4] platform/x86: think-lmi: Multi-certificate support
  2024-10-21 19:38 [PATCH 1/4] platform/x86: think-lmi: improve check if BIOS account security enabled Mark Pearson
  2024-10-21 19:38 ` [PATCH 2/4] platform/x86: think-lmi: Add certificate as mechanism Mark Pearson
  2024-10-21 19:38 ` [PATCH 3/4] platform/x86: think-lmi: Allow empty admin password Mark Pearson
@ 2024-10-21 19:38 ` Mark Pearson
  2024-10-22  8:14   ` Ilpo Järvinen
  2 siblings, 1 reply; 8+ messages in thread
From: Mark Pearson @ 2024-10-21 19:38 UTC (permalink / raw)
  To: mpearson-lenovo
  Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel

Lenovo are adding support for both Admin and System certificates to
the certificate based authentication feature

This commit adds the support for this.

Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
---
 .../testing/sysfs-class-firmware-attributes   |   1 +
 drivers/platform/x86/think-lmi.c              | 141 ++++++++++++++----
 drivers/platform/x86/think-lmi.h              |   4 +
 3 files changed, 116 insertions(+), 30 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
index 1a8b59f5d6e3..2713efa509b4 100644
--- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
+++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
@@ -303,6 +303,7 @@ Description:
 					being configured allowing anyone to make changes.
 					After any of these operations the system must reboot for the changes to
 					take effect.
+					Admin and System certificates are supported from 2025 systems onward.
 
 		certificate_thumbprint:
 					Read only attribute used to display the MD5, SHA1 and SHA256 thumbprints
diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
index 751e351dfc42..fca190232c24 100644
--- a/drivers/platform/x86/think-lmi.c
+++ b/drivers/platform/x86/think-lmi.c
@@ -169,11 +169,12 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support");
  */
 #define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4"
 
-#define TLMI_POP_PWD BIT(0) /* Supervisor */
-#define TLMI_PAP_PWD BIT(1) /* Power-on */
-#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */
-#define TLMI_SMP_PWD BIT(6) /* System Management */
-#define TLMI_CERT    BIT(7) /* Certificate Based */
+#define TLMI_POP_PWD  BIT(0) /* Supervisor */
+#define TLMI_PAP_PWD  BIT(1) /* Power-on */
+#define TLMI_HDD_PWD  BIT(2) /* HDD/NVME */
+#define TLMI_SMP_PWD  BIT(6) /* System Management */
+#define TLMI_CERT_SVC BIT(7) /* Admin Certificate Based */
+#define TLMI_CERT_SMC BIT(8) /* System Certificate Based */
 
 static const struct tlmi_err_codes tlmi_errs[] = {
 	{"Success", 0},
@@ -678,18 +679,35 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count)
 	return count;
 }
 
+#define NUM_THUMBTYPES 3
+static char *thumbtypes[NUM_THUMBTYPES] = {"Md5", "Sha1", "Sha256"};
+
 static ssize_t certificate_thumbprint_show(struct kobject *kobj, struct kobj_attribute *attr,
 			 char *buf)
 {
 	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
-	int count = 0;
+	char *wmistr;
+	int count = 0, i;
 
 	if (!tlmi_priv.certificate_support || !setting->cert_installed)
 		return -EOPNOTSUPP;
 
-	count += cert_thumbprint(buf, "Md5", count);
-	count += cert_thumbprint(buf, "Sha1", count);
-	count += cert_thumbprint(buf, "Sha256", count);
+	for (i = 0; i < NUM_THUMBTYPES; i++) {
+		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
+			/* Format: 'SVC | SMC, Thumbtype' */
+			wmistr = kasprintf(GFP_KERNEL, "%s,%s",
+					   setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
+					   thumbtypes[i]);
+		} else {
+			/* Format: 'Thumbtype' */
+			wmistr = kasprintf(GFP_KERNEL, "%s", thumbtypes[i]);
+		}
+		if (!wmistr)
+			return -ENOMEM;
+		count += cert_thumbprint(buf, wmistr, count);
+		kfree(wmistr);
+	}
+
 	return count;
 }
 
@@ -720,8 +738,15 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
 	if (!passwd)
 		return -ENOMEM;
 
-	/* Format: 'Password,Signature' */
-	auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
+	if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
+		/* Format: 'SVC | SMC, password, signature' */
+		auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
+				     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
+				     passwd, setting->signature);
+	} else {
+		/* Format: 'Password,Signature' */
+		auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
+	}
 	if (!auth_str) {
 		kfree_sensitive(passwd);
 		return -ENOMEM;
@@ -735,12 +760,19 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
 
 static struct kobj_attribute auth_cert_to_password = __ATTR_WO(cert_to_password);
 
+enum cert_install_mode {
+	TLMI_CERT_INSTALL,
+	TLMI_CERT_UPDATE,
+};
+
 static ssize_t certificate_store(struct kobject *kobj,
 				  struct kobj_attribute *attr,
 				  const char *buf, size_t count)
 {
 	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
+	enum cert_install_mode install_mode = TLMI_CERT_INSTALL;
 	char *auth_str, *new_cert;
+	char *signature;
 	char *guid;
 	int ret;
 
@@ -756,10 +788,18 @@ static ssize_t certificate_store(struct kobject *kobj,
 		if (!setting->signature || !setting->signature[0])
 			return -EACCES;
 
-		/* Format: 'serial#, signature' */
-		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
-				dmi_get_system_info(DMI_PRODUCT_SERIAL),
-				setting->signature);
+		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
+			/* Format: 'SVC | SMC, serial#, signature' */
+			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
+					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
+					     dmi_get_system_info(DMI_PRODUCT_SERIAL),
+					     setting->signature);
+		} else {
+			/* Format: 'serial#, signature' */
+			auth_str = kasprintf(GFP_KERNEL, "%s,%s",
+					     dmi_get_system_info(DMI_PRODUCT_SERIAL),
+					     setting->signature);
+		}
 		if (!auth_str)
 			return -ENOMEM;
 
@@ -776,24 +816,59 @@ static ssize_t certificate_store(struct kobject *kobj,
 
 	if (setting->cert_installed) {
 		/* Certificate is installed so this is an update */
-		if (!setting->signature || !setting->signature[0]) {
+		install_mode = TLMI_CERT_UPDATE;
+		/* If admin account enabled - need to use it's signature */
+		if (tlmi_priv.pwd_admin->pwd_enabled)
+			signature = tlmi_priv.pwd_admin->signature;
+		else
+			signature = setting->signature;
+	} else { /* Cert install */
+		/* Check if SMC and SVC already installed */
+		if ((setting == tlmi_priv.pwd_system) && tlmi_priv.pwd_admin->cert_installed) {
+			/* This gets treated as a cert update */
+			install_mode = TLMI_CERT_UPDATE;
+			signature = tlmi_priv.pwd_admin->signature;
+		} else { /* Regular cert install */
+			install_mode = TLMI_CERT_INSTALL;
+			signature = setting->signature;
+		}
+	}
+
+	if (install_mode == TLMI_CERT_UPDATE) {
+		/* This is a certificate update */
+		if (!signature || !signature[0]) {
 			kfree(new_cert);
 			return -EACCES;
 		}
 		guid = LENOVO_UPDATE_BIOS_CERT_GUID;
-		/* Format: 'Certificate,Signature' */
-		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
-				new_cert, setting->signature);
+		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
+			/* Format: 'SVC | SMC, certificate, signature' */
+			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
+					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
+					     new_cert, signature);
+		} else {
+			/* Format: 'Certificate,Signature' */
+			auth_str = kasprintf(GFP_KERNEL, "%s,%s",
+					     new_cert, signature);
+		}
 	} else {
 		/* This is a fresh install */
-		if (!setting->pwd_enabled || !setting->password[0]) {
+		/* To set admin cert, a password must be enabled */
+		if ((setting == tlmi_priv.pwd_admin) &&
+		    (!setting->pwd_enabled || !setting->password[0])) {
 			kfree(new_cert);
 			return -EACCES;
 		}
 		guid = LENOVO_SET_BIOS_CERT_GUID;
-		/* Format: 'Certificate,Admin-password' */
-		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
-				new_cert, setting->password);
+		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
+			/* Format: 'SVC | SMC, Certificate, password' */
+			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
+					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
+					     new_cert, setting->password);
+		} else {
+			/* Format: 'Certificate, password' */
+			auth_str = kasprintf(GFP_KERNEL, "%s,%s", new_cert, setting->password);
+		}
 	}
 	kfree(new_cert);
 	if (!auth_str)
@@ -873,14 +948,19 @@ static umode_t auth_attr_is_visible(struct kobject *kobj,
 		return 0;
 	}
 
-	/* We only display certificates on Admin account, if supported */
+	/* We only display certificates, if supported */
 	if (attr == &auth_certificate.attr ||
 	    attr == &auth_signature.attr ||
 	    attr == &auth_save_signature.attr ||
 	    attr == &auth_cert_thumb.attr ||
 	    attr == &auth_cert_to_password.attr) {
-		if ((setting == tlmi_priv.pwd_admin) && tlmi_priv.certificate_support)
+		if (tlmi_priv.certificate_support) {
+			if (setting == tlmi_priv.pwd_admin)
+				return attr->mode;
+		if ((tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) &&
+		    (setting == tlmi_priv.pwd_system))
 			return attr->mode;
+		}
 		return 0;
 	}
 
@@ -1700,12 +1780,13 @@ static int tlmi_analyze(void)
 		}
 	}
 
-	if (tlmi_priv.certificate_support &&
-		(tlmi_priv.pwdcfg.core.password_state & TLMI_CERT))
-		tlmi_priv.pwd_admin->cert_installed = true;
-
+	if (tlmi_priv.certificate_support) {
+		tlmi_priv.pwd_admin->cert_installed =
+			tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC;
+		tlmi_priv.pwd_system->cert_installed =
+			tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SMC;
+	}
 	return 0;
-
 fail_clear_attr:
 	for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
 		if (tlmi_priv.setting[i]) {
diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h
index 4728f40143a3..f267d8b46957 100644
--- a/drivers/platform/x86/think-lmi.h
+++ b/drivers/platform/x86/think-lmi.h
@@ -41,6 +41,10 @@ enum save_mode {
 };
 
 /* password configuration details */
+#define TLMI_PWDCFG_MODE_LEGACY    0
+#define TLMI_PWDCFG_MODE_PASSWORD  1
+#define TLMI_PWDCFG_MODE_MULTICERT 3
+
 struct tlmi_pwdcfg_core {
 	uint32_t password_mode;
 	uint32_t password_state;
-- 
2.47.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/4] platform/x86: think-lmi: Allow empty admin password
  2024-10-21 19:38 ` [PATCH 3/4] platform/x86: think-lmi: Allow empty admin password Mark Pearson
@ 2024-10-22  7:59   ` Ilpo Järvinen
  2024-10-22 19:19     ` Mark Pearson
  0 siblings, 1 reply; 8+ messages in thread
From: Ilpo Järvinen @ 2024-10-22  7:59 UTC (permalink / raw)
  To: Mark Pearson; +Cc: Hans de Goede, platform-driver-x86, LKML

On Mon, 21 Oct 2024, Mark Pearson wrote:

> SVP = BIOS Supervisor/Admin password
> SMP = BIOS System password
> 
> If SMP ACL is enabled in the BIOS then the system allows you to set the
> SMP without a SVP password configured. Change code to allow this.
> BIOS will return permissions error if SVP is required.
> 
> Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> ---
>  drivers/platform/x86/think-lmi.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
> index 46ab82fb2898..751e351dfc42 100644
> --- a/drivers/platform/x86/think-lmi.c
> +++ b/drivers/platform/x86/think-lmi.c
> @@ -469,7 +469,12 @@ static ssize_t new_password_store(struct kobject *kobj,
>  		if (ret)
>  			goto out;
>  
> -		if (tlmi_priv.pwd_admin->pwd_enabled) {
> +		/*
> +		 * Note admin password not always required if SMPControl enabled in BIOS,

is not always required

> +		 * So only set if it's configured.
> +		 * Let BIOS figure it out - we'll get an error if operation not permitted

operation is not permitted.

Please reflow the comment to fit into 80 chars (this only relates to 
comments to keep their line lengths readable without large eye movement).

> +		 */
> +		if (tlmi_priv.pwd_admin->pwd_enabled && strlen(tlmi_priv.pwd_admin->password)) {
>  			ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
>  					tlmi_priv.pwd_admin->password);
>  			if (ret)
> 

-- 
 i.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/4] platform/x86: think-lmi: Multi-certificate support
  2024-10-21 19:38 ` [PATCH 4/4] platform/x86: think-lmi: Multi-certificate support Mark Pearson
@ 2024-10-22  8:14   ` Ilpo Järvinen
  2024-10-22 19:30     ` Mark Pearson
  0 siblings, 1 reply; 8+ messages in thread
From: Ilpo Järvinen @ 2024-10-22  8:14 UTC (permalink / raw)
  To: Mark Pearson; +Cc: Hans de Goede, platform-driver-x86, LKML

On Mon, 21 Oct 2024, Mark Pearson wrote:

> Lenovo are adding support for both Admin and System certificates to
> the certificate based authentication feature
> 
> This commit adds the support for this.
> 
> Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
> ---
>  .../testing/sysfs-class-firmware-attributes   |   1 +
>  drivers/platform/x86/think-lmi.c              | 141 ++++++++++++++----
>  drivers/platform/x86/think-lmi.h              |   4 +
>  3 files changed, 116 insertions(+), 30 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> index 1a8b59f5d6e3..2713efa509b4 100644
> --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
> +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
> @@ -303,6 +303,7 @@ Description:
>  					being configured allowing anyone to make changes.
>  					After any of these operations the system must reboot for the changes to
>  					take effect.
> +					Admin and System certificates are supported from 2025 systems onward.
>  
>  		certificate_thumbprint:
>  					Read only attribute used to display the MD5, SHA1 and SHA256 thumbprints
> diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
> index 751e351dfc42..fca190232c24 100644
> --- a/drivers/platform/x86/think-lmi.c
> +++ b/drivers/platform/x86/think-lmi.c
> @@ -169,11 +169,12 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support");
>   */
>  #define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4"
>  
> -#define TLMI_POP_PWD BIT(0) /* Supervisor */
> -#define TLMI_PAP_PWD BIT(1) /* Power-on */
> -#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */
> -#define TLMI_SMP_PWD BIT(6) /* System Management */
> -#define TLMI_CERT    BIT(7) /* Certificate Based */
> +#define TLMI_POP_PWD  BIT(0) /* Supervisor */
> +#define TLMI_PAP_PWD  BIT(1) /* Power-on */
> +#define TLMI_HDD_PWD  BIT(2) /* HDD/NVME */
> +#define TLMI_SMP_PWD  BIT(6) /* System Management */
> +#define TLMI_CERT_SVC BIT(7) /* Admin Certificate Based */
> +#define TLMI_CERT_SMC BIT(8) /* System Certificate Based */
>  
>  static const struct tlmi_err_codes tlmi_errs[] = {
>  	{"Success", 0},
> @@ -678,18 +679,35 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count)
>  	return count;
>  }
>  
> +#define NUM_THUMBTYPES 3
> +static char *thumbtypes[NUM_THUMBTYPES] = {"Md5", "Sha1", "Sha256"};
> +
>  static ssize_t certificate_thumbprint_show(struct kobject *kobj, struct kobj_attribute *attr,
>  			 char *buf)
>  {
>  	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
> -	int count = 0;
> +	char *wmistr;
> +	int count = 0, i;

Reverse xmas-tree order.

>  
>  	if (!tlmi_priv.certificate_support || !setting->cert_installed)
>  		return -EOPNOTSUPP;
>  
> -	count += cert_thumbprint(buf, "Md5", count);
> -	count += cert_thumbprint(buf, "Sha1", count);
> -	count += cert_thumbprint(buf, "Sha256", count);
> +	for (i = 0; i < NUM_THUMBTYPES; i++) {

Use ARRAY_SIZE() + add include for it.

These days, the usual custom is to use unsigned int for loop variables 
that are never meant to be negative.

> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
> +			/* Format: 'SVC | SMC, Thumbtype' */
> +			wmistr = kasprintf(GFP_KERNEL, "%s,%s",
> +					   setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
> +					   thumbtypes[i]);
> +		} else {
> +			/* Format: 'Thumbtype' */
> +			wmistr = kasprintf(GFP_KERNEL, "%s", thumbtypes[i]);
> +		}
> +		if (!wmistr)
> +			return -ENOMEM;
> +		count += cert_thumbprint(buf, wmistr, count);
> +		kfree(wmistr);
> +	}
> +
>  	return count;
>  }
>  
> @@ -720,8 +738,15 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
>  	if (!passwd)
>  		return -ENOMEM;
>  
> -	/* Format: 'Password,Signature' */
> -	auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
> +	if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
> +		/* Format: 'SVC | SMC, password, signature' */
> +		auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
> +				     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
> +				     passwd, setting->signature);
> +	} else {
> +		/* Format: 'Password,Signature' */
> +		auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
> +	}
>  	if (!auth_str) {
>  		kfree_sensitive(passwd);
>  		return -ENOMEM;
> @@ -735,12 +760,19 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
>  
>  static struct kobj_attribute auth_cert_to_password = __ATTR_WO(cert_to_password);
>  
> +enum cert_install_mode {
> +	TLMI_CERT_INSTALL,
> +	TLMI_CERT_UPDATE,
> +};
> +
>  static ssize_t certificate_store(struct kobject *kobj,
>  				  struct kobj_attribute *attr,
>  				  const char *buf, size_t count)
>  {
>  	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
> +	enum cert_install_mode install_mode = TLMI_CERT_INSTALL;
>  	char *auth_str, *new_cert;
> +	char *signature;
>  	char *guid;
>  	int ret;
>  
> @@ -756,10 +788,18 @@ static ssize_t certificate_store(struct kobject *kobj,
>  		if (!setting->signature || !setting->signature[0])
>  			return -EACCES;
>  
> -		/* Format: 'serial#, signature' */
> -		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
> -				dmi_get_system_info(DMI_PRODUCT_SERIAL),
> -				setting->signature);
> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
> +			/* Format: 'SVC | SMC, serial#, signature' */
> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
> +					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
> +					     dmi_get_system_info(DMI_PRODUCT_SERIAL),
> +					     setting->signature);
> +		} else {
> +			/* Format: 'serial#, signature' */
> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s",
> +					     dmi_get_system_info(DMI_PRODUCT_SERIAL),
> +					     setting->signature);
> +		}
>  		if (!auth_str)
>  			return -ENOMEM;
>  
> @@ -776,24 +816,59 @@ static ssize_t certificate_store(struct kobject *kobj,
>  
>  	if (setting->cert_installed) {
>  		/* Certificate is installed so this is an update */
> -		if (!setting->signature || !setting->signature[0]) {
> +		install_mode = TLMI_CERT_UPDATE;
> +		/* If admin account enabled - need to use it's signature */
> +		if (tlmi_priv.pwd_admin->pwd_enabled)
> +			signature = tlmi_priv.pwd_admin->signature;
> +		else
> +			signature = setting->signature;
> +	} else { /* Cert install */
> +		/* Check if SMC and SVC already installed */
> +		if ((setting == tlmi_priv.pwd_system) && tlmi_priv.pwd_admin->cert_installed) {
> +			/* This gets treated as a cert update */
> +			install_mode = TLMI_CERT_UPDATE;
> +			signature = tlmi_priv.pwd_admin->signature;
> +		} else { /* Regular cert install */
> +			install_mode = TLMI_CERT_INSTALL;
> +			signature = setting->signature;
> +		}
> +	}
> +
> +	if (install_mode == TLMI_CERT_UPDATE) {
> +		/* This is a certificate update */
> +		if (!signature || !signature[0]) {
>  			kfree(new_cert);
>  			return -EACCES;
>  		}
>  		guid = LENOVO_UPDATE_BIOS_CERT_GUID;
> -		/* Format: 'Certificate,Signature' */
> -		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
> -				new_cert, setting->signature);
> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
> +			/* Format: 'SVC | SMC, certificate, signature' */
> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
> +					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
> +					     new_cert, signature);
> +		} else {
> +			/* Format: 'Certificate,Signature' */
> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s",
> +					     new_cert, signature);
> +		}
>  	} else {
>  		/* This is a fresh install */
> -		if (!setting->pwd_enabled || !setting->password[0]) {
> +		/* To set admin cert, a password must be enabled */
> +		if ((setting == tlmi_priv.pwd_admin) &&
> +		    (!setting->pwd_enabled || !setting->password[0])) {
>  			kfree(new_cert);
>  			return -EACCES;
>  		}
>  		guid = LENOVO_SET_BIOS_CERT_GUID;
> -		/* Format: 'Certificate,Admin-password' */
> -		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
> -				new_cert, setting->password);
> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
> +			/* Format: 'SVC | SMC, Certificate, password' */
> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
> +					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
> +					     new_cert, setting->password);
> +		} else {
> +			/* Format: 'Certificate, password' */
> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s", new_cert, setting->password);
> +		}

Have you considered creating a helper for this if/else construct to create 
the string? (you've basically repeated it multiple times by now with 
limited change to only parameters AFAICT).

>  	}
>  	kfree(new_cert);
>  	if (!auth_str)
> @@ -873,14 +948,19 @@ static umode_t auth_attr_is_visible(struct kobject *kobj,
>  		return 0;
>  	}
>  
> -	/* We only display certificates on Admin account, if supported */
> +	/* We only display certificates, if supported */
>  	if (attr == &auth_certificate.attr ||
>  	    attr == &auth_signature.attr ||
>  	    attr == &auth_save_signature.attr ||
>  	    attr == &auth_cert_thumb.attr ||
>  	    attr == &auth_cert_to_password.attr) {
> -		if ((setting == tlmi_priv.pwd_admin) && tlmi_priv.certificate_support)
> +		if (tlmi_priv.certificate_support) {
> +			if (setting == tlmi_priv.pwd_admin)

These two if()s combined look the same as the old ode, why are you redoing 
it?

> +				return attr->mode;
> +		if ((tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) &&
> +		    (setting == tlmi_priv.pwd_system))
>  			return attr->mode;
> +		}
>  		return 0;
>  	}
>  
> @@ -1700,12 +1780,13 @@ static int tlmi_analyze(void)
>  		}
>  	}
>  
> -	if (tlmi_priv.certificate_support &&
> -		(tlmi_priv.pwdcfg.core.password_state & TLMI_CERT))
> -		tlmi_priv.pwd_admin->cert_installed = true;
> -
> +	if (tlmi_priv.certificate_support) {
> +		tlmi_priv.pwd_admin->cert_installed =
> +			tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC;
> +		tlmi_priv.pwd_system->cert_installed =
> +			tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SMC;
> +	}
>  	return 0;
> -

Stray change.

-- 
 i.

>  fail_clear_attr:
>  	for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
>  		if (tlmi_priv.setting[i]) {
> diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h
> index 4728f40143a3..f267d8b46957 100644
> --- a/drivers/platform/x86/think-lmi.h
> +++ b/drivers/platform/x86/think-lmi.h
> @@ -41,6 +41,10 @@ enum save_mode {
>  };
>  
>  /* password configuration details */
> +#define TLMI_PWDCFG_MODE_LEGACY    0
> +#define TLMI_PWDCFG_MODE_PASSWORD  1
> +#define TLMI_PWDCFG_MODE_MULTICERT 3
> +
>  struct tlmi_pwdcfg_core {
>  	uint32_t password_mode;
>  	uint32_t password_state;
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/4] platform/x86: think-lmi: Allow empty admin password
  2024-10-22  7:59   ` Ilpo Järvinen
@ 2024-10-22 19:19     ` Mark Pearson
  0 siblings, 0 replies; 8+ messages in thread
From: Mark Pearson @ 2024-10-22 19:19 UTC (permalink / raw)
  To: Ilpo Järvinen; +Cc: Hans de Goede, platform-driver-x86, LKML

Hi Ilpo

On Tue, Oct 22, 2024, at 3:59 AM, Ilpo Järvinen wrote:
> On Mon, 21 Oct 2024, Mark Pearson wrote:
>
>> SVP = BIOS Supervisor/Admin password
>> SMP = BIOS System password
>> 
>> If SMP ACL is enabled in the BIOS then the system allows you to set the
>> SMP without a SVP password configured. Change code to allow this.
>> BIOS will return permissions error if SVP is required.
>> 
>> Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
>> ---
>>  drivers/platform/x86/think-lmi.c | 7 ++++++-
>>  1 file changed, 6 insertions(+), 1 deletion(-)
>> 
>> diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
>> index 46ab82fb2898..751e351dfc42 100644
>> --- a/drivers/platform/x86/think-lmi.c
>> +++ b/drivers/platform/x86/think-lmi.c
>> @@ -469,7 +469,12 @@ static ssize_t new_password_store(struct kobject *kobj,
>>  		if (ret)
>>  			goto out;
>>  
>> -		if (tlmi_priv.pwd_admin->pwd_enabled) {
>> +		/*
>> +		 * Note admin password not always required if SMPControl enabled in BIOS,
>
> is not always required
>
>> +		 * So only set if it's configured.
>> +		 * Let BIOS figure it out - we'll get an error if operation not permitted
>
> operation is not permitted.
>
> Please reflow the comment to fit into 80 chars (this only relates to 
> comments to keep their line lengths readable without large eye movement).
>
>> +		 */
>> +		if (tlmi_priv.pwd_admin->pwd_enabled && strlen(tlmi_priv.pwd_admin->password)) {
>>  			ret = tlmi_opcode_setting("WmiOpcodePasswordAdmin",
>>  					tlmi_priv.pwd_admin->password);
>>  			if (ret)
>> 
>
> -- 
>  i.

Thanks for the review.
I'll update those. I'll give it a couple of days in case there is any other feedback
Mark

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/4] platform/x86: think-lmi: Multi-certificate support
  2024-10-22  8:14   ` Ilpo Järvinen
@ 2024-10-22 19:30     ` Mark Pearson
  0 siblings, 0 replies; 8+ messages in thread
From: Mark Pearson @ 2024-10-22 19:30 UTC (permalink / raw)
  To: Ilpo Järvinen; +Cc: Hans de Goede, platform-driver-x86, LKML

Hi Ilpo,

Thanks for the review.

On Tue, Oct 22, 2024, at 4:14 AM, Ilpo Järvinen wrote:
> On Mon, 21 Oct 2024, Mark Pearson wrote:
>
>> Lenovo are adding support for both Admin and System certificates to
>> the certificate based authentication feature
>> 
>> This commit adds the support for this.
>> 
>> Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca>
>> ---
>>  .../testing/sysfs-class-firmware-attributes   |   1 +
>>  drivers/platform/x86/think-lmi.c              | 141 ++++++++++++++----
>>  drivers/platform/x86/think-lmi.h              |   4 +
>>  3 files changed, 116 insertions(+), 30 deletions(-)
>> 
>> diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Documentation/ABI/testing/sysfs-class-firmware-attributes
>> index 1a8b59f5d6e3..2713efa509b4 100644
>> --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes
>> +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes
>> @@ -303,6 +303,7 @@ Description:
>>  					being configured allowing anyone to make changes.
>>  					After any of these operations the system must reboot for the changes to
>>  					take effect.
>> +					Admin and System certificates are supported from 2025 systems onward.
>>  
>>  		certificate_thumbprint:
>>  					Read only attribute used to display the MD5, SHA1 and SHA256 thumbprints
>> diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
>> index 751e351dfc42..fca190232c24 100644
>> --- a/drivers/platform/x86/think-lmi.c
>> +++ b/drivers/platform/x86/think-lmi.c
>> @@ -169,11 +169,12 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support");
>>   */
>>  #define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4"
>>  
>> -#define TLMI_POP_PWD BIT(0) /* Supervisor */
>> -#define TLMI_PAP_PWD BIT(1) /* Power-on */
>> -#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */
>> -#define TLMI_SMP_PWD BIT(6) /* System Management */
>> -#define TLMI_CERT    BIT(7) /* Certificate Based */
>> +#define TLMI_POP_PWD  BIT(0) /* Supervisor */
>> +#define TLMI_PAP_PWD  BIT(1) /* Power-on */
>> +#define TLMI_HDD_PWD  BIT(2) /* HDD/NVME */
>> +#define TLMI_SMP_PWD  BIT(6) /* System Management */
>> +#define TLMI_CERT_SVC BIT(7) /* Admin Certificate Based */
>> +#define TLMI_CERT_SMC BIT(8) /* System Certificate Based */
>>  
>>  static const struct tlmi_err_codes tlmi_errs[] = {
>>  	{"Success", 0},
>> @@ -678,18 +679,35 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count)
>>  	return count;
>>  }
>>  
>> +#define NUM_THUMBTYPES 3
>> +static char *thumbtypes[NUM_THUMBTYPES] = {"Md5", "Sha1", "Sha256"};
>> +
>>  static ssize_t certificate_thumbprint_show(struct kobject *kobj, struct kobj_attribute *attr,
>>  			 char *buf)
>>  {
>>  	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
>> -	int count = 0;
>> +	char *wmistr;
>> +	int count = 0, i;
>
> Reverse xmas-tree order.

Ack

>
>>  
>>  	if (!tlmi_priv.certificate_support || !setting->cert_installed)
>>  		return -EOPNOTSUPP;
>>  
>> -	count += cert_thumbprint(buf, "Md5", count);
>> -	count += cert_thumbprint(buf, "Sha1", count);
>> -	count += cert_thumbprint(buf, "Sha256", count);
>> +	for (i = 0; i < NUM_THUMBTYPES; i++) {
>
> Use ARRAY_SIZE() + add include for it.
>
> These days, the usual custom is to use unsigned int for loop variables 
> that are never meant to be negative.
>
Will update.

>> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
>> +			/* Format: 'SVC | SMC, Thumbtype' */
>> +			wmistr = kasprintf(GFP_KERNEL, "%s,%s",
>> +					   setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
>> +					   thumbtypes[i]);
>> +		} else {
>> +			/* Format: 'Thumbtype' */
>> +			wmistr = kasprintf(GFP_KERNEL, "%s", thumbtypes[i]);
>> +		}
>> +		if (!wmistr)
>> +			return -ENOMEM;
>> +		count += cert_thumbprint(buf, wmistr, count);
>> +		kfree(wmistr);
>> +	}
>> +
>>  	return count;
>>  }
>>  
>> @@ -720,8 +738,15 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
>>  	if (!passwd)
>>  		return -ENOMEM;
>>  
>> -	/* Format: 'Password,Signature' */
>> -	auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
>> +	if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
>> +		/* Format: 'SVC | SMC, password, signature' */
>> +		auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
>> +				     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
>> +				     passwd, setting->signature);
>> +	} else {
>> +		/* Format: 'Password,Signature' */
>> +		auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
>> +	}
>>  	if (!auth_str) {
>>  		kfree_sensitive(passwd);
>>  		return -ENOMEM;
>> @@ -735,12 +760,19 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
>>  
>>  static struct kobj_attribute auth_cert_to_password = __ATTR_WO(cert_to_password);
>>  
>> +enum cert_install_mode {
>> +	TLMI_CERT_INSTALL,
>> +	TLMI_CERT_UPDATE,
>> +};
>> +
>>  static ssize_t certificate_store(struct kobject *kobj,
>>  				  struct kobj_attribute *attr,
>>  				  const char *buf, size_t count)
>>  {
>>  	struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
>> +	enum cert_install_mode install_mode = TLMI_CERT_INSTALL;
>>  	char *auth_str, *new_cert;
>> +	char *signature;
>>  	char *guid;
>>  	int ret;
>>  
>> @@ -756,10 +788,18 @@ static ssize_t certificate_store(struct kobject *kobj,
>>  		if (!setting->signature || !setting->signature[0])
>>  			return -EACCES;
>>  
>> -		/* Format: 'serial#, signature' */
>> -		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
>> -				dmi_get_system_info(DMI_PRODUCT_SERIAL),
>> -				setting->signature);
>> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
>> +			/* Format: 'SVC | SMC, serial#, signature' */
>> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
>> +					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
>> +					     dmi_get_system_info(DMI_PRODUCT_SERIAL),
>> +					     setting->signature);
>> +		} else {
>> +			/* Format: 'serial#, signature' */
>> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s",
>> +					     dmi_get_system_info(DMI_PRODUCT_SERIAL),
>> +					     setting->signature);
>> +		}
>>  		if (!auth_str)
>>  			return -ENOMEM;
>>  
>> @@ -776,24 +816,59 @@ static ssize_t certificate_store(struct kobject *kobj,
>>  
>>  	if (setting->cert_installed) {
>>  		/* Certificate is installed so this is an update */
>> -		if (!setting->signature || !setting->signature[0]) {
>> +		install_mode = TLMI_CERT_UPDATE;
>> +		/* If admin account enabled - need to use it's signature */
>> +		if (tlmi_priv.pwd_admin->pwd_enabled)
>> +			signature = tlmi_priv.pwd_admin->signature;
>> +		else
>> +			signature = setting->signature;
>> +	} else { /* Cert install */
>> +		/* Check if SMC and SVC already installed */
>> +		if ((setting == tlmi_priv.pwd_system) && tlmi_priv.pwd_admin->cert_installed) {
>> +			/* This gets treated as a cert update */
>> +			install_mode = TLMI_CERT_UPDATE;
>> +			signature = tlmi_priv.pwd_admin->signature;
>> +		} else { /* Regular cert install */
>> +			install_mode = TLMI_CERT_INSTALL;
>> +			signature = setting->signature;
>> +		}
>> +	}
>> +
>> +	if (install_mode == TLMI_CERT_UPDATE) {
>> +		/* This is a certificate update */
>> +		if (!signature || !signature[0]) {
>>  			kfree(new_cert);
>>  			return -EACCES;
>>  		}
>>  		guid = LENOVO_UPDATE_BIOS_CERT_GUID;
>> -		/* Format: 'Certificate,Signature' */
>> -		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
>> -				new_cert, setting->signature);
>> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
>> +			/* Format: 'SVC | SMC, certificate, signature' */
>> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
>> +					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
>> +					     new_cert, signature);
>> +		} else {
>> +			/* Format: 'Certificate,Signature' */
>> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s",
>> +					     new_cert, signature);
>> +		}
>>  	} else {
>>  		/* This is a fresh install */
>> -		if (!setting->pwd_enabled || !setting->password[0]) {
>> +		/* To set admin cert, a password must be enabled */
>> +		if ((setting == tlmi_priv.pwd_admin) &&
>> +		    (!setting->pwd_enabled || !setting->password[0])) {
>>  			kfree(new_cert);
>>  			return -EACCES;
>>  		}
>>  		guid = LENOVO_SET_BIOS_CERT_GUID;
>> -		/* Format: 'Certificate,Admin-password' */
>> -		auth_str = kasprintf(GFP_KERNEL, "%s,%s",
>> -				new_cert, setting->password);
>> +		if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
>> +			/* Format: 'SVC | SMC, Certificate, password' */
>> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s,%s",
>> +					     setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
>> +					     new_cert, setting->password);
>> +		} else {
>> +			/* Format: 'Certificate, password' */
>> +			auth_str = kasprintf(GFP_KERNEL, "%s,%s", new_cert, setting->password);
>> +		}
>
> Have you considered creating a helper for this if/else construct to create 
> the string? (you've basically repeated it multiple times by now with 
> limited change to only parameters AFAICT).
>

I hadn't considered it, but yeah, it probably makes sense.
Not completely sure how I would do it to be honest - if you've got any suggestions let me know, but I will look into it and see if I can improve it.

>>  	}
>>  	kfree(new_cert);
>>  	if (!auth_str)
>> @@ -873,14 +948,19 @@ static umode_t auth_attr_is_visible(struct kobject *kobj,
>>  		return 0;
>>  	}
>>  
>> -	/* We only display certificates on Admin account, if supported */
>> +	/* We only display certificates, if supported */
>>  	if (attr == &auth_certificate.attr ||
>>  	    attr == &auth_signature.attr ||
>>  	    attr == &auth_save_signature.attr ||
>>  	    attr == &auth_cert_thumb.attr ||
>>  	    attr == &auth_cert_to_password.attr) {
>> -		if ((setting == tlmi_priv.pwd_admin) && tlmi_priv.certificate_support)
>> +		if (tlmi_priv.certificate_support) {
>> +			if (setting == tlmi_priv.pwd_admin)
>
> These two if()s combined look the same as the old ode, why are you redoing 
> it?

My indenting here is somehow messed up...not sure how that happened (will fix).
The block below should be indented too...and then I think it makes more sense.
Let me know if you disagree.

>
>> +				return attr->mode;
>> +		if ((tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) &&
>> +		    (setting == tlmi_priv.pwd_system))
>>  			return attr->mode;
>> +		}
>>  		return 0;
>>  	}
>>  
>> @@ -1700,12 +1780,13 @@ static int tlmi_analyze(void)
>>  		}
>>  	}
>>  
>> -	if (tlmi_priv.certificate_support &&
>> -		(tlmi_priv.pwdcfg.core.password_state & TLMI_CERT))
>> -		tlmi_priv.pwd_admin->cert_installed = true;
>> -
>> +	if (tlmi_priv.certificate_support) {
>> +		tlmi_priv.pwd_admin->cert_installed =
>> +			tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC;
>> +		tlmi_priv.pwd_system->cert_installed =
>> +			tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SMC;
>> +	}
>>  	return 0;
>> -
>
> Stray change.

Oops. Will fix.

>
> -- 
>  i.
>
>>  fail_clear_attr:
>>  	for (i = 0; i < TLMI_SETTINGS_COUNT; ++i) {
>>  		if (tlmi_priv.setting[i]) {
>> diff --git a/drivers/platform/x86/think-lmi.h b/drivers/platform/x86/think-lmi.h
>> index 4728f40143a3..f267d8b46957 100644
>> --- a/drivers/platform/x86/think-lmi.h
>> +++ b/drivers/platform/x86/think-lmi.h
>> @@ -41,6 +41,10 @@ enum save_mode {
>>  };
>>  
>>  /* password configuration details */
>> +#define TLMI_PWDCFG_MODE_LEGACY    0
>> +#define TLMI_PWDCFG_MODE_PASSWORD  1
>> +#define TLMI_PWDCFG_MODE_MULTICERT 3
>> +
>>  struct tlmi_pwdcfg_core {
>>  	uint32_t password_mode;
>>  	uint32_t password_state;
>>

Mark

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2024-10-22 19:30 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-10-21 19:38 [PATCH 1/4] platform/x86: think-lmi: improve check if BIOS account security enabled Mark Pearson
2024-10-21 19:38 ` [PATCH 2/4] platform/x86: think-lmi: Add certificate as mechanism Mark Pearson
2024-10-21 19:38 ` [PATCH 3/4] platform/x86: think-lmi: Allow empty admin password Mark Pearson
2024-10-22  7:59   ` Ilpo Järvinen
2024-10-22 19:19     ` Mark Pearson
2024-10-21 19:38 ` [PATCH 4/4] platform/x86: think-lmi: Multi-certificate support Mark Pearson
2024-10-22  8:14   ` Ilpo Järvinen
2024-10-22 19:30     ` Mark Pearson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®