Re: [PATCH v1 1/4] misc: fastrpc: Add CRC support using invokeV2 request

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jan 23, 2025 at 11:16:41AM +0530, Ekansh Gupta wrote:
> 
> 
> 
> On 10/7/2024 7:27 PM, Dmitry Baryshkov wrote:
> > On Mon, Oct 07, 2024 at 02:15:15PM GMT, Ekansh Gupta wrote:
> >> InvokeV2 request is intended to support multiple enhanced invoke
> >> requests like CRC check, performance counter enablement and polling
> >> mode for RPC invocations. CRC check is getting enabled as part of
> >> this patch. CRC check for input and output argument helps in ensuring
> >> data consistency over a remote call. If user intends to enable CRC
> >> check, first local user CRC is calculated at user end and a CRC buffer
> >> is passed to DSP to capture remote CRC values. DSP is expected to
> >> write to the remote CRC buffer which is then compared at user level
> >> with the local CRC values.
> > This doesn't explain why this is necessary. Why do you need to checksum
> > arguments?
> This helps if the user suspects any data inconsistencies in the buffers passed to DSP over
> remote call. This is not enabled by default and user can enable it as per their reqirement.
> I'll add this information.

An inconsistency where? Between the kernel and the DSP? Between the user
and the DSP? Does it cover buffer contents or just the addresses?

> >
> > Also, what if the DSP firmware doesn't support CRC? How should userspace
> > know that?
> CRC support on DSP is there since long time(>6years).

This doesn't give us a lot. Upstream kernel supports fastrpc since
MSM8916 and MSM8996. Do those platforms support CRC?
And if they do, why do we need the invoke_v2? Can we modify existing
code instead?

> From user space CRC check failure is
> not fatal and is printed as a warning. But if copy of CRC to user fails, it will result in remote
> call failure. Should I keep it as fatal considering that ever very old DSP support this or should
> I consider the copy failure as non-fatal as userspace is treating this as a warning?

warnings can remain unseen for a long time. Consider a GUI app. Nobody
is there to view kernel warnings or library output.

> >
> >> Signed-off-by: Ekansh Gupta <quic_ekangupt@xxxxxxxxxxx>
> >> ---
> >>  drivers/misc/fastrpc.c      | 161 ++++++++++++++++++++++++------------
> >>  include/uapi/misc/fastrpc.h |   7 ++
> >>  2 files changed, 116 insertions(+), 52 deletions(-)
> >>
> >> diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
> >> index 74181b8c386b..8e817a763d1d 100644
> >> --- a/drivers/misc/fastrpc.c
> >> +++ b/drivers/misc/fastrpc.c
> >> @@ -573,13 +573,15 @@ static void fastrpc_get_buff_overlaps(struct fastrpc_invoke_ctx *ctx)
> >>  
> >>  static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
> >>  			struct fastrpc_user *user, u32 kernel, u32 sc,
> >> -			struct fastrpc_invoke_args *args)
> >> +			struct fastrpc_invoke_v2 *inv2)
> >>  {
> >>  	struct fastrpc_channel_ctx *cctx = user->cctx;
> >>  	struct fastrpc_invoke_ctx *ctx = NULL;
> >> +	struct fastrpc_invoke_args *args = NULL;
> > Why do you need to init to NULL if you are going to set it two lines
> > below?
> >
> >>  	unsigned long flags;
> >>  	int ret;
> >>  
> >> +	args = (struct fastrpc_invoke_args *)inv2->inv.args;
> > Why does it need a typecast?
> >
> >>  	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> >>  	if (!ctx)
> >>  		return ERR_PTR(-ENOMEM);
> >> @@ -611,6 +613,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
> >>  	/* Released in fastrpc_context_put() */
> >>  	fastrpc_channel_ctx_get(cctx);
> >>  
> >> +	ctx->crc = (u32 *)(uintptr_t)inv2->crc;
> > Oh, but why? Also is it a user pointer or in-kernel data? If it's a
> > user-based pointer, where is the accessiblity check? Why isn't it
> > annotated properly?
> This is a user pointer where the crc data is expected to be copied. There is no
> other access to this pointer from kernel. I'm planning to change the data type
> for crc as (void __user*) inside fastrpc_invoke_ctx structure.

Yes, please. Also make sure that sparse doesn't add any warnings
regarding pointer conversions.

> >
> >>  	ctx->sc = sc;
> >>  	ctx->retval = -1;
> >>  	ctx->pid = current->pid;
> >> @@ -1070,6 +1073,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
> >>  	struct fastrpc_invoke_buf *list;
> >>  	struct fastrpc_phy_page *pages;
> >>  	u64 *fdlist;
> >> +	u32 *crclist;
> >>  	int i, inbufs, outbufs, handles;
> >>  
> >>  	inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
> >> @@ -1078,6 +1082,7 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
> >>  	list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
> >>  	pages = fastrpc_phy_page_start(list, ctx->nscalars);
> >>  	fdlist = (uint64_t *)(pages + inbufs + outbufs + handles);
> >> +	crclist = (u32 *)(fdlist + FASTRPC_MAX_FDLIST);
> > I think we should rewrite this parsing somehow. Is the format of data
> > documented somewhere?
> fdlist, crclist and poll(planned) are the only pointers that is being used. I'm planning
> to store these pointers to ctx structure and directly use it wherever needed. This will
> clean-up this unnecessary calculations at multiple places.


Please do. Nevertheless, the format also must be documented.

> >
> >>  
> >>  	for (i = inbufs; i < ctx->nbufs; ++i) {
> >>  		if (!ctx->maps[i]) {
> >> @@ -1102,6 +1107,12 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx,
> >>  			fastrpc_map_put(mmap);
> >>  	}
> >>  
> >> +	if (ctx->crc && crclist && rpra) {
> >> +		if (copy_to_user((void __user *)ctx->crc, crclist,
> >> +				FASTRPC_MAX_CRCLIST * sizeof(u32)))
> > Oh, so it's a user pointer. Then u32* was completely incorrect.
> > Also you are copying FASTRPC_MAX_CRCLIST elements. Are all of them
> > filled? Or are we leaking some data to userspace?
> Yes, right. Planning clean-up in next patch.
> 
> All of FASTRPC_MAX_CRCLIST is filled with crc data by DSP so copying should be fine.

Huh? I definitely want to see documentation for function arguments.

> >
> >> +			return -EFAULT;
> >> +	}
> >> +
> >>  	return 0;
> >>  }
> >>  
> >> @@ -1137,13 +1148,12 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
> >>  
> >>  }
> >>  
> >> -static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
> >> -				   u32 handle, u32 sc,
> >> -				   struct fastrpc_invoke_args *args)
> >> +static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel, struct fastrpc_invoke_v2 *inv2)
> > Please don't touch what doesn't need to be touched. You are replacing
> > handle/sc/args with inv2, not touching the first line.
> Ack.
> >
> >>  {
> >>  	struct fastrpc_invoke_ctx *ctx = NULL;
> >>  	struct fastrpc_buf *buf, *b;
> >> -
> >> +	struct fastrpc_invoke inv;
> >> +	u32 handle, sc;
> >>  	int err = 0;
> >>  
> >>  	if (!fl->sctx)
> >> @@ -1152,12 +1162,15 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
> >>  	if (!fl->cctx->rpdev)
> >>  		return -EPIPE;
> >>  
> >> +	inv = inv2->inv;
> >> +	handle = inv.handle;
> >> +	sc = inv.sc;
> >>  	if (handle == FASTRPC_INIT_HANDLE && !kernel) {
> >>  		dev_warn_ratelimited(fl->sctx->dev, "user app trying to send a kernel RPC message (%d)\n",  handle);
> >>  		return -EPERM;
> >>  	}
> >>  
> >> -	ctx = fastrpc_context_alloc(fl, kernel, sc, args);
> >> +	ctx = fastrpc_context_alloc(fl, kernel, sc, inv2);
> >>  	if (IS_ERR(ctx))
> >>  		return PTR_ERR(ctx);
> >>  
> >> @@ -1239,6 +1252,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
> >>  {
> >>  	struct fastrpc_init_create_static init;
> >>  	struct fastrpc_invoke_args *args;
> >> +	struct fastrpc_invoke_v2 ioctl = {0};
> > Why do you need to init it?
> Ack.
> >
> >>  	struct fastrpc_phy_page pages[1];
> >>  	char *name;
> >>  	int err;
> >> @@ -1248,7 +1262,6 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
> >>  		u32 namelen;
> >>  		u32 pageslen;
> >>  	} inbuf;
> >> -	u32 sc;
> >>  
> >>  	args = kcalloc(FASTRPC_CREATE_STATIC_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
> >>  	if (!args)
> >> @@ -1313,10 +1326,10 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
> >>  	args[2].length = sizeof(*pages);
> >>  	args[2].fd = -1;
> >>  
> >> -	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_STATIC, 3, 0);
> >> -
> >> -	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
> >> -				      sc, args);
> >> +	ioctl.inv.handle = FASTRPC_INIT_HANDLE;
> >> +	ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_STATIC, 3, 0);
> >> +	ioctl.inv.args = (u64)args;
> > Can you pass it as is, without typecasts?
> Cleaned up in refactoring change.
> >
> >> +	err = fastrpc_internal_invoke(fl, true, &ioctl);
> >>  	if (err)
> >>  		goto err_invoke;
> >>  
> >> @@ -1357,6 +1370,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
> >>  {
> >>  	struct fastrpc_init_create init;
> >>  	struct fastrpc_invoke_args *args;
> >> +	struct fastrpc_invoke_v2 ioctl = {0};
> >>  	struct fastrpc_phy_page pages[1];
> >>  	struct fastrpc_map *map = NULL;
> >>  	struct fastrpc_buf *imem = NULL;
> >> @@ -1370,7 +1384,6 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
> >>  		u32 attrs;
> >>  		u32 siglen;
> >>  	} inbuf;
> >> -	u32 sc;
> >>  	bool unsigned_module = false;
> >>  
> >>  	args = kcalloc(FASTRPC_CREATE_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
> >> @@ -1444,12 +1457,12 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
> >>  	args[5].length = sizeof(inbuf.siglen);
> >>  	args[5].fd = -1;
> >>  
> >> -	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
> >> +	ioctl.inv.handle = FASTRPC_INIT_HANDLE;
> >> +	ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
> >>  	if (init.attrs)
> >> -		sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
> >> -
> >> -	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
> >> -				      sc, args);
> >> +		ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
> > if (init.attrs)
> >     ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);
> > else
> >     ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
> >
> >> +	ioctl.inv.args = (u64)args;
> >> +	err = fastrpc_internal_invoke(fl, true, &ioctl);
> >>  	if (err)
> >>  		goto err_invoke;
> >>  
> >> @@ -1501,17 +1514,18 @@ static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
> >>  static int fastrpc_release_current_dsp_process(struct fastrpc_user *fl)
> >>  {
> >>  	struct fastrpc_invoke_args args[1];
> >> +	struct fastrpc_invoke_v2 ioctl = {0};
> >>  	int tgid = 0;
> >> -	u32 sc;
> >>  
> >>  	tgid = fl->tgid;
> >>  	args[0].ptr = (u64)(uintptr_t) &tgid;
> >>  	args[0].length = sizeof(tgid);
> >>  	args[0].fd = -1;
> >> -	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0);
> >>  
> >> -	return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
> >> -				       sc, &args[0]);
> >> +	ioctl.inv.handle = FASTRPC_INIT_HANDLE;
> >> +	ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0);
> >> +	ioctl.inv.args = (u64)args;
> >> +	return fastrpc_internal_invoke(fl, true, &ioctl);
> >>  }
> >>  
> >>  static int fastrpc_device_release(struct inode *inode, struct file *file)
> >> @@ -1647,45 +1661,77 @@ static int fastrpc_dmabuf_alloc(struct fastrpc_user *fl, char __user *argp)
> >>  static int fastrpc_init_attach(struct fastrpc_user *fl, int pd)
> >>  {
> >>  	struct fastrpc_invoke_args args[1];
> >> +	struct fastrpc_invoke_v2 ioctl = {0};
> >>  	int tgid = fl->tgid;
> >> -	u32 sc;
> >>  
> >>  	args[0].ptr = (u64)(uintptr_t) &tgid;
> >>  	args[0].length = sizeof(tgid);
> >>  	args[0].fd = -1;
> >> -	sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);
> >>  	fl->pd = pd;
> >>  
> >> -	return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
> >> -				       sc, &args[0]);
> >> +	ioctl.inv.handle = FASTRPC_INIT_HANDLE;
> >> +	ioctl.inv.sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0);
> >> +	ioctl.inv.args = (u64)args;
> >> +	return fastrpc_internal_invoke(fl, true, &ioctl);
> >>  }
> >>  
> >> -static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
> >> +static int fastrpc_copy_args(struct fastrpc_invoke *inv)
> >>  {
> >>  	struct fastrpc_invoke_args *args = NULL;
> >> -	struct fastrpc_invoke inv;
> >>  	u32 nscalars;
> >> -	int err;
> >> -
> >> -	if (copy_from_user(&inv, argp, sizeof(inv)))
> >> -		return -EFAULT;
> >>  
> >>  	/* nscalars is truncated here to max supported value */
> >> -	nscalars = REMOTE_SCALARS_LENGTH(inv.sc);
> >> +	nscalars = REMOTE_SCALARS_LENGTH(inv->sc);
> >>  	if (nscalars) {
> >>  		args = kcalloc(nscalars, sizeof(*args), GFP_KERNEL);
> >>  		if (!args)
> >>  			return -ENOMEM;
> >>  
> >> -		if (copy_from_user(args, (void __user *)(uintptr_t)inv.args,
> >> +		if (copy_from_user(args, (void __user *)(uintptr_t)inv->args,
> > Wait... So inv->args is a user pointer? Then how can you assign a
> > kernel-based pointer to the same field? I think you need to sanitize
> > your structures. One is userspace-facing. It should be using userspace
> > data pointers, etc. Another one is a kernel representation of the ioctl
> > args. It might have a different structure, it shouldn't contain __user
> > data, etc.
> I'm planning to have a new structure to carry ctx specific data which will be saved in
> fastrpc_invoke_ctx structure during fastrpc_context_alloc.
> 
> Something like this:
> struct fastrpc_ctx_args {
>     struct fastrpc_invoke_args *args;  /* Carries args that is copied from ioctl structure */
>     void __user *crc; /* Carries CRC user pointer where the crcdata from DSP will be copied for user to read */
>     u64 poll_timeout; /* Carried context specific poll_timeout information */
> };
> 
> Do you see any problem with this?

Not yet. But I'd like to see patches first.

> >
> >>  				   nscalars * sizeof(*args))) {
> >>  			kfree(args);
> >>  			return -EFAULT;
> >>  		}
> >>  	}
> >> +	inv->args = args;
> >>  
> >> -	err = fastrpc_internal_invoke(fl, false, inv.handle, inv.sc, args);
> >> -	kfree(args);
> >> +	return 0;
> >> +}
> > Looking at the rest of the code, I think the patch needs to be split.
> > CRC is the minor issue at this point, please focus on getting existing
> > data being handled correctly while refactoring the code to use new
> > structure. I'd suggest seeing two struct definitions: one for the
> > userspace and another one for the kernel space.
> I've made changes for refactoring where instead of using userspace structure, I'm
> planning to use fastrpc_ctx_args structure mentioned above.
> >
> >> +
> >> +static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp)
> >> +{
> >> +	struct fastrpc_invoke_v2 ioctl = {0};
> >> +	struct fastrpc_invoke inv;
> >> +	int err;
> >> +
> >> +	if (copy_from_user(&inv, argp, sizeof(inv)))
> >> +		return -EFAULT;
> >> +
> >> +	err = fastrpc_copy_args(&inv);
> >> +	if (err)
> >>
> >> -- 
> >> 2.34.1
> >>
> 

-- 
With best wishes
Dmitry



[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux