lkml.org 
[lkml]   [2018]   [Sep]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.18 227/235] IB/mlx5: fix uaccess beyond "count" in debugfs read/write handlers
    Date
    4.18-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Jann Horn <jannh@google.com>

    [ Upstream commit 60e6627f12a78203a093ca05b7bca15627747d81 ]

    In general, accessing userspace memory beyond the length of the supplied
    buffer in VFS read/write handlers can lead to both kernel memory corruption
    (via kernel_read()/kernel_write(), which can e.g. be triggered via
    sys_splice()) and privilege escalation inside userspace.

    In this case, the affected files are in debugfs (and should therefore only
    be accessible to root), and the read handlers check that *pos is zero
    (meaning that at least sys_splice() can't trigger kernel memory
    corruption). Because of the root requirement, this is not a security fix,
    but rather a cleanup.

    For the read handlers, fix it by using simple_read_from_buffer() instead
    of custom logic. Add min() calls to the write handlers.

    Fixes: 4a2da0b8c078 ("IB/mlx5: Add debug control parameters for congestion control")
    Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters")
    Signed-off-by: Jann Horn <jannh@google.com>
    Reviewed-by: Leon Romanovsky <leonro@mellanox.com>
    Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
    Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/infiniband/hw/mlx5/cong.c | 9 +--------
    drivers/infiniband/hw/mlx5/mr.c | 32 ++++++++------------------------
    2 files changed, 9 insertions(+), 32 deletions(-)

    --- a/drivers/infiniband/hw/mlx5/cong.c
    +++ b/drivers/infiniband/hw/mlx5/cong.c
    @@ -359,9 +359,6 @@ static ssize_t get_param(struct file *fi
    int ret;
    char lbuf[11];

    - if (*pos)
    - return 0;
    -
    ret = mlx5_ib_get_cc_params(param->dev, param->port_num, offset, &var);
    if (ret)
    return ret;
    @@ -370,11 +367,7 @@ static ssize_t get_param(struct file *fi
    if (ret < 0)
    return ret;

    - if (copy_to_user(buf, lbuf, ret))
    - return -EFAULT;
    -
    - *pos += ret;
    - return ret;
    + return simple_read_from_buffer(buf, count, pos, lbuf, ret);
    }

    static const struct file_operations dbg_cc_fops = {
    --- a/drivers/infiniband/hw/mlx5/mr.c
    +++ b/drivers/infiniband/hw/mlx5/mr.c
    @@ -271,16 +271,16 @@ static ssize_t size_write(struct file *f
    {
    struct mlx5_cache_ent *ent = filp->private_data;
    struct mlx5_ib_dev *dev = ent->dev;
    - char lbuf[20];
    + char lbuf[20] = {0};
    u32 var;
    int err;
    int c;

    - if (copy_from_user(lbuf, buf, sizeof(lbuf)))
    + count = min(count, sizeof(lbuf) - 1);
    + if (copy_from_user(lbuf, buf, count))
    return -EFAULT;

    c = order2idx(dev, ent->order);
    - lbuf[sizeof(lbuf) - 1] = 0;

    if (sscanf(lbuf, "%u", &var) != 1)
    return -EINVAL;
    @@ -310,19 +310,11 @@ static ssize_t size_read(struct file *fi
    char lbuf[20];
    int err;

    - if (*pos)
    - return 0;
    -
    err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->size);
    if (err < 0)
    return err;

    - if (copy_to_user(buf, lbuf, err))
    - return -EFAULT;
    -
    - *pos += err;
    -
    - return err;
    + return simple_read_from_buffer(buf, count, pos, lbuf, err);
    }

    static const struct file_operations size_fops = {
    @@ -337,16 +329,16 @@ static ssize_t limit_write(struct file *
    {
    struct mlx5_cache_ent *ent = filp->private_data;
    struct mlx5_ib_dev *dev = ent->dev;
    - char lbuf[20];
    + char lbuf[20] = {0};
    u32 var;
    int err;
    int c;

    - if (copy_from_user(lbuf, buf, sizeof(lbuf)))
    + count = min(count, sizeof(lbuf) - 1);
    + if (copy_from_user(lbuf, buf, count))
    return -EFAULT;

    c = order2idx(dev, ent->order);
    - lbuf[sizeof(lbuf) - 1] = 0;

    if (sscanf(lbuf, "%u", &var) != 1)
    return -EINVAL;
    @@ -372,19 +364,11 @@ static ssize_t limit_read(struct file *f
    char lbuf[20];
    int err;

    - if (*pos)
    - return 0;
    -
    err = snprintf(lbuf, sizeof(lbuf), "%d\n", ent->limit);
    if (err < 0)
    return err;

    - if (copy_to_user(buf, lbuf, err))
    - return -EFAULT;
    -
    - *pos += err;
    -
    - return err;
    + return simple_read_from_buffer(buf, count, pos, lbuf, err);
    }

    static const struct file_operations limit_fops = {

    \
     
     \ /
      Last update: 2018-09-24 14:48    [W:4.140 / U:0.084 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site