brintos

brintos / linux-shallow public Read only

0
0
Text · 15.3 KiB · 35936c0 Raw
547 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Functions corresponding to password object type attributes under4 * BIOS PASSWORD for use with hp-bioscfg driver.5 *6 * Copyright (c) 2022 HP Development Company, L.P.7 */8 9#include "bioscfg.h"10 11GET_INSTANCE_ID(password);12/*13 * Clear all passwords copied to memory for a particular14 * authentication instance15 */16static int clear_passwords(const int instance)17{18	struct password_data *password_data = &bioscfg_drv.password_data[instance];19 20	if (!password_data->is_enabled)21		return 0;22 23	memset(password_data->current_password,24	       0, sizeof(password_data->current_password));25	memset(password_data->new_password,26	       0, sizeof(password_data->new_password));27 28	return 0;29}30 31/*32 * Clear all credentials copied to memory for both Power-ON and Setup33 * BIOS instances34 */35int hp_clear_all_credentials(void)36{37	int count = bioscfg_drv.password_instances_count;38	int instance;39 40	/* clear all passwords */41	for (instance = 0; instance < count; instance++)42		clear_passwords(instance);43 44	/* clear auth_token */45	kfree(bioscfg_drv.spm_data.auth_token);46	bioscfg_drv.spm_data.auth_token = NULL;47 48	return 0;49}50 51int hp_get_password_instance_for_type(const char *name)52{53	int count = bioscfg_drv.password_instances_count;54	int instance;55 56	for (instance = 0; instance < count; instance++)57		if (!strcmp(bioscfg_drv.password_data[instance].common.display_name, name))58			return instance;59 60	return -EINVAL;61}62 63static int validate_password_input(int instance_id, const char *buf)64{65	int length;66	struct password_data *password_data = &bioscfg_drv.password_data[instance_id];67 68	length = strlen(buf);69	if (buf[length - 1] == '\n')70		length--;71 72	if (length > MAX_PASSWD_SIZE)73		return INVALID_BIOS_AUTH;74 75	if (password_data->min_password_length > length ||76	    password_data->max_password_length < length)77		return INVALID_BIOS_AUTH;78	return SUCCESS;79}80 81ATTRIBUTE_N_PROPERTY_SHOW(is_enabled, password);82static struct kobj_attribute password_is_password_set = __ATTR_RO(is_enabled);83 84static int store_password_instance(struct kobject *kobj, const char *buf,85				   size_t count, bool is_current)86{87	char *buf_cp;88	int id, ret = 0;89 90	buf_cp = kstrdup(buf, GFP_KERNEL);91	if (!buf_cp)92		return -ENOMEM;93 94	ret = hp_enforce_single_line_input(buf_cp, count);95	if (!ret) {96		id = get_password_instance_id(kobj);97 98		if (id >= 0)99			ret = validate_password_input(id, buf_cp);100	}101 102	if (!ret) {103		if (is_current)104			strscpy(bioscfg_drv.password_data[id].current_password, buf_cp);105		else106			strscpy(bioscfg_drv.password_data[id].new_password, buf_cp);107	}108 109	kfree(buf_cp);110	return ret < 0 ? ret : count;111}112 113static ssize_t current_password_store(struct kobject *kobj,114				      struct kobj_attribute *attr,115				      const char *buf, size_t count)116{117	return store_password_instance(kobj, buf, count, true);118}119 120static struct kobj_attribute password_current_password = __ATTR_WO(current_password);121 122static ssize_t new_password_store(struct kobject *kobj,123				  struct kobj_attribute *attr,124				  const char *buf, size_t count)125{126	return store_password_instance(kobj, buf, count, true);127}128 129static struct kobj_attribute password_new_password = __ATTR_WO(new_password);130 131ATTRIBUTE_N_PROPERTY_SHOW(min_password_length, password);132static struct kobj_attribute password_min_password_length = __ATTR_RO(min_password_length);133 134ATTRIBUTE_N_PROPERTY_SHOW(max_password_length, password);135static struct kobj_attribute password_max_password_length = __ATTR_RO(max_password_length);136 137static ssize_t role_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)138{139	if (!strcmp(kobj->name, SETUP_PASSWD))140		return sysfs_emit(buf, "%s\n", BIOS_ADMIN);141 142	if (!strcmp(kobj->name, POWER_ON_PASSWD))143		return sysfs_emit(buf, "%s\n", POWER_ON);144 145	return -EIO;146}147 148static struct kobj_attribute password_role = __ATTR_RO(role);149 150static ssize_t mechanism_show(struct kobject *kobj, struct kobj_attribute *attr,151			      char *buf)152{153	int i = get_password_instance_id(kobj);154 155	if (i < 0)156		return i;157 158	if (bioscfg_drv.password_data[i].mechanism != PASSWORD)159		return -EINVAL;160 161	return sysfs_emit(buf, "%s\n", PASSWD_MECHANISM_TYPES);162}163 164static struct kobj_attribute password_mechanism = __ATTR_RO(mechanism);165 166ATTRIBUTE_VALUES_PROPERTY_SHOW(encodings, password, SEMICOLON_SEP);167static struct kobj_attribute password_encodings_val = __ATTR_RO(encodings);168 169static struct attribute *password_attrs[] = {170	&password_is_password_set.attr,171	&password_min_password_length.attr,172	&password_max_password_length.attr,173	&password_current_password.attr,174	&password_new_password.attr,175	&password_role.attr,176	&password_mechanism.attr,177	&password_encodings_val.attr,178	NULL179};180 181static const struct attribute_group password_attr_group = {182	.attrs = password_attrs183};184 185int hp_alloc_password_data(void)186{187	bioscfg_drv.password_instances_count = hp_get_instance_count(HP_WMI_BIOS_PASSWORD_GUID);188	bioscfg_drv.password_data = kcalloc(bioscfg_drv.password_instances_count,189					    sizeof(*bioscfg_drv.password_data), GFP_KERNEL);190	if (!bioscfg_drv.password_data) {191		bioscfg_drv.password_instances_count = 0;192		return -ENOMEM;193	}194 195	return 0;196}197 198/* Expected Values types associated with each element */199static const acpi_object_type expected_password_types[] = {200	[NAME] = ACPI_TYPE_STRING,201	[VALUE] = ACPI_TYPE_STRING,202	[PATH] = ACPI_TYPE_STRING,203	[IS_READONLY] = ACPI_TYPE_INTEGER,204	[DISPLAY_IN_UI] = ACPI_TYPE_INTEGER,205	[REQUIRES_PHYSICAL_PRESENCE] = ACPI_TYPE_INTEGER,206	[SEQUENCE] = ACPI_TYPE_INTEGER,207	[PREREQUISITES_SIZE] = ACPI_TYPE_INTEGER,208	[PREREQUISITES] = ACPI_TYPE_STRING,209	[SECURITY_LEVEL] = ACPI_TYPE_INTEGER,210	[PSWD_MIN_LENGTH] = ACPI_TYPE_INTEGER,211	[PSWD_MAX_LENGTH] = ACPI_TYPE_INTEGER,212	[PSWD_SIZE] = ACPI_TYPE_INTEGER,213	[PSWD_ENCODINGS] = ACPI_TYPE_STRING,214	[PSWD_IS_SET] = ACPI_TYPE_INTEGER,215};216 217static int hp_populate_password_elements_from_package(union acpi_object *password_obj,218						      int password_obj_count,219						      int instance_id)220{221	char *str_value = NULL;222	int value_len;223	int ret;224	u32 size;225	u32 int_value = 0;226	int elem;227	int reqs;228	int eloc;229	int pos_values;230	struct password_data *password_data = &bioscfg_drv.password_data[instance_id];231 232	if (!password_obj)233		return -EINVAL;234 235	for (elem = 1, eloc = 1; elem < password_obj_count; elem++, eloc++) {236		/* ONLY look at the first PASSWORD_ELEM_CNT elements */237		if (eloc == PSWD_ELEM_CNT)238			goto exit_package;239 240		switch (password_obj[elem].type) {241		case ACPI_TYPE_STRING:242			if (PREREQUISITES != elem && PSWD_ENCODINGS != elem) {243				ret = hp_convert_hexstr_to_str(password_obj[elem].string.pointer,244							       password_obj[elem].string.length,245							       &str_value, &value_len);246				if (ret)247					continue;248			}249			break;250		case ACPI_TYPE_INTEGER:251			int_value = (u32)password_obj[elem].integer.value;252			break;253		default:254			pr_warn("Unsupported object type [%d]\n", password_obj[elem].type);255			continue;256		}257 258		/* Check that both expected and read object type match */259		if (expected_password_types[eloc] != password_obj[elem].type) {260			pr_err("Error expected type %d for elem %d, but got type %d instead\n",261			       expected_password_types[eloc], elem, password_obj[elem].type);262			kfree(str_value);263			return -EIO;264		}265 266		/* Assign appropriate element value to corresponding field*/267		switch (eloc) {268		case VALUE:269			break;270		case PATH:271			strscpy(password_data->common.path, str_value);272			break;273		case IS_READONLY:274			password_data->common.is_readonly = int_value;275			break;276		case DISPLAY_IN_UI:277			password_data->common.display_in_ui = int_value;278			break;279		case REQUIRES_PHYSICAL_PRESENCE:280			password_data->common.requires_physical_presence = int_value;281			break;282		case SEQUENCE:283			password_data->common.sequence = int_value;284			break;285		case PREREQUISITES_SIZE:286			if (int_value > MAX_PREREQUISITES_SIZE) {287				pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");288				int_value = MAX_PREREQUISITES_SIZE;289			}290			password_data->common.prerequisites_size = int_value;291 292			/* This step is needed to keep the expected293			 * element list pointing to the right obj[elem].type294			 * when the size is zero. PREREQUISITES295			 * object is omitted by BIOS when the size is296			 * zero.297			 */298			if (int_value == 0)299				eloc++;300			break;301		case PREREQUISITES:302			size = min_t(u32, password_data->common.prerequisites_size,303				     MAX_PREREQUISITES_SIZE);304 305			for (reqs = 0; reqs < size; reqs++) {306				ret = hp_convert_hexstr_to_str(password_obj[elem + reqs].string.pointer,307							       password_obj[elem + reqs].string.length,308							       &str_value, &value_len);309 310				if (ret)311					break;312 313				strscpy(password_data->common.prerequisites[reqs], str_value);314 315				kfree(str_value);316				str_value = NULL;317 318			}319			break;320		case SECURITY_LEVEL:321			password_data->common.security_level = int_value;322			break;323		case PSWD_MIN_LENGTH:324			password_data->min_password_length = int_value;325			break;326		case PSWD_MAX_LENGTH:327			password_data->max_password_length = int_value;328			break;329		case PSWD_SIZE:330 331			if (int_value > MAX_ENCODINGS_SIZE) {332				pr_warn("Password Encoding size value exceeded the maximum number of elements supported or data may be malformed\n");333				int_value = MAX_ENCODINGS_SIZE;334			}335			password_data->encodings_size = int_value;336 337			/* This step is needed to keep the expected338			 * element list pointing to the right obj[elem].type339			 * when the size is zero. PSWD_ENCODINGS340			 * object is omitted by BIOS when the size is341			 * zero.342			 */343			if (int_value == 0)344				eloc++;345			break;346		case PSWD_ENCODINGS:347			size = min_t(u32, password_data->encodings_size, MAX_ENCODINGS_SIZE);348			for (pos_values = 0; pos_values < size; pos_values++) {349				ret = hp_convert_hexstr_to_str(password_obj[elem + pos_values].string.pointer,350							       password_obj[elem + pos_values].string.length,351							       &str_value, &value_len);352				if (ret)353					break;354 355				strscpy(password_data->encodings[pos_values], str_value);356				kfree(str_value);357				str_value = NULL;358 359			}360			break;361		case PSWD_IS_SET:362			password_data->is_enabled = int_value;363			break;364		default:365			pr_warn("Invalid element: %d found in Password attribute or data may be malformed\n", elem);366			break;367		}368 369		kfree(str_value);370		str_value = NULL;371	}372 373exit_package:374	kfree(str_value);375	return 0;376}377 378/**379 * hp_populate_password_package_data()380 *	Populate all properties for an instance under password attribute381 *382 * @password_obj: ACPI object with password data383 * @instance_id: The instance to enumerate384 * @attr_name_kobj: The parent kernel object385 */386int hp_populate_password_package_data(union acpi_object *password_obj, int instance_id,387				      struct kobject *attr_name_kobj)388{389	struct password_data *password_data = &bioscfg_drv.password_data[instance_id];390 391	password_data->attr_name_kobj = attr_name_kobj;392 393	hp_populate_password_elements_from_package(password_obj,394						   password_obj->package.count,395						   instance_id);396 397	hp_friendly_user_name_update(password_data->common.path,398				     attr_name_kobj->name,399				     password_data->common.display_name,400				     sizeof(password_data->common.display_name));401 402	if (!strcmp(attr_name_kobj->name, SETUP_PASSWD))403		return sysfs_create_group(attr_name_kobj, &password_attr_group);404 405	return sysfs_create_group(attr_name_kobj, &password_attr_group);406}407 408static int hp_populate_password_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size,409						     int instance_id)410{411	int values;412	int isreadonly;413	struct password_data *password_data = &bioscfg_drv.password_data[instance_id];414	int ret = 0;415 416	/*417	 * Only data relevant to this driver and its functionality is418	 * read. BIOS defines the order in which each * element is419	 * read. Element 0 data is not relevant to this420	 * driver hence it is ignored. For clarity, all element names421	 * (DISPLAY_IN_UI) which defines the order in which is read422	 * and the name matches the variable where the data is stored.423	 *424	 * In earlier implementation, reported errors were ignored425	 * causing the data to remain uninitialized. It is not426	 * possible to determine if data read from BIOS is valid or427	 * not. It is for this reason functions may return a error428	 * without validating the data itself.429	 */430 431	// VALUE:432	ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, password_data->current_password,433					sizeof(password_data->current_password));434	if (ret < 0)435		goto buffer_exit;436 437	// COMMON:438	ret = hp_get_common_data_from_buffer(&buffer_ptr, buffer_size,439					     &password_data->common);440	if (ret < 0)441		goto buffer_exit;442 443	// PSWD_MIN_LENGTH:444	ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,445					 &password_data->min_password_length);446	if (ret < 0)447		goto buffer_exit;448 449	// PSWD_MAX_LENGTH:450	ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,451					 &password_data->max_password_length);452	if (ret < 0)453		goto buffer_exit;454 455	// PSWD_SIZE:456	ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,457					 &password_data->encodings_size);458	if (ret < 0)459		goto buffer_exit;460 461	if (password_data->encodings_size > MAX_ENCODINGS_SIZE) {462		/* Report a message and limit possible values size to maximum value */463		pr_warn("Password Encoding size value exceeded the maximum number of elements supported or data may be malformed\n");464		password_data->encodings_size = MAX_ENCODINGS_SIZE;465	}466 467	// PSWD_ENCODINGS:468	for (values = 0; values < password_data->encodings_size; values++) {469		ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size,470						password_data->encodings[values],471						sizeof(password_data->encodings[values]));472		if (ret < 0)473			break;474	}475 476	// PSWD_IS_SET:477	ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size, &isreadonly);478	if (ret < 0)479		goto buffer_exit;480 481	password_data->is_enabled = isreadonly ? true : false;482 483buffer_exit:484	return ret;485}486 487/**488 * hp_populate_password_buffer_data()489 * Populate all properties for an instance under password object attribute490 *491 * @buffer_ptr: Buffer pointer492 * @buffer_size: Buffer size493 * @instance_id: The instance to enumerate494 * @attr_name_kobj: The parent kernel object495 */496int hp_populate_password_buffer_data(u8 *buffer_ptr, u32 *buffer_size, int instance_id,497				     struct kobject *attr_name_kobj)498{499	struct password_data *password_data = &bioscfg_drv.password_data[instance_id];500	int ret = 0;501 502	password_data->attr_name_kobj = attr_name_kobj;503 504	/* Populate Password attributes */505	ret = hp_populate_password_elements_from_buffer(buffer_ptr, buffer_size,506							instance_id);507	if (ret < 0)508		return ret;509 510	hp_friendly_user_name_update(password_data->common.path,511				     attr_name_kobj->name,512				     password_data->common.display_name,513				     sizeof(password_data->common.display_name));514	if (!strcmp(attr_name_kobj->name, SETUP_PASSWD))515		return sysfs_create_group(attr_name_kobj, &password_attr_group);516 517	return sysfs_create_group(attr_name_kobj, &password_attr_group);518}519 520/**521 * hp_exit_password_attributes() - Clear all attribute data522 *523 * Clears all data allocated for this group of attributes524 */525void hp_exit_password_attributes(void)526{527	int instance_id;528 529	for (instance_id = 0; instance_id < bioscfg_drv.password_instances_count;530	     instance_id++) {531		struct kobject *attr_name_kobj =532			bioscfg_drv.password_data[instance_id].attr_name_kobj;533 534		if (attr_name_kobj) {535			if (!strcmp(attr_name_kobj->name, SETUP_PASSWD))536				sysfs_remove_group(attr_name_kobj,537						   &password_attr_group);538			else539				sysfs_remove_group(attr_name_kobj,540						   &password_attr_group);541		}542	}543	bioscfg_drv.password_instances_count = 0;544	kfree(bioscfg_drv.password_data);545	bioscfg_drv.password_data = NULL;546}547