Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nvmem: core: fix possibly memleak when use nvmem_cell_info_to_nvmem_cell()

Fix missing 'kfree_const(cell->name)' when call to
nvmem_cell_info_to_nvmem_cell() in several places:

* after nvmem_cell_info_to_nvmem_cell() failed during
nvmem_add_cells()

* during nvmem_device_cell_{read,write} when cell->name is
kstrdup'ed() without calling kfree_const() at the end, but
really there is no reason to do that 'dup, because the cell
instance is allocated on the stack for some short period to be
read/write without exposing it to the caller.

So the new nvmem_cell_info_to_nvmem_cell_nodup() helper is introduced
which is used to convert cell_info -> cell without name duplication as
a lighweight version of nvmem_cell_info_to_nvmem_cell().

Fixes: e2a5402ec7c6 ("nvmem: Add nvmem_device based consumer apis.")
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Acked-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu>
Link: https://lore.kernel.org/r/20200923204456.14032-1-vadym.kochan@plvision.eu
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Vadym Kochan and committed by
Greg Kroah-Hartman
fc9eec4d 709ec3f7

+24 -9
+24 -9
drivers/nvmem/core.c
··· 361 361 blocking_notifier_call_chain(&nvmem_notifier, NVMEM_CELL_ADD, cell); 362 362 } 363 363 364 - static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 365 - const struct nvmem_cell_info *info, 366 - struct nvmem_cell *cell) 364 + static int nvmem_cell_info_to_nvmem_cell_nodup(struct nvmem_device *nvmem, 365 + const struct nvmem_cell_info *info, 366 + struct nvmem_cell *cell) 367 367 { 368 368 cell->nvmem = nvmem; 369 369 cell->offset = info->offset; 370 370 cell->bytes = info->bytes; 371 - cell->name = kstrdup_const(info->name, GFP_KERNEL); 372 - if (!cell->name) 373 - return -ENOMEM; 371 + cell->name = info->name; 374 372 375 373 cell->bit_offset = info->bit_offset; 376 374 cell->nbits = info->nbits; ··· 380 382 if (!IS_ALIGNED(cell->offset, nvmem->stride)) { 381 383 dev_err(&nvmem->dev, 382 384 "cell %s unaligned to nvmem stride %d\n", 383 - cell->name, nvmem->stride); 385 + cell->name ?: "<unknown>", nvmem->stride); 384 386 return -EINVAL; 385 387 } 388 + 389 + return 0; 390 + } 391 + 392 + static int nvmem_cell_info_to_nvmem_cell(struct nvmem_device *nvmem, 393 + const struct nvmem_cell_info *info, 394 + struct nvmem_cell *cell) 395 + { 396 + int err; 397 + 398 + err = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, cell); 399 + if (err) 400 + return err; 401 + 402 + cell->name = kstrdup_const(info->name, GFP_KERNEL); 403 + if (!cell->name) 404 + return -ENOMEM; 386 405 387 406 return 0; 388 407 } ··· 1478 1463 if (!nvmem) 1479 1464 return -EINVAL; 1480 1465 1481 - rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1466 + rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); 1482 1467 if (rc) 1483 1468 return rc; 1484 1469 ··· 1508 1493 if (!nvmem) 1509 1494 return -EINVAL; 1510 1495 1511 - rc = nvmem_cell_info_to_nvmem_cell(nvmem, info, &cell); 1496 + rc = nvmem_cell_info_to_nvmem_cell_nodup(nvmem, info, &cell); 1512 1497 if (rc) 1513 1498 return rc; 1514 1499