nvscic2c-pcie: Add Buffer limts per endpoint

Address security ARR: DOS60-REQ-7169 in streaming mode.
Add per endpoint streaming mode buffer limits.

Bug 4883175
JIRA NVIPC-2453

Change-Id: I31edb2bacf4a8af560e7e6da7d378da874d105bd
Signed-off-by: Janardhan Reddy <jreddya@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3196300
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Janardhan Reddy
2024-08-19 11:00:14 +00:00
committed by Jon Hunter
parent 6c9bba8912
commit cfaad9cd6d
7 changed files with 188 additions and 14 deletions

View File

@@ -1,5 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*/
#define pr_fmt(fmt) "nvscic2c-pcie: dt: " fmt
@@ -59,8 +62,8 @@ dt_print(struct driver_param_t *drv_param)
prop = &drv_param->endpoint_props[i];
pr_debug("\t\t(%s)::\n", prop->name);
pr_debug("\t\t\tnframes = (%02u) frame_size=(%08u)",
prop->nframes, prop->frame_sz);
pr_debug("\t\t\tnframes = (%02u) frame_size=(%08u) buff limit=(%lld)",
prop->nframes, prop->frame_sz, prop->aperture_limit);
}
pr_debug("dt parsing ends\n");
}
@@ -114,6 +117,31 @@ tokenize_u8(char **input, const char *delim,
return ret;
}
/*
* helper function to tokenize the string with caller provided
* delimiter and provide the sting->u64 value.
*
* @param input is an in,out parameter.
*
*/
static int
tokenize_u64(char **input, const char *delim,
u32 base, u64 *value)
{
int ret = 0;
char *token = NULL;
/* skipping args check - internal api.*/
token = tokenize(input, delim);
if (!token)
ret = -ENODATA;
else
ret = kstrtou64(token, base, value);
return ret;
}
/*
* helper function to tokenize the string with caller provided
* delimiter and provide the sting->u32 value.
@@ -550,6 +578,13 @@ parse_endpoint_db(struct driver_param_t *drv_param)
break;
}
/* parse streaming mode per endpoint PCIe aperture mapping limit */
ret = tokenize_u64(&inp, ",", base, &ep_prop->aperture_limit);
if (ret) {
pr_err("Error parsing token aperture_limit\n");
break;
}
/* validate some basic properties of endpoint.*/
ret = validate_endpoint_prop(ep_prop);
if (ret) {

View File

@@ -1,5 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*/
#define pr_fmt(fmt) "nvscic2c-pcie: endpoint: " fmt
@@ -1113,6 +1116,7 @@ endpoints_setup(struct driver_ctx_t *drv_ctx, void **endpoints_h)
stream_ext_params->ep_id = ep_prop->id;
stream_ext_params->ep_name = endpoint->name;
stream_ext_params->drv_mode = drv_ctx->drv_mode;
stream_ext_params->aperture_limit = ep_prop->aperture_limit;
/* create nvscic2c-pcie endpoint device.*/
ret = create_endpoint_device(eps_ctx, endpoint);

View File

@@ -74,6 +74,8 @@ struct driver_param_t {
/* Frames and per frame size.*/
u8 nframes;
u32 frame_sz;
/* Streaming mode per endpoint PCIe aperture mapping limit */
uint64_t aperture_limit;
} endpoint_props[MAX_ENDPOINTS];
};

View File

@@ -180,6 +180,10 @@ struct stream_ext_ctx_t {
u32 ep_id;
char ep_name[NAME_MAX];
/* Streaming mode per endpoint PCIe aperture mapping limit */
uint64_t aperture_limit;
/* Streaming mode per endpoint PCIe aperture mapping usage */
uint64_t aperture_inuse;
struct node_info_t local_node;
struct node_info_t peer_node;
@@ -640,6 +644,11 @@ ioctl_set_max_copy_requests(struct stream_ext_ctx_t *ctx,
struct copy_request *cr = NULL;
struct list_head *curr = NULL, *next = NULL;
if (ctx->aperture_limit == 0) {
pr_err("Err: Streaming is not supported in this Endpoint: %s\n", ctx->ep_name);
return -EINVAL;
}
if (WARN_ON(!args->max_copy_requests ||
!args->max_flush_ranges ||
!args->max_post_fences))
@@ -762,6 +771,8 @@ stream_extension_init(struct stream_ext_params *params, void **stream_ext_h)
ctx->vmap_h = params->vmap_h;
ctx->pci_client_h = params->pci_client_h;
ctx->comm_channel_h = params->comm_channel_h;
ctx->aperture_limit = params->aperture_limit;
ctx->aperture_inuse = 0UL;
strscpy(ctx->ep_name, params->ep_name, NAME_MAX);
memcpy(&ctx->local_node, params->local_node, sizeof(ctx->local_node));
memcpy(&ctx->peer_node, params->peer_node, sizeof(ctx->peer_node));
@@ -895,7 +906,11 @@ allocate_handle(struct stream_ext_ctx_t *ctx, enum nvscic2c_pcie_obj_type type,
pr_err("Incorrect NVSCIC2C_IOCTL_MAP params\n");
return -EINVAL;
}
ret = vmap_obj_map(ctx->vmap_h, &vmap_params, &vmap_attrib);
ret = vmap_obj_map(ctx->vmap_h,
&vmap_params,
&vmap_attrib,
ctx->aperture_limit,
&ctx->aperture_inuse);
if (ret) {
if (ret == -EAGAIN)
pr_info("Failed to map obj of type: (%d)\n", type);

View File

@@ -1,5 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*/
/*
* Internal to gos-nvscic2c module. This file is not supposed to be included
@@ -21,6 +24,8 @@ struct stream_ext_params {
struct node_info_t *peer_node;
u32 ep_id;
char *ep_name;
/* Streaming mode per endpoint PCIe aperture mapping limit */
uint64_t aperture_limit;
struct platform_device *host1x_pdev;
enum drv_mode_t drv_mode;
void *pci_client_h;

View File

@@ -1,5 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*/
#define pr_fmt(fmt) "nvscic2c-pcie: vmap: " fmt
@@ -42,13 +45,76 @@ match_dmabuf(int id, void *entry, void *data)
return 0;
}
static int dev_map_limit_check(uint64_t aperture_limit, uint64_t aperture_inuse, size_t map_size)
{
int ret = 0;
if ((aperture_inuse + map_size) > aperture_limit) {
ret = -ENOMEM;
pr_err("per endpoint mapping limit exceeded, aperture_inuse: %lld, map_size: %zu\n",
aperture_inuse, map_size);
return ret;
}
return ret;
}
static void
dma_mem_get_size_exit(struct memobj_pin_t *pin)
{
if (!(IS_ERR_OR_NULL(pin->sgt))) {
dma_buf_unmap_attachment(pin->attach, pin->sgt, pin->dir);
pin->sgt = NULL;
}
if (!(IS_ERR_OR_NULL(pin->attach))) {
dma_buf_detach(pin->dmabuf, pin->attach);
pin->attach = NULL;
}
}
static int dma_mem_get_size(struct vmap_ctx_t *vmap_ctx, struct memobj_pin_t *pin, size_t *map_size)
{
int ret = 0;
u32 sg_index = 0;
struct scatterlist *sg = NULL;
/*
* pin to dummy device (which has smmu disabled) to get scatter-list
* of phys addr.
*/
pin->attach = dma_buf_attach(pin->dmabuf, &vmap_ctx->dummy_pdev->dev);
if (IS_ERR_OR_NULL(pin->attach)) {
ret = PTR_ERR(pin->attach);
pr_err("client_mngd dma_buf_attach failed\n");
goto fn_exit;
}
pin->sgt = dma_buf_map_attachment(pin->attach, pin->dir);
if (IS_ERR_OR_NULL(pin->sgt)) {
ret = PTR_ERR(pin->sgt);
pr_err("client_mngd dma_buf_attachment failed\n");
goto fn_exit;
}
*map_size = 0;
for_each_sg(pin->sgt->sgl, sg, pin->sgt->nents, sg_index)
*map_size += sg->length;
fn_exit:
dma_mem_get_size_exit(pin);
return ret;
}
static int
memobj_map(struct vmap_ctx_t *vmap_ctx,
struct vmap_memobj_map_params *params,
struct vmap_obj_attributes *attrib)
struct vmap_obj_attributes *attrib,
uint64_t aperture_limit,
uint64_t *const aperture_inuse)
{
int ret = 0;
s32 id_exist = 0;
size_t map_size = 0;
struct memobj_map_ref *map = NULL;
struct dma_buf *dmabuf = NULL;
@@ -105,6 +171,23 @@ memobj_map(struct vmap_ctx_t *vmap_ctx,
goto err;
}
if ((map->pin.mngd == VMAP_MNGD_CLIENT) && (aperture_inuse != NULL)) {
ret = dma_mem_get_size(vmap_ctx, &map->pin, &map_size);
if (ret != 0) {
pr_err("Failed in dma buf mem get size\n");
idr_remove(&vmap_ctx->mem_idr, map->obj_id);
kfree(map);
goto err;
}
ret = dev_map_limit_check(aperture_limit, *aperture_inuse, map_size);
if (ret != 0) {
pr_err("Failed in aperture limit check\n");
idr_remove(&vmap_ctx->mem_idr, map->obj_id);
kfree(map);
goto err;
}
}
/* populates map->pin.attrib within.*/
ret = memobj_pin(vmap_ctx, &map->pin);
if (ret) {
@@ -113,6 +196,8 @@ memobj_map(struct vmap_ctx_t *vmap_ctx,
kfree(map);
goto err;
}
if ((map->pin.mngd == VMAP_MNGD_CLIENT) && (aperture_inuse != NULL))
*aperture_inuse += map->pin.attrib.size;
}
attrib->type = VMAP_OBJ_TYPE_MEM;
@@ -200,7 +285,9 @@ match_syncpt_id(int id, void *entry, void *data)
static int
syncobj_map(struct vmap_ctx_t *vmap_ctx,
struct vmap_syncobj_map_params *params,
struct vmap_obj_attributes *attrib)
struct vmap_obj_attributes *attrib,
uint64_t aperture_limit,
uint64_t *const aperture_inuse)
{
int ret = 0;
s32 id_exist = 0;
@@ -239,6 +326,16 @@ syncobj_map(struct vmap_ctx_t *vmap_ctx,
goto err;
}
if ((params->mngd == VMAP_MNGD_CLIENT) && (aperture_inuse != NULL)) {
ret = dev_map_limit_check(aperture_limit, *aperture_inuse, SP_MAP_SIZE);
if (ret != 0) {
pr_err("Failed in aperture limit check\n");
idr_remove(&vmap_ctx->sync_idr, map->obj_id);
kfree(map);
goto err;
}
}
/* local syncobjs do not need to be pinned to pcie iova.*/
map->pin.fd = params->fd;
map->pin.syncpt_id = syncpt_id;
@@ -253,6 +350,9 @@ syncobj_map(struct vmap_ctx_t *vmap_ctx,
kfree(map);
goto err;
}
if ((params->mngd == VMAP_MNGD_CLIENT) && (aperture_inuse != NULL))
*aperture_inuse += map->pin.attrib.size;
attrib->type = VMAP_OBJ_TYPE_SYNC;
attrib->id = map->obj_id;
attrib->iova = map->pin.attrib.iova;
@@ -461,7 +561,8 @@ importobj_getref(struct vmap_ctx_t *vmap_ctx, s32 obj_id)
int
vmap_obj_map(void *vmap_h, struct vmap_obj_map_params *params,
struct vmap_obj_attributes *attrib)
struct vmap_obj_attributes *attrib, uint64_t aperture_limit,
uint64_t *const aperture_inuse)
{
int ret = 0;
struct vmap_ctx_t *vmap_ctx = (struct vmap_ctx_t *)vmap_h;
@@ -471,10 +572,18 @@ vmap_obj_map(void *vmap_h, struct vmap_obj_map_params *params,
switch (params->type) {
case VMAP_OBJ_TYPE_MEM:
ret = memobj_map(vmap_ctx, &params->u.memobj, attrib);
ret = memobj_map(vmap_ctx,
&params->u.memobj,
attrib,
aperture_limit,
aperture_inuse);
break;
case VMAP_OBJ_TYPE_SYNC:
ret = syncobj_map(vmap_ctx, &params->u.syncobj, attrib);
ret = syncobj_map(vmap_ctx,
&params->u.syncobj,
attrib,
aperture_limit,
aperture_inuse);
break;
case VMAP_OBJ_TYPE_IMPORT:
ret = importobj_map(vmap_ctx, &params->u.importobj, attrib);

View File

@@ -1,5 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
/*
* SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*/
#ifndef __VMAP_H__
#define __VMAP_H__
@@ -232,7 +235,8 @@ vmap_deinit(void **vmap_h);
/* Map objects to pcie device.*/
int
vmap_obj_map(void *vmap_h, struct vmap_obj_map_params *params,
struct vmap_obj_attributes *attrib);
struct vmap_obj_attributes *attrib, uint64_t aperture_limit,
uint64_t *const aperture_inuse);
/* Unmap objects from pcie device.*/
int