lkml.org 
[lkml]   [2019]   [Dec]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.3 014/105] aio: Fix io_pgetevents() struct __compat_aio_sigset layout
    Date
    From: Guillem Jover <guillem@hadrons.org>

    [ Upstream commit 97eba80fcca754856d09e048f469db22773bec68 ]

    This type is used to pass the sigset_t from userland to the kernel,
    but it was using the kernel native pointer type for the member
    representing the compat userland pointer to the userland sigset_t.

    This messes up the layout, and makes the kernel eat up both the
    userland pointer and the size members into the kernel pointer, and
    then reads garbage into the kernel sigsetsize. Which makes the sigset_t
    size consistency check fail, and consequently the syscall always
    returns -EINVAL.

    This breaks both libaio and strace on 32-bit userland running on 64-bit
    kernels. And there are apparently no users in the wild of the current
    broken layout (at least according to codesearch.debian.org and a brief
    check over github.com search). So it looks safe to fix this directly
    in the kernel, instead of either letting userland deal with this
    permanently with the additional overhead or trying to make the syscall
    infer what layout userland used, even though this is also being worked
    around in libaio to temporarily cope with kernels that have not yet
    been fixed.

    We use a proper compat_uptr_t instead of a compat_sigset_t pointer.

    Fixes: 7a074e96dee6 ("aio: implement io_pgetevents")
    Signed-off-by: Guillem Jover <guillem@hadrons.org>
    Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/aio.c | 10 +++++-----
    1 file changed, 5 insertions(+), 5 deletions(-)

    diff --git a/fs/aio.c b/fs/aio.c
    index 01e0fb9ae45ae..0d9a559d488c1 100644
    --- a/fs/aio.c
    +++ b/fs/aio.c
    @@ -2179,7 +2179,7 @@ SYSCALL_DEFINE5(io_getevents_time32, __u32, ctx_id,
    #ifdef CONFIG_COMPAT

    struct __compat_aio_sigset {
    - compat_sigset_t __user *sigmask;
    + compat_uptr_t sigmask;
    compat_size_t sigsetsize;
    };

    @@ -2193,7 +2193,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
    struct old_timespec32 __user *, timeout,
    const struct __compat_aio_sigset __user *, usig)
    {
    - struct __compat_aio_sigset ksig = { NULL, };
    + struct __compat_aio_sigset ksig = { 0, };
    struct timespec64 t;
    bool interrupted;
    int ret;
    @@ -2204,7 +2204,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
    if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
    return -EFAULT;

    - ret = set_compat_user_sigmask(ksig.sigmask, ksig.sigsetsize);
    + ret = set_compat_user_sigmask(compat_ptr(ksig.sigmask), ksig.sigsetsize);
    if (ret)
    return ret;

    @@ -2228,7 +2228,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
    struct __kernel_timespec __user *, timeout,
    const struct __compat_aio_sigset __user *, usig)
    {
    - struct __compat_aio_sigset ksig = { NULL, };
    + struct __compat_aio_sigset ksig = { 0, };
    struct timespec64 t;
    bool interrupted;
    int ret;
    @@ -2239,7 +2239,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
    if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
    return -EFAULT;

    - ret = set_compat_user_sigmask(ksig.sigmask, ksig.sigsetsize);
    + ret = set_compat_user_sigmask(compat_ptr(ksig.sigmask), ksig.sigsetsize);
    if (ret)
    return ret;

    --
    2.20.1


    \
     
     \ /
      Last update: 2019-12-11 17:03    [W:4.028 / U:0.472 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site