[PATCH 1/2] powerpc/spufs: fix copy_to_user while atomic
Christoph Hellwig
hch at lst.de
Mon May 4 23:04:43 AEST 2020
powerpc mantainers,
are you going to pick this up for the next -rc1? I'm waiting for it to
hit upstream before resending the coredump series.
On Wed, Apr 29, 2020 at 03:03:02PM +0800, Jeremy Kerr wrote:
> Currently, we may perform a copy_to_user (through
> simple_read_from_buffer()) while holding a context's register_lock,
> while accessing the context save area.
>
> This change uses a temporary buffer for the context save area data,
> which we then pass to simple_read_from_buffer.
>
> Includes changes from Christoph Hellwig <hch at lst.de>.
>
> Fixes: bf1ab978be23 ("[POWERPC] coredump: Add SPU elf notes to coredump.")
> Signed-off-by: Jeremy Kerr <jk at ozlabs.org>
> Reviewed-by: Arnd Bergmann <arnd at arndb.de>
> Reviewed-by: Christoph Hellwig <hch at lst.de>
> ---
> arch/powerpc/platforms/cell/spufs/file.c | 113 +++++++++++++++--------
> 1 file changed, 75 insertions(+), 38 deletions(-)
>
> diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
> index c0f950a3f4e1..b4e1ef650b40 100644
> --- a/arch/powerpc/platforms/cell/spufs/file.c
> +++ b/arch/powerpc/platforms/cell/spufs/file.c
> @@ -1978,8 +1978,9 @@ static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
> static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
> size_t len, loff_t *pos)
> {
> - int ret;
> struct spu_context *ctx = file->private_data;
> + u32 stat, data;
> + int ret;
>
> if (!access_ok(buf, len))
> return -EFAULT;
> @@ -1988,11 +1989,16 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
> if (ret)
> return ret;
> spin_lock(&ctx->csa.register_lock);
> - ret = __spufs_mbox_info_read(ctx, buf, len, pos);
> + stat = ctx->csa.prob.mb_stat_R;
> + data = ctx->csa.prob.pu_mb_R;
> spin_unlock(&ctx->csa.register_lock);
> spu_release_saved(ctx);
>
> - return ret;
> + /* EOF if there's no entry in the mbox */
> + if (!(stat & 0x0000ff))
> + return 0;
> +
> + return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
> }
>
> static const struct file_operations spufs_mbox_info_fops = {
> @@ -2019,6 +2025,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
> size_t len, loff_t *pos)
> {
> struct spu_context *ctx = file->private_data;
> + u32 stat, data;
> int ret;
>
> if (!access_ok(buf, len))
> @@ -2028,11 +2035,16 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
> if (ret)
> return ret;
> spin_lock(&ctx->csa.register_lock);
> - ret = __spufs_ibox_info_read(ctx, buf, len, pos);
> + stat = ctx->csa.prob.mb_stat_R;
> + data = ctx->csa.priv2.puint_mb_R;
> spin_unlock(&ctx->csa.register_lock);
> spu_release_saved(ctx);
>
> - return ret;
> + /* EOF if there's no entry in the ibox */
> + if (!(stat & 0xff0000))
> + return 0;
> +
> + return simple_read_from_buffer(buf, len, pos, &data, sizeof(data));
> }
>
> static const struct file_operations spufs_ibox_info_fops = {
> @@ -2041,6 +2053,11 @@ static const struct file_operations spufs_ibox_info_fops = {
> .llseek = generic_file_llseek,
> };
>
> +static size_t spufs_wbox_info_cnt(struct spu_context *ctx)
> +{
> + return (4 - ((ctx->csa.prob.mb_stat_R & 0x00ff00) >> 8)) * sizeof(u32);
> +}
> +
> static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
> char __user *buf, size_t len, loff_t *pos)
> {
> @@ -2049,7 +2066,7 @@ static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,
> u32 wbox_stat;
>
> wbox_stat = ctx->csa.prob.mb_stat_R;
> - cnt = 4 - ((wbox_stat & 0x00ff00) >> 8);
> + cnt = spufs_wbox_info_cnt(ctx);
> for (i = 0; i < cnt; i++) {
> data[i] = ctx->csa.spu_mailbox_data[i];
> }
> @@ -2062,7 +2079,8 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
> size_t len, loff_t *pos)
> {
> struct spu_context *ctx = file->private_data;
> - int ret;
> + u32 data[ARRAY_SIZE(ctx->csa.spu_mailbox_data)];
> + int ret, count;
>
> if (!access_ok(buf, len))
> return -EFAULT;
> @@ -2071,11 +2089,13 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
> if (ret)
> return ret;
> spin_lock(&ctx->csa.register_lock);
> - ret = __spufs_wbox_info_read(ctx, buf, len, pos);
> + count = spufs_wbox_info_cnt(ctx);
> + memcpy(&data, &ctx->csa.spu_mailbox_data, sizeof(data));
> spin_unlock(&ctx->csa.register_lock);
> spu_release_saved(ctx);
>
> - return ret;
> + return simple_read_from_buffer(buf, len, pos, &data,
> + count * sizeof(u32));
> }
>
> static const struct file_operations spufs_wbox_info_fops = {
> @@ -2084,27 +2104,33 @@ static const struct file_operations spufs_wbox_info_fops = {
> .llseek = generic_file_llseek,
> };
>
> -static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
> - char __user *buf, size_t len, loff_t *pos)
> +static void ___spufs_dma_info_read(struct spu_context *ctx,
> + struct spu_dma_info *info)
> {
> - struct spu_dma_info info;
> - struct mfc_cq_sr *qp, *spuqp;
> int i;
>
> - info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
> - info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
> - info.dma_info_status = ctx->csa.spu_chnldata_RW[24];
> - info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
> - info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
> + info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW;
> + info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0];
> + info->dma_info_status = ctx->csa.spu_chnldata_RW[24];
> + info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25];
> + info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27];
> for (i = 0; i < 16; i++) {
> - qp = &info.dma_info_command_data[i];
> - spuqp = &ctx->csa.priv2.spuq[i];
> + struct mfc_cq_sr *qp = &info->dma_info_command_data[i];
> + struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i];
>
> qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW;
> qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW;
> qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW;
> qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW;
> }
> +}
> +
> +static ssize_t __spufs_dma_info_read(struct spu_context *ctx,
> + char __user *buf, size_t len, loff_t *pos)
> +{
> + struct spu_dma_info info;
> +
> + ___spufs_dma_info_read(ctx, &info);
>
> return simple_read_from_buffer(buf, len, pos, &info,
> sizeof info);
> @@ -2114,6 +2140,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
> size_t len, loff_t *pos)
> {
> struct spu_context *ctx = file->private_data;
> + struct spu_dma_info info;
> int ret;
>
> if (!access_ok(buf, len))
> @@ -2123,11 +2150,12 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
> if (ret)
> return ret;
> spin_lock(&ctx->csa.register_lock);
> - ret = __spufs_dma_info_read(ctx, buf, len, pos);
> + ___spufs_dma_info_read(ctx, &info);
> spin_unlock(&ctx->csa.register_lock);
> spu_release_saved(ctx);
>
> - return ret;
> + return simple_read_from_buffer(buf, len, pos, &info,
> + sizeof(info));
> }
>
> static const struct file_operations spufs_dma_info_fops = {
> @@ -2136,13 +2164,31 @@ static const struct file_operations spufs_dma_info_fops = {
> .llseek = no_llseek,
> };
>
> +static void ___spufs_proxydma_info_read(struct spu_context *ctx,
> + struct spu_proxydma_info *info)
> +{
> + int i;
> +
> + info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
> + info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
> + info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
> +
> + for (i = 0; i < 8; i++) {
> + struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i];
> + struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i];
> +
> + qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
> + qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
> + qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
> + qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
> + }
> +}
> +
> static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
> char __user *buf, size_t len, loff_t *pos)
> {
> struct spu_proxydma_info info;
> - struct mfc_cq_sr *qp, *puqp;
> int ret = sizeof info;
> - int i;
>
> if (len < ret)
> return -EINVAL;
> @@ -2150,18 +2196,7 @@ static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
> if (!access_ok(buf, len))
> return -EFAULT;
>
> - info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW;
> - info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW;
> - info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R;
> - for (i = 0; i < 8; i++) {
> - qp = &info.proxydma_info_command_data[i];
> - puqp = &ctx->csa.priv2.puq[i];
> -
> - qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW;
> - qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW;
> - qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW;
> - qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW;
> - }
> + ___spufs_proxydma_info_read(ctx, &info);
>
> return simple_read_from_buffer(buf, len, pos, &info,
> sizeof info);
> @@ -2171,17 +2206,19 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
> size_t len, loff_t *pos)
> {
> struct spu_context *ctx = file->private_data;
> + struct spu_proxydma_info info;
> int ret;
>
> ret = spu_acquire_saved(ctx);
> if (ret)
> return ret;
> spin_lock(&ctx->csa.register_lock);
> - ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
> + ___spufs_proxydma_info_read(ctx, &info);
> spin_unlock(&ctx->csa.register_lock);
> spu_release_saved(ctx);
>
> - return ret;
> + return simple_read_from_buffer(buf, len, pos, &info,
> + sizeof(info));
> }
>
> static const struct file_operations spufs_proxydma_info_fops = {
> --
> 2.17.1
---end quoted text---
More information about the Linuxppc-dev
mailing list