qcacmn: Use panic in qdf_mem_copy/move/set/zero/cmp()

It has been observed at that several issues have crept into mainline due
to qdf_mem_copy() gracefully returning when the source or destination
pointers are NULL. In order to prevent such regressions in the future,
change calls to qdf_mem_copy/move/set/zero/cmp() with NULL pointer
parameters so they panic in debug builds.

Change-Id: I6df4c42245ed1d0d8a85477f59552f8243488924
CRs-Fixed: 2408266
This commit is contained in:
Dustin Brown
2019-03-01 15:08:21 -08:00
committed by nshrivas
parent 510a27c966
commit c9681754d0
3 changed files with 93 additions and 129 deletions

View File

@@ -318,41 +318,87 @@ void qdf_mem_set_io(void *ptr, uint32_t num_bytes, uint32_t value);
void qdf_mem_copy_toio(void *dst_addr, const void *src_addr, void qdf_mem_copy_toio(void *dst_addr, const void *src_addr,
uint32_t num_bytes); uint32_t num_bytes);
/**
* qdf_mem_set() - set (fill) memory with a specified byte value.
* @ptr: Pointer to memory that will be set
* @num_bytes: Number of bytes to be set
* @value: Byte set in memory
*
* WARNING: parameter @num_bytes and @value are swapped comparing with
* standard C function "memset", please ensure correct usage of this function!
*
* Return: None
*/
void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value); void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value);
void qdf_mem_zero(void *ptr, uint32_t num_bytes); /**
* qdf_mem_zero() - zero out memory
* @ptr: pointer to memory that will be set to zero
* @num_bytes: number of bytes zero
*
* This function sets the memory location to all zeros, essentially clearing
* the memory.
*
* Return: None
*/
static inline void qdf_mem_zero(void *ptr, uint32_t num_bytes)
{
qdf_mem_set(ptr, num_bytes, 0);
}
/**
* qdf_mem_copy() - copy memory
* @dst_addr: Pointer to destination memory location (to copy to)
* @src_addr: Pointer to source memory location (to copy from)
* @num_bytes: Number of bytes to copy.
*
* Copy host memory from one location to another, similar to memcpy in
* standard C. Note this function does not specifically handle overlapping
* source and destination memory locations. Calling this function with
* overlapping source and destination memory locations will result in
* unpredictable results. Use qdf_mem_move() if the memory locations
* for the source and destination are overlapping (or could be overlapping!)
*
* Return: none
*/
void qdf_mem_copy(void *dst_addr, const void *src_addr, uint32_t num_bytes); void qdf_mem_copy(void *dst_addr, const void *src_addr, uint32_t num_bytes);
/**
* qdf_mem_move() - move memory
* @dst_addr: pointer to destination memory location (to move to)
* @src_addr: pointer to source memory location (to move from)
* @num_bytes: number of bytes to move.
*
* Move host memory from one location to another, similar to memmove in
* standard C. Note this function *does* handle overlapping
* source and destination memory locations.
* Return: None
*/
void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes); void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes);
/**
* qdf_mem_cmp() - memory compare
* @left: pointer to one location in memory to compare
* @right: pointer to second location in memory to compare
* @size: the number of bytes to compare
*
* Function to compare two pieces of memory, similar to memcmp function
* in standard C.
*
* Return:
* 0 -- equal
* < 0 -- *memory1 is less than *memory2
* > 0 -- *memory1 is bigger than *memory2
*/
int qdf_mem_cmp(const void *left, const void *right, size_t size);
void qdf_mem_free_outline(void *buf); void qdf_mem_free_outline(void *buf);
void qdf_mem_zero_outline(void *buf, qdf_size_t size); void qdf_mem_zero_outline(void *buf, qdf_size_t size);
void qdf_ether_addr_copy(void *dst_addr, const void *src_addr); void qdf_ether_addr_copy(void *dst_addr, const void *src_addr);
/**
* qdf_mem_cmp() - memory compare
* @memory1: pointer to one location in memory to compare.
* @memory2: pointer to second location in memory to compare.
* @num_bytes: the number of bytes to compare.
*
* Function to compare two pieces of memory, similar to memcmp function
* in standard C.
* Return:
* int32_t - returns an int value that tells if the memory
* locations are equal or not equal.
* 0 -- equal
* < 0 -- *memory1 is less than *memory2
* > 0 -- *memory1 is bigger than *memory2
*/
static inline int32_t qdf_mem_cmp(const void *memory1, const void *memory2,
uint32_t num_bytes)
{
return __qdf_mem_cmp(memory1, memory2, num_bytes);
}
/** /**
* qdf_mem_map_nbytes_single - Map memory for DMA * qdf_mem_map_nbytes_single - Map memory for DMA
* @osdev: pomter OS device context * @osdev: pomter OS device context

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014-2018 The Linux Foundation. All rights reserved. * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for * Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the * any purpose with or without fee is hereby granted, provided that the
@@ -180,27 +180,6 @@ void __qdf_mempool_free(qdf_device_t osdev, __qdf_mempool_t pool, void *buf);
#define __qdf_mempool_elem_size(_pool) ((_pool)->elem_size) #define __qdf_mempool_elem_size(_pool) ((_pool)->elem_size)
#endif #endif
/**
* __qdf_mem_cmp() - memory compare
* @memory1: pointer to one location in memory to compare.
* @memory2: pointer to second location in memory to compare.
* @num_bytes: the number of bytes to compare.
*
* Function to compare two pieces of memory, similar to memcmp function
* in standard C.
* Return:
* int32_t - returns an int value that tells if the memory
* locations are equal or not equal.
* 0 -- equal
* < 0 -- *memory1 is less than *memory2
* > 0 -- *memory1 is bigger than *memory2
*/
static inline int32_t __qdf_mem_cmp(const void *memory1, const void *memory2,
uint32_t num_bytes)
{
return (int32_t) memcmp(memory1, memory2, num_bytes);
}
/** /**
* __qdf_mem_smmu_s1_enabled() - Return SMMU stage 1 translation enable status * __qdf_mem_smmu_s1_enabled() - Return SMMU stage 1 translation enable status
* @osdev parent device instance * @osdev parent device instance

View File

@@ -1423,35 +1423,17 @@ int qdf_mem_multi_page_link(qdf_device_t osdev,
} }
qdf_export_symbol(qdf_mem_multi_page_link); qdf_export_symbol(qdf_mem_multi_page_link);
/**
* qdf_mem_copy() - copy memory
* @dst_addr: Pointer to destination memory location (to copy to)
* @src_addr: Pointer to source memory location (to copy from)
* @num_bytes: Number of bytes to copy.
*
* Copy host memory from one location to another, similar to memcpy in
* standard C. Note this function does not specifically handle overlapping
* source and destination memory locations. Calling this function with
* overlapping source and destination memory locations will result in
* unpredictable results. Use qdf_mem_move() if the memory locations
* for the source and destination are overlapping (or could be overlapping!)
*
* Return: none
*/
void qdf_mem_copy(void *dst_addr, const void *src_addr, uint32_t num_bytes) void qdf_mem_copy(void *dst_addr, const void *src_addr, uint32_t num_bytes)
{ {
if (0 == num_bytes) { /* special case where dst_addr or src_addr can be NULL */
/* special case where dst_addr or src_addr can be NULL */ if (!num_bytes)
return; return;
}
if ((dst_addr == NULL) || (src_addr == NULL)) { QDF_BUG(dst_addr);
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, QDF_BUG(src_addr);
"%s called with NULL parameter, source:%pK destination:%pK", if (!dst_addr || !src_addr)
__func__, src_addr, dst_addr);
QDF_ASSERT(0);
return; return;
}
memcpy(dst_addr, src_addr, num_bytes); memcpy(dst_addr, src_addr, num_bytes);
} }
qdf_export_symbol(qdf_mem_copy); qdf_export_symbol(qdf_mem_copy);
@@ -1504,32 +1486,6 @@ qdf_shared_mem_t *qdf_mem_shared_mem_alloc(qdf_device_t osdev, uint32_t size)
qdf_export_symbol(qdf_mem_shared_mem_alloc); qdf_export_symbol(qdf_mem_shared_mem_alloc);
/**
* qdf_mem_zero() - zero out memory
* @ptr: pointer to memory that will be set to zero
* @num_bytes: number of bytes zero
*
* This function sets the memory location to all zeros, essentially clearing
* the memory.
*
* Return: None
*/
void qdf_mem_zero(void *ptr, uint32_t num_bytes)
{
if (0 == num_bytes) {
/* special case where ptr can be NULL */
return;
}
if (ptr == NULL) {
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR,
"%s called with NULL parameter ptr", __func__);
return;
}
memset(ptr, 0, num_bytes);
}
qdf_export_symbol(qdf_mem_zero);
/** /**
* qdf_mem_copy_toio() - copy memory * qdf_mem_copy_toio() - copy memory
* @dst_addr: Pointer to destination memory location (to copy to) * @dst_addr: Pointer to destination memory location (to copy to)
@@ -1576,57 +1532,40 @@ void qdf_mem_set_io(void *ptr, uint32_t num_bytes, uint32_t value)
qdf_export_symbol(qdf_mem_set_io); qdf_export_symbol(qdf_mem_set_io);
/**
* qdf_mem_set() - set (fill) memory with a specified byte value.
* @ptr: Pointer to memory that will be set
* @num_bytes: Number of bytes to be set
* @value: Byte set in memory
*
* WARNING: parameter @num_bytes and @value are swapped comparing with
* standard C function "memset", please ensure correct usage of this function!
*
* Return: None
*/
void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value) void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value)
{ {
if (ptr == NULL) { QDF_BUG(ptr);
qdf_print("%s called with NULL parameter ptr", __func__); if (!ptr)
return; return;
}
memset(ptr, value, num_bytes); memset(ptr, value, num_bytes);
} }
qdf_export_symbol(qdf_mem_set); qdf_export_symbol(qdf_mem_set);
/**
* qdf_mem_move() - move memory
* @dst_addr: pointer to destination memory location (to move to)
* @src_addr: pointer to source memory location (to move from)
* @num_bytes: number of bytes to move.
*
* Move host memory from one location to another, similar to memmove in
* standard C. Note this function *does* handle overlapping
* source and destination memory locations.
* Return: None
*/
void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes) void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes)
{ {
if (0 == num_bytes) { /* special case where dst_addr or src_addr can be NULL */
/* special case where dst_addr or src_addr can be NULL */ if (!num_bytes)
return; return;
}
if ((dst_addr == NULL) || (src_addr == NULL)) { QDF_BUG(dst_addr);
QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, QDF_BUG(src_addr);
"%s called with NULL parameter, source:%pK destination:%pK", if (!dst_addr || !src_addr)
__func__, src_addr, dst_addr);
QDF_ASSERT(0);
return; return;
}
memmove(dst_addr, src_addr, num_bytes); memmove(dst_addr, src_addr, num_bytes);
} }
qdf_export_symbol(qdf_mem_move); qdf_export_symbol(qdf_mem_move);
int qdf_mem_cmp(const void *left, const void *right, size_t size)
{
QDF_BUG(left);
QDF_BUG(right);
return memcmp(left, right, size);
}
qdf_export_symbol(qdf_mem_cmp);
#if defined(A_SIMOS_DEVHOST) || defined(HIF_SDIO) || defined(HIF_USB) #if defined(A_SIMOS_DEVHOST) || defined(HIF_SDIO) || defined(HIF_USB)
/** /**
* qdf_mem_dma_alloc() - allocates memory for dma * qdf_mem_dma_alloc() - allocates memory for dma