Skip to content

Commit 1981b29

Browse files
Wer-Wolfjwrdegoede
authored andcommitted
platform/x86: dell-smbios: Fix wrong token data in sysfs
When reading token data from sysfs on my Inspiron 3505, the token locations and values are wrong. This happens because match_attribute() blindly assumes that all entries in da_tokens have an associated entry in token_attrs. This however is not true as soon as da_tokens[] contains zeroed token entries. Those entries are being skipped when initialising token_attrs, breaking the core assumption of match_attribute(). Fix this by defining an extra struct for each pair of token attributes and use container_of() to retrieve token information. Tested on a Dell Inspiron 3050. Fixes: 33b9ca1 ("platform/x86: dell-smbios: Add a sysfs interface for SMBIOS tokens") Signed-off-by: Armin Wolf <[email protected]> Reviewed-by: Ilpo Järvinen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Hans de Goede <[email protected]> Signed-off-by: Hans de Goede <[email protected]>
1 parent 078fc56 commit 1981b29

File tree

1 file changed

+36
-56
lines changed

1 file changed

+36
-56
lines changed

drivers/platform/x86/dell/dell-smbios-base.c

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1313

14+
#include <linux/container_of.h>
1415
#include <linux/kernel.h>
1516
#include <linux/module.h>
1617
#include <linux/capability.h>
@@ -25,11 +26,16 @@ static u32 da_supported_commands;
2526
static int da_num_tokens;
2627
static struct platform_device *platform_device;
2728
static struct calling_interface_token *da_tokens;
28-
static struct device_attribute *token_location_attrs;
29-
static struct device_attribute *token_value_attrs;
29+
static struct token_sysfs_data *token_entries;
3030
static struct attribute **token_attrs;
3131
static DEFINE_MUTEX(smbios_mutex);
3232

33+
struct token_sysfs_data {
34+
struct device_attribute location_attr;
35+
struct device_attribute value_attr;
36+
struct calling_interface_token *token;
37+
};
38+
3339
struct smbios_device {
3440
struct list_head list;
3541
struct device *device;
@@ -416,47 +422,26 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
416422
}
417423
}
418424

419-
static int match_attribute(struct device *dev,
420-
struct device_attribute *attr)
421-
{
422-
int i;
423-
424-
for (i = 0; i < da_num_tokens * 2; i++) {
425-
if (!token_attrs[i])
426-
continue;
427-
if (strcmp(token_attrs[i]->name, attr->attr.name) == 0)
428-
return i/2;
429-
}
430-
dev_dbg(dev, "couldn't match: %s\n", attr->attr.name);
431-
return -EINVAL;
432-
}
433-
434425
static ssize_t location_show(struct device *dev,
435426
struct device_attribute *attr, char *buf)
436427
{
437-
int i;
428+
struct token_sysfs_data *data = container_of(attr, struct token_sysfs_data, location_attr);
438429

439430
if (!capable(CAP_SYS_ADMIN))
440431
return -EPERM;
441432

442-
i = match_attribute(dev, attr);
443-
if (i > 0)
444-
return sysfs_emit(buf, "%08x", da_tokens[i].location);
445-
return 0;
433+
return sysfs_emit(buf, "%08x", data->token->location);
446434
}
447435

448436
static ssize_t value_show(struct device *dev,
449437
struct device_attribute *attr, char *buf)
450438
{
451-
int i;
439+
struct token_sysfs_data *data = container_of(attr, struct token_sysfs_data, value_attr);
452440

453441
if (!capable(CAP_SYS_ADMIN))
454442
return -EPERM;
455443

456-
i = match_attribute(dev, attr);
457-
if (i > 0)
458-
return sysfs_emit(buf, "%08x", da_tokens[i].value);
459-
return 0;
444+
return sysfs_emit(buf, "%08x", data->token->value);
460445
}
461446

462447
static struct attribute_group smbios_attribute_group = {
@@ -473,50 +458,48 @@ static int build_tokens_sysfs(struct platform_device *dev)
473458
{
474459
char *location_name;
475460
char *value_name;
476-
size_t size;
477461
int ret;
478462
int i, j;
479463

480-
/* (number of tokens + 1 for null terminated */
481-
size = sizeof(struct device_attribute) * (da_num_tokens + 1);
482-
token_location_attrs = kzalloc(size, GFP_KERNEL);
483-
if (!token_location_attrs)
464+
token_entries = kcalloc(da_num_tokens, sizeof(*token_entries), GFP_KERNEL);
465+
if (!token_entries)
484466
return -ENOMEM;
485-
token_value_attrs = kzalloc(size, GFP_KERNEL);
486-
if (!token_value_attrs)
487-
goto out_allocate_value;
488467

489468
/* need to store both location and value + terminator*/
490-
size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1);
491-
token_attrs = kzalloc(size, GFP_KERNEL);
469+
token_attrs = kcalloc((2 * da_num_tokens) + 1, sizeof(*token_attrs), GFP_KERNEL);
492470
if (!token_attrs)
493471
goto out_allocate_attrs;
494472

495473
for (i = 0, j = 0; i < da_num_tokens; i++) {
496474
/* skip empty */
497475
if (da_tokens[i].tokenID == 0)
498476
continue;
477+
478+
token_entries[i].token = &da_tokens[i];
479+
499480
/* add location */
500481
location_name = kasprintf(GFP_KERNEL, "%04x_location",
501482
da_tokens[i].tokenID);
502483
if (location_name == NULL)
503484
goto out_unwind_strings;
504-
sysfs_attr_init(&token_location_attrs[i].attr);
505-
token_location_attrs[i].attr.name = location_name;
506-
token_location_attrs[i].attr.mode = 0444;
507-
token_location_attrs[i].show = location_show;
508-
token_attrs[j++] = &token_location_attrs[i].attr;
485+
486+
sysfs_attr_init(&token_entries[i].location_attr.attr);
487+
token_entries[i].location_attr.attr.name = location_name;
488+
token_entries[i].location_attr.attr.mode = 0444;
489+
token_entries[i].location_attr.show = location_show;
490+
token_attrs[j++] = &token_entries[i].location_attr.attr;
509491

510492
/* add value */
511493
value_name = kasprintf(GFP_KERNEL, "%04x_value",
512494
da_tokens[i].tokenID);
513495
if (value_name == NULL)
514496
goto loop_fail_create_value;
515-
sysfs_attr_init(&token_value_attrs[i].attr);
516-
token_value_attrs[i].attr.name = value_name;
517-
token_value_attrs[i].attr.mode = 0444;
518-
token_value_attrs[i].show = value_show;
519-
token_attrs[j++] = &token_value_attrs[i].attr;
497+
498+
sysfs_attr_init(&token_entries[i].value_attr.attr);
499+
token_entries[i].value_attr.attr.name = value_name;
500+
token_entries[i].value_attr.attr.mode = 0444;
501+
token_entries[i].value_attr.show = value_show;
502+
token_attrs[j++] = &token_entries[i].value_attr.attr;
520503
continue;
521504

522505
loop_fail_create_value:
@@ -532,14 +515,12 @@ static int build_tokens_sysfs(struct platform_device *dev)
532515

533516
out_unwind_strings:
534517
while (i--) {
535-
kfree(token_location_attrs[i].attr.name);
536-
kfree(token_value_attrs[i].attr.name);
518+
kfree(token_entries[i].location_attr.attr.name);
519+
kfree(token_entries[i].value_attr.attr.name);
537520
}
538521
kfree(token_attrs);
539522
out_allocate_attrs:
540-
kfree(token_value_attrs);
541-
out_allocate_value:
542-
kfree(token_location_attrs);
523+
kfree(token_entries);
543524

544525
return -ENOMEM;
545526
}
@@ -551,12 +532,11 @@ static void free_group(struct platform_device *pdev)
551532
sysfs_remove_group(&pdev->dev.kobj,
552533
&smbios_attribute_group);
553534
for (i = 0; i < da_num_tokens; i++) {
554-
kfree(token_location_attrs[i].attr.name);
555-
kfree(token_value_attrs[i].attr.name);
535+
kfree(token_entries[i].location_attr.attr.name);
536+
kfree(token_entries[i].value_attr.attr.name);
556537
}
557538
kfree(token_attrs);
558-
kfree(token_value_attrs);
559-
kfree(token_location_attrs);
539+
kfree(token_entries);
560540
}
561541

562542
static int __init dell_smbios_init(void)

0 commit comments

Comments
 (0)