qcacmn: Add QDF API for ID allocation

In P2P ROC and MGMT tx cases, it use kernel address as cookie and
provides to userspace. Which has security risk. Add QDF API for ID
allocation and map ID to pointer, provides ID to userspace instead
of kernel address.

Change-Id: I4e10109988391474722df5b251fab11a87c7992b
CRs-Fixed: 2237756
This commit is contained in:
Wu Gao
2018-05-04 18:57:54 +08:00
committed by nshrivas
parent 51198fc4ee
commit 210778359a
3 changed files with 266 additions and 0 deletions

142
qdf/linux/src/qdf_idr.c Normal file
View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: qdf_idr
* This file provides the ability to map an ID to a pointer
*/
/* Include files */
#include <qdf_idr.h>
#include <qdf_module.h>
#define QDF_IDR_START 0x100
#define QDF_IDR_END 0
static int qdf_idr_gpf_flag(void)
{
if (in_interrupt() || irqs_disabled() || in_atomic())
return GFP_ATOMIC;
return GFP_KERNEL;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
/**
* __qdf_idr_alloc() - Allocates an unused ID
* @idp: pointer to qdf idr
* @ptr: pointer to be associated with the new ID
* @start: the minimum ID
* @end: the maximum ID
*
* Return: new ID
*/
static inline int32_t
__qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t start, int32_t end)
{
int32_t id = 0;
idr_get_new(&idp->idr, ptr, &id);
return id;
}
#else
static inline int32_t
__qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t start, int32_t end)
{
return idr_alloc(&idp->idr, ptr, start, end, qdf_idr_gpf_flag());
}
#endif
QDF_STATUS qdf_idr_create(qdf_idr *idp)
{
if (!idp)
return QDF_STATUS_E_INVAL;
qdf_spinlock_create(&idp->lock);
idr_init(&idp->idr);
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(qdf_idr_create);
QDF_STATUS qdf_idr_destroy(qdf_idr *idp)
{
if (!idp)
return QDF_STATUS_E_INVAL;
qdf_spinlock_destroy(&idp->lock);
idr_destroy(&idp->idr);
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(qdf_idr_destroy);
QDF_STATUS qdf_idr_alloc(qdf_idr *idp, void *ptr, int32_t *id)
{
int local_id;
if (!idp || !ptr)
return QDF_STATUS_E_INVAL;
qdf_spinlock_acquire(&idp->lock);
local_id = __qdf_idr_alloc(idp, ptr, QDF_IDR_START, QDF_IDR_END);
qdf_spinlock_release(&idp->lock);
if (local_id < QDF_IDR_START)
return QDF_STATUS_E_FAILURE;
*id = local_id;
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(qdf_idr_alloc);
QDF_STATUS qdf_idr_remove(qdf_idr *idp, int32_t id)
{
if (!idp || id < QDF_IDR_START)
return QDF_STATUS_E_INVAL;
qdf_spinlock_acquire(&idp->lock);
idr_remove(&idp->idr, id);
qdf_spinlock_release(&idp->lock);
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(qdf_idr_remove);
QDF_STATUS qdf_idr_find(qdf_idr *idp, int32_t id, void **ptr)
{
if (!ptr || (id < QDF_IDR_START))
return QDF_STATUS_E_INVAL;
qdf_spinlock_acquire(&idp->lock);
*ptr = idr_find(&idp->idr, id);
qdf_spinlock_release(&idp->lock);
if (!ptr)
return QDF_STATUS_E_INVAL;
else
return QDF_STATUS_SUCCESS;
}
qdf_export_symbol(qdf_idr_find);