fanotify: Fix sys_fanotify_mark() on native x86-32

commit 2ca408d9c7 upstream.

Commit

  121b32a58a ("x86/entry/32: Use IA32-specific wrappers for syscalls taking 64-bit arguments")

converted native x86-32 which take 64-bit arguments to use the
compat handlers to allow conversion to passing args via pt_regs.
sys_fanotify_mark() was however missed, as it has a general compat
handler. Add a config option that will use the syscall wrapper that
takes the split args for native 32-bit.

 [ bp: Fix typo in Kconfig help text. ]

Fixes: 121b32a58a ("x86/entry/32: Use IA32-specific wrappers for syscalls taking 64-bit arguments")
Reported-by: Paweł Jasiak <pawel@jasiak.xyz>
Signed-off-by: Brian Gerst <brgerst@gmail.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: Jan Kara <jack@suse.cz>
Acked-by: Andy Lutomirski <luto@kernel.org>
Link: https://lkml.kernel.org/r/20201130223059.101286-1-brgerst@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Brian Gerst 2020-11-30 17:30:59 -05:00 committed by Greg Kroah-Hartman
parent 797c128d3c
commit 797335659e
4 changed files with 38 additions and 10 deletions

View file

@ -1053,6 +1053,12 @@ config ARCH_WANT_LD_ORPHAN_WARN
by the linker, since the locations of such sections can change between linker by the linker, since the locations of such sections can change between linker
versions. versions.
config ARCH_SPLIT_ARG64
bool
help
If a 32-bit architecture requires 64-bit arguments to be split into
pairs of 32-bit arguments, select this option.
source "kernel/gcov/Kconfig" source "kernel/gcov/Kconfig"
source "scripts/gcc-plugins/Kconfig" source "scripts/gcc-plugins/Kconfig"

View file

@ -18,6 +18,7 @@ config X86_32
select MODULES_USE_ELF_REL select MODULES_USE_ELF_REL
select OLD_SIGACTION select OLD_SIGACTION
select GENERIC_VDSO_32 select GENERIC_VDSO_32
select ARCH_SPLIT_ARG64
config X86_64 config X86_64
def_bool y def_bool y

View file

@ -1285,26 +1285,23 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
return ret; return ret;
} }
#ifndef CONFIG_ARCH_SPLIT_ARG64
SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags, SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
__u64, mask, int, dfd, __u64, mask, int, dfd,
const char __user *, pathname) const char __user *, pathname)
{ {
return do_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname); return do_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname);
} }
#endif
#ifdef CONFIG_COMPAT #if defined(CONFIG_ARCH_SPLIT_ARG64) || defined(CONFIG_COMPAT)
COMPAT_SYSCALL_DEFINE6(fanotify_mark, SYSCALL32_DEFINE6(fanotify_mark,
int, fanotify_fd, unsigned int, flags, int, fanotify_fd, unsigned int, flags,
__u32, mask0, __u32, mask1, int, dfd, SC_ARG64(mask), int, dfd,
const char __user *, pathname) const char __user *, pathname)
{ {
return do_fanotify_mark(fanotify_fd, flags, return do_fanotify_mark(fanotify_fd, flags, SC_VAL64(__u64, mask),
#ifdef __BIG_ENDIAN dfd, pathname);
((__u64)mask0 << 32) | mask1,
#else
((__u64)mask1 << 32) | mask0,
#endif
dfd, pathname);
} }
#endif #endif

View file

@ -251,6 +251,30 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event)
static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
#endif /* __SYSCALL_DEFINEx */ #endif /* __SYSCALL_DEFINEx */
/* For split 64-bit arguments on 32-bit architectures */
#ifdef __LITTLE_ENDIAN
#define SC_ARG64(name) u32, name##_lo, u32, name##_hi
#else
#define SC_ARG64(name) u32, name##_hi, u32, name##_lo
#endif
#define SC_VAL64(type, name) ((type) name##_hi << 32 | name##_lo)
#ifdef CONFIG_COMPAT
#define SYSCALL32_DEFINE1 COMPAT_SYSCALL_DEFINE1
#define SYSCALL32_DEFINE2 COMPAT_SYSCALL_DEFINE2
#define SYSCALL32_DEFINE3 COMPAT_SYSCALL_DEFINE3
#define SYSCALL32_DEFINE4 COMPAT_SYSCALL_DEFINE4
#define SYSCALL32_DEFINE5 COMPAT_SYSCALL_DEFINE5
#define SYSCALL32_DEFINE6 COMPAT_SYSCALL_DEFINE6
#else
#define SYSCALL32_DEFINE1 SYSCALL_DEFINE1
#define SYSCALL32_DEFINE2 SYSCALL_DEFINE2
#define SYSCALL32_DEFINE3 SYSCALL_DEFINE3
#define SYSCALL32_DEFINE4 SYSCALL_DEFINE4
#define SYSCALL32_DEFINE5 SYSCALL_DEFINE5
#define SYSCALL32_DEFINE6 SYSCALL_DEFINE6
#endif
/* /*
* Called before coming back to user-mode. Returning to user-mode with an * Called before coming back to user-mode. Returning to user-mode with an
* address limit different than USER_DS can allow to overwrite kernel memory. * address limit different than USER_DS can allow to overwrite kernel memory.