Skip to content

Commit f52e98d

Browse files
jwrdegoedeij-intel
authored andcommitted
platform/x86: panasonic-laptop: Fix SINF array out of bounds accesses
The panasonic laptop code in various places uses the SINF array with index values of 0 - SINF_CUR_BRIGHT(0x0d) without checking that the SINF array is big enough. Not all panasonic laptops have this many SINF array entries, for example the Toughbook CF-18 model only has 10 SINF array entries. So it only supports the AC+DC brightness entries and mute. Check that the SINF array has a minimum size which covers all AC+DC brightness entries and refuse to load if the SINF array is smaller. For higher SINF indexes hide the sysfs attributes when the SINF array does not contain an entry for that attribute, avoiding show()/store() accessing the array out of bounds and add bounds checking to the probe() and resume() code accessing these. Fixes: e424fb8 ("panasonic-laptop: avoid overflow in acpi_pcc_hotkey_add()") Cc: [email protected] Signed-off-by: Hans de Goede <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Ilpo Järvinen <[email protected]> Signed-off-by: Ilpo Järvinen <[email protected]>
1 parent d34af75 commit f52e98d

File tree

1 file changed

+39
-10
lines changed

1 file changed

+39
-10
lines changed

drivers/platform/x86/panasonic-laptop.c

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,24 @@ static DEVICE_ATTR_RW(dc_brightness);
773773
static DEVICE_ATTR_RW(current_brightness);
774774
static DEVICE_ATTR_RW(cdpower);
775775

776+
static umode_t pcc_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
777+
{
778+
struct device *dev = kobj_to_dev(kobj);
779+
struct acpi_device *acpi = to_acpi_device(dev);
780+
struct pcc_acpi *pcc = acpi_driver_data(acpi);
781+
782+
if (attr == &dev_attr_mute.attr)
783+
return (pcc->num_sifr > SINF_MUTE) ? attr->mode : 0;
784+
785+
if (attr == &dev_attr_eco_mode.attr)
786+
return (pcc->num_sifr > SINF_ECO_MODE) ? attr->mode : 0;
787+
788+
if (attr == &dev_attr_current_brightness.attr)
789+
return (pcc->num_sifr > SINF_CUR_BRIGHT) ? attr->mode : 0;
790+
791+
return attr->mode;
792+
}
793+
776794
static struct attribute *pcc_sysfs_entries[] = {
777795
&dev_attr_numbatt.attr,
778796
&dev_attr_lcdtype.attr,
@@ -787,8 +805,9 @@ static struct attribute *pcc_sysfs_entries[] = {
787805
};
788806

789807
static const struct attribute_group pcc_attr_group = {
790-
.name = NULL, /* put in device directory */
791-
.attrs = pcc_sysfs_entries,
808+
.name = NULL, /* put in device directory */
809+
.attrs = pcc_sysfs_entries,
810+
.is_visible = pcc_sysfs_is_visible,
792811
};
793812

794813

@@ -941,12 +960,15 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
941960
if (!pcc)
942961
return -EINVAL;
943962

944-
acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
945-
acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode);
963+
if (pcc->num_sifr > SINF_MUTE)
964+
acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
965+
if (pcc->num_sifr > SINF_ECO_MODE)
966+
acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode);
946967
acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_key);
947968
acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, pcc->ac_brightness);
948969
acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, pcc->dc_brightness);
949-
acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness);
970+
if (pcc->num_sifr > SINF_CUR_BRIGHT)
971+
acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness);
950972

951973
return 0;
952974
}
@@ -963,8 +985,12 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
963985

964986
num_sifr = acpi_pcc_get_sqty(device);
965987

966-
if (num_sifr < 0 || num_sifr > 255) {
967-
pr_err("num_sifr out of range");
988+
/*
989+
* pcc->sinf is expected to at least have the AC+DC brightness entries.
990+
* Accesses to higher SINF entries are checked against num_sifr.
991+
*/
992+
if (num_sifr <= SINF_DC_CUR_BRIGHT || num_sifr > 255) {
993+
pr_err("num_sifr %d out of range %d - 255\n", num_sifr, SINF_DC_CUR_BRIGHT + 1);
968994
return -ENODEV;
969995
}
970996

@@ -1020,11 +1046,14 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device)
10201046
acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0);
10211047
pcc->sticky_key = 0;
10221048

1023-
pcc->eco_mode = pcc->sinf[SINF_ECO_MODE];
1024-
pcc->mute = pcc->sinf[SINF_MUTE];
10251049
pcc->ac_brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
10261050
pcc->dc_brightness = pcc->sinf[SINF_DC_CUR_BRIGHT];
1027-
pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT];
1051+
if (pcc->num_sifr > SINF_MUTE)
1052+
pcc->mute = pcc->sinf[SINF_MUTE];
1053+
if (pcc->num_sifr > SINF_ECO_MODE)
1054+
pcc->eco_mode = pcc->sinf[SINF_ECO_MODE];
1055+
if (pcc->num_sifr > SINF_CUR_BRIGHT)
1056+
pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT];
10281057

10291058
/* add sysfs attributes */
10301059
result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);

0 commit comments

Comments
 (0)