Skip to content

Commit e57b929

Browse files
committed
Merge: at24: fix memory corruption race condition
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/4469 JIRA: https://issues.redhat.com/browse/RHEL-37020 CVE: CVE-2024-35848 If the eeprom is not accessible, an nvmem device will be registered, the read will fail, and the device will be torn down. If another driver accesses the nvmem device after the teardown, it will reference invalid memory. Signed-off-by: Mark Salter <msalter@redhat.com> Approved-by: Eric Chanudet <echanude@redhat.com> Approved-by: Andrew Halaney <ahalaney@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Scott Weaver <scweaver@redhat.com>
2 parents f18f10a + 36965a3 commit e57b929

File tree

1 file changed

+93
-58
lines changed

1 file changed

+93
-58
lines changed

drivers/misc/eeprom/at24.c

Lines changed: 93 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,6 @@
6868
* which won't work on pure SMBus systems.
6969
*/
7070

71-
struct at24_client {
72-
struct i2c_client *client;
73-
struct regmap *regmap;
74-
};
75-
7671
struct at24_data {
7772
/*
7873
* Lock protects against activities from other Linux tasks,
@@ -94,9 +89,10 @@ struct at24_data {
9489

9590
/*
9691
* Some chips tie up multiple I2C addresses; dummy devices reserve
97-
* them for us, and we'll use them with SMBus calls.
92+
* them for us.
9893
*/
99-
struct at24_client client[];
94+
u8 bank_addr_shift;
95+
struct regmap *client_regmaps[];
10096
};
10197

10298
/*
@@ -123,6 +119,7 @@ MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
123119
struct at24_chip_data {
124120
u32 byte_len;
125121
u8 flags;
122+
u8 bank_addr_shift;
126123
void (*read_post)(unsigned int off, char *buf, size_t count);
127124
};
128125

@@ -137,6 +134,12 @@ struct at24_chip_data {
137134
.read_post = _read_post, \
138135
}
139136

137+
#define AT24_CHIP_DATA_BS(_name, _len, _flags, _bank_addr_shift) \
138+
static const struct at24_chip_data _name = { \
139+
.byte_len = _len, .flags = _flags, \
140+
.bank_addr_shift = _bank_addr_shift \
141+
}
142+
140143
static void at24_read_post_vaio(unsigned int off, char *buf, size_t count)
141144
{
142145
int i;
@@ -197,6 +200,7 @@ AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16);
197200
AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16);
198201
AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16);
199202
AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16);
203+
AT24_CHIP_DATA_BS(at24_data_24c1025, 1048576 / 8, AT24_FLAG_ADDR16, 2);
200204
AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16);
201205
/* identical to 24c08 ? */
202206
AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
@@ -225,6 +229,7 @@ static const struct i2c_device_id at24_ids[] = {
225229
{ "24c256", (kernel_ulong_t)&at24_data_24c256 },
226230
{ "24c512", (kernel_ulong_t)&at24_data_24c512 },
227231
{ "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
232+
{ "24c1025", (kernel_ulong_t)&at24_data_24c1025 },
228233
{ "24c2048", (kernel_ulong_t)&at24_data_24c2048 },
229234
{ "at24", 0 },
230235
{ /* END OF LIST */ }
@@ -254,6 +259,7 @@ static const struct of_device_id at24_of_match[] = {
254259
{ .compatible = "atmel,24c256", .data = &at24_data_24c256 },
255260
{ .compatible = "atmel,24c512", .data = &at24_data_24c512 },
256261
{ .compatible = "atmel,24c1024", .data = &at24_data_24c1024 },
262+
{ .compatible = "atmel,24c1025", .data = &at24_data_24c1025 },
257263
{ .compatible = "atmel,24c2048", .data = &at24_data_24c2048 },
258264
{ /* END OF LIST */ },
259265
};
@@ -275,8 +281,8 @@ MODULE_DEVICE_TABLE(acpi, at24_acpi_ids);
275281
* set the byte address; on a multi-master board, another master
276282
* may have changed the chip's "current" address pointer.
277283
*/
278-
static struct at24_client *at24_translate_offset(struct at24_data *at24,
279-
unsigned int *offset)
284+
static struct regmap *at24_translate_offset(struct at24_data *at24,
285+
unsigned int *offset)
280286
{
281287
unsigned int i;
282288

@@ -288,12 +294,12 @@ static struct at24_client *at24_translate_offset(struct at24_data *at24,
288294
*offset &= 0xff;
289295
}
290296

291-
return &at24->client[i];
297+
return at24->client_regmaps[i];
292298
}
293299

294300
static struct device *at24_base_client_dev(struct at24_data *at24)
295301
{
296-
return &at24->client[0].client->dev;
302+
return regmap_get_device(at24->client_regmaps[0]);
297303
}
298304

299305
static size_t at24_adjust_read_count(struct at24_data *at24,
@@ -324,14 +330,10 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
324330
unsigned int offset, size_t count)
325331
{
326332
unsigned long timeout, read_time;
327-
struct at24_client *at24_client;
328-
struct i2c_client *client;
329333
struct regmap *regmap;
330334
int ret;
331335

332-
at24_client = at24_translate_offset(at24, &offset);
333-
regmap = at24_client->regmap;
334-
client = at24_client->client;
336+
regmap = at24_translate_offset(at24, &offset);
335337
count = at24_adjust_read_count(at24, offset, count);
336338

337339
/* adjust offset for mac and serial read ops */
@@ -346,7 +348,7 @@ static ssize_t at24_regmap_read(struct at24_data *at24, char *buf,
346348
read_time = jiffies;
347349

348350
ret = regmap_bulk_read(regmap, offset, buf, count);
349-
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n",
351+
dev_dbg(regmap_get_device(regmap), "read %zu@%d --> %d (%ld)\n",
350352
count, offset, ret, jiffies);
351353
if (!ret)
352354
return count;
@@ -387,14 +389,10 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
387389
unsigned int offset, size_t count)
388390
{
389391
unsigned long timeout, write_time;
390-
struct at24_client *at24_client;
391-
struct i2c_client *client;
392392
struct regmap *regmap;
393393
int ret;
394394

395-
at24_client = at24_translate_offset(at24, &offset);
396-
regmap = at24_client->regmap;
397-
client = at24_client->client;
395+
regmap = at24_translate_offset(at24, &offset);
398396
count = at24_adjust_write_count(at24, offset, count);
399397
timeout = jiffies + msecs_to_jiffies(at24_write_timeout);
400398

@@ -406,7 +404,7 @@ static ssize_t at24_regmap_write(struct at24_data *at24, const char *buf,
406404
write_time = jiffies;
407405

408406
ret = regmap_bulk_write(regmap, offset, buf, count);
409-
dev_dbg(&client->dev, "write %zu@%d --> %d (%ld)\n",
407+
dev_dbg(regmap_get_device(regmap), "write %zu@%d --> %d (%ld)\n",
410408
count, offset, ret, jiffies);
411409
if (!ret)
412410
return count;
@@ -538,26 +536,24 @@ static const struct at24_chip_data *at24_get_chip_data(struct device *dev)
538536
}
539537

540538
static int at24_make_dummy_client(struct at24_data *at24, unsigned int index,
539+
struct i2c_client *base_client,
541540
struct regmap_config *regmap_config)
542541
{
543-
struct i2c_client *base_client, *dummy_client;
542+
struct i2c_client *dummy_client;
544543
struct regmap *regmap;
545-
struct device *dev;
546-
547-
base_client = at24->client[0].client;
548-
dev = &base_client->dev;
549544

550-
dummy_client = devm_i2c_new_dummy_device(dev, base_client->adapter,
551-
base_client->addr + index);
545+
dummy_client = devm_i2c_new_dummy_device(&base_client->dev,
546+
base_client->adapter,
547+
base_client->addr +
548+
(index << at24->bank_addr_shift));
552549
if (IS_ERR(dummy_client))
553550
return PTR_ERR(dummy_client);
554551

555552
regmap = devm_regmap_init_i2c(dummy_client, regmap_config);
556553
if (IS_ERR(regmap))
557554
return PTR_ERR(regmap);
558555

559-
at24->client[index].client = dummy_client;
560-
at24->client[index].regmap = regmap;
556+
at24->client_regmaps[index] = regmap;
561557

562558
return 0;
563559
}
@@ -585,6 +581,31 @@ static unsigned int at24_get_offset_adj(u8 flags, unsigned int byte_len)
585581
}
586582
}
587583

584+
static void at24_probe_temp_sensor(struct i2c_client *client)
585+
{
586+
struct at24_data *at24 = i2c_get_clientdata(client);
587+
struct i2c_board_info info = { .type = "jc42" };
588+
int ret;
589+
u8 val;
590+
591+
/*
592+
* Byte 2 has value 11 for DDR3, earlier versions don't
593+
* support the thermal sensor present flag
594+
*/
595+
ret = at24_read(at24, 2, &val, 1);
596+
if (ret || val != 11)
597+
return;
598+
599+
/* Byte 32, bit 7 is set if temp sensor is present */
600+
ret = at24_read(at24, 32, &val, 1);
601+
if (ret || !(val & BIT(7)))
602+
return;
603+
604+
info.addr = 0x18 | (client->addr & 7);
605+
606+
i2c_new_client_device(client->adapter, &info);
607+
}
608+
588609
static int at24_probe(struct i2c_client *client)
589610
{
590611
struct regmap_config regmap_config = { };
@@ -595,6 +616,7 @@ static int at24_probe(struct i2c_client *client)
595616
bool i2c_fn_i2c, i2c_fn_block;
596617
unsigned int i, num_addresses;
597618
struct at24_data *at24;
619+
bool full_power;
598620
struct regmap *regmap;
599621
bool writable;
600622
u8 test_byte;
@@ -679,7 +701,7 @@ static int at24_probe(struct i2c_client *client)
679701
if (IS_ERR(regmap))
680702
return PTR_ERR(regmap);
681703

682-
at24 = devm_kzalloc(dev, struct_size(at24, client, num_addresses),
704+
at24 = devm_kzalloc(dev, struct_size(at24, client_regmaps, num_addresses),
683705
GFP_KERNEL);
684706
if (!at24)
685707
return -ENOMEM;
@@ -689,10 +711,10 @@ static int at24_probe(struct i2c_client *client)
689711
at24->page_size = page_size;
690712
at24->flags = flags;
691713
at24->read_post = cdata->read_post;
714+
at24->bank_addr_shift = cdata->bank_addr_shift;
692715
at24->num_addresses = num_addresses;
693716
at24->offset_adj = at24_get_offset_adj(flags, byte_len);
694-
at24->client[0].client = client;
695-
at24->client[0].regmap = regmap;
717+
at24->client_regmaps[0] = regmap;
696718

697719
at24->vcc_reg = devm_regulator_get(dev, "vcc");
698720
if (IS_ERR(at24->vcc_reg))
@@ -708,7 +730,7 @@ static int at24_probe(struct i2c_client *client)
708730

709731
/* use dummy devices for multiple-address chips */
710732
for (i = 1; i < num_addresses; i++) {
711-
err = at24_make_dummy_client(at24, i, &regmap_config);
733+
err = at24_make_dummy_client(at24, i, client, &regmap_config);
712734
if (err)
713735
return err;
714736
}
@@ -747,35 +769,45 @@ static int at24_probe(struct i2c_client *client)
747769

748770
i2c_set_clientdata(client, at24);
749771

750-
err = regulator_enable(at24->vcc_reg);
751-
if (err) {
752-
dev_err(dev, "Failed to enable vcc regulator\n");
753-
return err;
754-
}
772+
full_power = acpi_dev_state_d0(&client->dev);
773+
if (full_power) {
774+
err = regulator_enable(at24->vcc_reg);
775+
if (err) {
776+
dev_err(dev, "Failed to enable vcc regulator\n");
777+
return err;
778+
}
755779

756-
/* enable runtime pm */
757-
pm_runtime_set_active(dev);
780+
pm_runtime_set_active(dev);
781+
}
758782
pm_runtime_enable(dev);
759783

784+
/*
785+
* Perform a one-byte test read to verify that the chip is functional,
786+
* unless powering on the device is to be avoided during probe (i.e.
787+
* it's powered off right now).
788+
*/
789+
if (full_power) {
790+
err = at24_read(at24, 0, &test_byte, 1);
791+
if (err) {
792+
pm_runtime_disable(dev);
793+
if (!pm_runtime_status_suspended(dev))
794+
regulator_disable(at24->vcc_reg);
795+
return -ENODEV;
796+
}
797+
}
798+
760799
at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
761800
if (IS_ERR(at24->nvmem)) {
762801
pm_runtime_disable(dev);
763802
if (!pm_runtime_status_suspended(dev))
764803
regulator_disable(at24->vcc_reg);
765-
return PTR_ERR(at24->nvmem);
804+
return dev_err_probe(dev, PTR_ERR(at24->nvmem),
805+
"failed to register nvmem\n");
766806
}
767807

768-
/*
769-
* Perform a one-byte test read to verify that the
770-
* chip is functional.
771-
*/
772-
err = at24_read(at24, 0, &test_byte, 1);
773-
if (err) {
774-
pm_runtime_disable(dev);
775-
if (!pm_runtime_status_suspended(dev))
776-
regulator_disable(at24->vcc_reg);
777-
return -ENODEV;
778-
}
808+
/* If this a SPD EEPROM, probe for DDR3 thermal sensor */
809+
if (cdata == &at24_data_spd)
810+
at24_probe_temp_sensor(client);
779811

780812
pm_runtime_idle(dev);
781813

@@ -794,9 +826,11 @@ static int at24_remove(struct i2c_client *client)
794826
struct at24_data *at24 = i2c_get_clientdata(client);
795827

796828
pm_runtime_disable(&client->dev);
797-
if (!pm_runtime_status_suspended(&client->dev))
798-
regulator_disable(at24->vcc_reg);
799-
pm_runtime_set_suspended(&client->dev);
829+
if (acpi_dev_state_d0(&client->dev)) {
830+
if (!pm_runtime_status_suspended(&client->dev))
831+
regulator_disable(at24->vcc_reg);
832+
pm_runtime_set_suspended(&client->dev);
833+
}
800834

801835
return 0;
802836
}
@@ -833,6 +867,7 @@ static struct i2c_driver at24_driver = {
833867
.probe_new = at24_probe,
834868
.remove = at24_remove,
835869
.id_table = at24_ids,
870+
.flags = I2C_DRV_ACPI_WAIVE_D0_PROBE,
836871
};
837872

838873
static int __init at24_init(void)

0 commit comments

Comments
 (0)