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

staging: zsmalloc: Ensure handle is never 0 on success

zsmalloc encodes a handle using the pfn and an object
index. On hardware platforms with physical memory starting
at 0x0 the pfn can be 0. This causes the encoded handle to be
0 and is incorrectly interpreted as an allocation failure.

This issue affects all current and future SoCs with physical
memory starting at 0x0. All MSM8974 SoCs which includes
Google Nexus 5 devices are affected.

To prevent this false error we ensure that the encoded handle
will not be 0 when allocation succeeds.

Signed-off-by: Olav Haugan <ohaugan@codeaurora.org>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Olav Haugan and committed by
Greg Kroah-Hartman
67296874 b39f15c9

+13 -4
+13 -4
drivers/staging/zsmalloc/zsmalloc-main.c
··· 430 430 return next; 431 431 } 432 432 433 - /* Encode <page, obj_idx> as a single handle value */ 433 + /* 434 + * Encode <page, obj_idx> as a single handle value. 435 + * On hardware platforms with physical memory starting at 0x0 the pfn 436 + * could be 0 so we ensure that the handle will never be 0 by adjusting the 437 + * encoded obj_idx value before encoding. 438 + */ 434 439 static void *obj_location_to_handle(struct page *page, unsigned long obj_idx) 435 440 { 436 441 unsigned long handle; ··· 446 441 } 447 442 448 443 handle = page_to_pfn(page) << OBJ_INDEX_BITS; 449 - handle |= (obj_idx & OBJ_INDEX_MASK); 444 + handle |= ((obj_idx + 1) & OBJ_INDEX_MASK); 450 445 451 446 return (void *)handle; 452 447 } 453 448 454 - /* Decode <page, obj_idx> pair from the given object handle */ 449 + /* 450 + * Decode <page, obj_idx> pair from the given object handle. We adjust the 451 + * decoded obj_idx back to its original value since it was adjusted in 452 + * obj_location_to_handle(). 453 + */ 455 454 static void obj_handle_to_location(unsigned long handle, struct page **page, 456 455 unsigned long *obj_idx) 457 456 { 458 457 *page = pfn_to_page(handle >> OBJ_INDEX_BITS); 459 - *obj_idx = handle & OBJ_INDEX_MASK; 458 + *obj_idx = (handle & OBJ_INDEX_MASK) - 1; 460 459 } 461 460 462 461 static unsigned long obj_idx_to_offset(struct page *page,