Skip to content

Commit 97eba80

Browse files
guillemjAl Viro
authored andcommitted
aio: Fix io_pgetevents() struct __compat_aio_sigset layout
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: 7a074e9 ("aio: implement io_pgetevents") Signed-off-by: Guillem Jover <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 0ecee66 commit 97eba80

File tree

1 file changed

+5
-5
lines changed

1 file changed

+5
-5
lines changed

fs/aio.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2179,7 +2179,7 @@ SYSCALL_DEFINE5(io_getevents_time32, __u32, ctx_id,
21792179
#ifdef CONFIG_COMPAT
21802180

21812181
struct __compat_aio_sigset {
2182-
compat_sigset_t __user *sigmask;
2182+
compat_uptr_t sigmask;
21832183
compat_size_t sigsetsize;
21842184
};
21852185

@@ -2193,7 +2193,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
21932193
struct old_timespec32 __user *, timeout,
21942194
const struct __compat_aio_sigset __user *, usig)
21952195
{
2196-
struct __compat_aio_sigset ksig = { NULL, };
2196+
struct __compat_aio_sigset ksig = { 0, };
21972197
struct timespec64 t;
21982198
bool interrupted;
21992199
int ret;
@@ -2204,7 +2204,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents,
22042204
if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
22052205
return -EFAULT;
22062206

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

@@ -2228,7 +2228,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
22282228
struct __kernel_timespec __user *, timeout,
22292229
const struct __compat_aio_sigset __user *, usig)
22302230
{
2231-
struct __compat_aio_sigset ksig = { NULL, };
2231+
struct __compat_aio_sigset ksig = { 0, };
22322232
struct timespec64 t;
22332233
bool interrupted;
22342234
int ret;
@@ -2239,7 +2239,7 @@ COMPAT_SYSCALL_DEFINE6(io_pgetevents_time64,
22392239
if (usig && copy_from_user(&ksig, usig, sizeof(ksig)))
22402240
return -EFAULT;
22412241

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

0 commit comments

Comments
 (0)