2013-05-22 21:08:09

by Andy Lutomirski

[permalink] [raw]
Subject: [PATCH 0/5] x86: oops on uaccess faults outside of user addresses

Currently, __get_user can't trigger an OOPS -- any exception will be
caught and return -EFAULT. This means that, if an access_ok check is
missing somewhere, then an attacker can freely use it to probe for valid
kernel mappings.

This series annotates all of the exception fixups as "catch anything" or
"catch valid uaccess faults", and skips the fixup (and hence oopses) if
an instruction of the latter type faults for any reason other than a
page fault to a user address.

I know of only one bug of this type; it's fixed in patch 5.

Perhaps surprisingly, this seems to survive Trinity fairly well.

Andy Lutomirski (5):
x86: Split "utter crap" pnpbios fixup out of fixup_exception
x86: Clean up extable entry format (and free up a bit)
x86: Annotate _ASM_EXTABLE users to distinguish uaccess from
everything else
x86: Don't fixup uaccess faults to kernel or non-canonical addresses
net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

arch/x86/ia32/ia32entry.S | 4 +-
arch/x86/include/asm/asm.h | 75 ++++++++----
arch/x86/include/asm/fpu-internal.h | 6 +-
arch/x86/include/asm/futex.h | 8 +-
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/include/asm/msr.h | 4 +-
arch/x86/include/asm/segment.h | 2 +-
arch/x86/include/asm/special_insns.h | 2 +-
arch/x86/include/asm/traps.h | 6 +
arch/x86/include/asm/uaccess.h | 10 +-
arch/x86/include/asm/word-at-a-time.h | 2 +-
arch/x86/include/asm/xsave.h | 6 +-
arch/x86/kernel/entry_32.S | 26 ++---
arch/x86/kernel/entry_64.S | 6 +-
arch/x86/kernel/ftrace.c | 4 +-
arch/x86/kernel/kprobes/core.c | 4 +-
arch/x86/kernel/test_nx.c | 2 +-
arch/x86/kernel/test_rodata.c | 2 +-
arch/x86/kernel/traps.c | 12 +-
arch/x86/kvm/emulate.c | 4 +-
arch/x86/lib/checksum_32.S | 4 +-
arch/x86/lib/copy_user_64.S | 50 ++++----
arch/x86/lib/copy_user_nocache_64.S | 44 +++----
arch/x86/lib/csum-copy_64.S | 6 +-
arch/x86/lib/getuser.S | 12 +-
arch/x86/lib/mmx_32.c | 12 +-
arch/x86/lib/msr-reg.S | 4 +-
arch/x86/lib/putuser.S | 10 +-
arch/x86/lib/usercopy_32.c | 212 +++++++++++++++++-----------------
arch/x86/lib/usercopy_64.c | 4 +-
arch/x86/mm/extable.c | 41 +++----
arch/x86/mm/fault.c | 36 ++++--
arch/x86/mm/init_32.c | 2 +-
arch/x86/um/checksum_32.S | 4 +-
arch/x86/xen/xen-asm_32.S | 2 +-
net/socket.c | 33 +++++-
36 files changed, 375 insertions(+), 288 deletions(-)

--
1.8.1.4


2013-05-22 21:08:13

by Andy Lutomirski

[permalink] [raw]
Subject: [PATCH 1/5] x86: Split "utter crap" pnpbios fixup out of fixup_exception

It has odd semantics, and it's only applicable (AFAICS) to #GP and #PF.

Signed-off-by: Andy Lutomirski <[email protected]>
---
arch/x86/include/asm/traps.h | 6 ++++++
arch/x86/kernel/traps.c | 2 ++
arch/x86/mm/extable.c | 14 --------------
arch/x86/mm/fault.c | 19 +++++++++++++++++++
4 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 88eae2a..55521de 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -89,6 +89,12 @@ asmlinkage void smp_thermal_interrupt(void);
asmlinkage void mce_threshold_interrupt(void);
#endif

+#ifdef CONFIG_PNPBIOS
+extern void fixup_pnpbios_exception(struct pt_regs *regs);
+#else
+static inline void fixup_pnpbios_exception(struct pt_regs *regs) {}
+#endif
+
/* Interrupts/Exceptions */
enum {
X86_TRAP_DE = 0, /* 0, Divide-by-zero */
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 68bda7a..8647670 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -275,6 +275,8 @@ do_general_protection(struct pt_regs *regs, long error_code)

tsk = current;
if (!user_mode(regs)) {
+ fixup_pnpbios_exception(regs); /* Might not return */
+
if (fixup_exception(regs))
goto exit;

diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 903ec1e..82e4ae8 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -19,20 +19,6 @@ int fixup_exception(struct pt_regs *regs)
const struct exception_table_entry *fixup;
unsigned long new_ip;

-#ifdef CONFIG_PNPBIOS
- if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
- extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
- extern u32 pnp_bios_is_utter_crap;
- pnp_bios_is_utter_crap = 1;
- printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
- __asm__ volatile(
- "movl %0, %%esp\n\t"
- "jmp *%1\n\t"
- : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
- panic("do_trap: can't hit this");
- }
-#endif
-
fixup = search_exception_tables(regs->ip);
if (fixup) {
new_ip = ex_fixup_addr(fixup);
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 0e88336..58afb50 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -569,6 +569,23 @@ static int is_f00f_bug(struct pt_regs *regs, unsigned long address)
return 0;
}

+#ifdef CONFIG_PNPBIOS
+void fixup_pnpbios_exception(struct pt_regs *regs)
+{
+ if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
+ extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
+ extern u32 pnp_bios_is_utter_crap;
+ pnp_bios_is_utter_crap = 1;
+ printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
+ __asm__ volatile(
+ "movl %0, %%esp\n\t"
+ "jmp *%1\n\t"
+ : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
+ panic("do_trap: can't hit this");
+ }
+}
+#endif
+
static const char nx_warning[] = KERN_CRIT
"kernel tried to execute NX-protected page - exploit attempt? (uid: %d)\n";

@@ -636,6 +653,8 @@ no_context(struct pt_regs *regs, unsigned long error_code,
unsigned long flags;
int sig;

+ fixup_pnpbios_exception(regs); /* Might not return */
+
/* Are we prepared to handle this kernel fault? */
if (fixup_exception(regs)) {
if (current_thread_info()->sig_on_uaccess_error && signal) {
--
1.8.1.4

2013-05-22 21:08:26

by Andy Lutomirski

[permalink] [raw]
Subject: [PATCH 2/5] x86: Clean up extable entry format (and free up a bit)

This adds two bits of fixup class information to a fixup entry,
generalizing the uaccess_err hack currently in place.

Signed-off-by: Andy Lutomirski <[email protected]>
---
arch/x86/include/asm/asm.h | 70 ++++++++++++++++++++++++++++++----------------
arch/x86/mm/extable.c | 22 +++++++++------
2 files changed, 60 insertions(+), 32 deletions(-)

diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 1c2d247..fa47fd4 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -39,34 +39,56 @@
#define _ASM_DI __ASM_REG(di)

/* Exception table entry */
-#ifdef __ASSEMBLY__
-# define _ASM_EXTABLE(from,to) \
- .pushsection "__ex_table","a" ; \
- .balign 8 ; \
- .long (from) - . ; \
- .long (to) - . ; \
- .popsection

-# define _ASM_EXTABLE_EX(from,to) \
- .pushsection "__ex_table","a" ; \
- .balign 8 ; \
- .long (from) - . ; \
- .long (to) - . + 0x7ffffff0 ; \
+/*
+ * An exception table entry is 64 bits. The first 32 bits are the offset
+ * from that entry to the potentially faulting instruction. sortextable
+ * relies on that exact encoding. The second 32 bits encode the fault
+ * handler address.
+ *
+ * We want to stick two extra bits of handler class into the fault handler
+ * address. All of these are generated by relocations, so we can only
+ * rely on addition. We therefore emit:
+ *
+ * (target - here) + (class) + 0x20000000
+ *
+ * This has the property that the two high bits are the class and the
+ * rest is easy to decode.
+ */
+
+/* There are two bits of extable entry class, added to a signed offset. */
+#define _EXTABLE_CLASS_DEFAULT 0 /* standard uaccess fixup */
+#define _EXTABLE_CLASS_EX 0x80000000 /* uaccess + set uaccess_err */
+
+/*
+ * The biases are the class constants + 0x20000000, as signed integers.
+ * This can't use ordinary arithmetic -- the assembler isn't that smart.
+ */
+#define _EXTABLE_BIAS_DEFAULT 0x20000000
+#define _EXTABLE_BIAS_EX 0x20000000 - 0x80000000
+
+#ifdef __ASSEMBLY__
+# define _EXPAND_EXTABLE_BIAS(x) x
+# define _ASM_EXTABLE_CLASS(from,to,bias) \
+ .pushsection "__ex_table","a" ; \
+ .balign 8 ; \
+ .long (from) - . ; \
+ .long (to) - . + _EXPAND_EXTABLE_BIAS(bias) ; \
.popsection
#else
-# define _ASM_EXTABLE(from,to) \
- " .pushsection \"__ex_table\",\"a\"\n" \
- " .balign 8\n" \
- " .long (" #from ") - .\n" \
- " .long (" #to ") - .\n" \
- " .popsection\n"
-
-# define _ASM_EXTABLE_EX(from,to) \
- " .pushsection \"__ex_table\",\"a\"\n" \
- " .balign 8\n" \
- " .long (" #from ") - .\n" \
- " .long (" #to ") - . + 0x7ffffff0\n" \
+# define _EXPAND_EXTABLE_BIAS(x) #x
+# define _ASM_EXTABLE_CLASS(from,to,bias) \
+ " .pushsection \"__ex_table\",\"a\"\n" \
+ " .balign 8\n" \
+ " .long (" #from ") - .\n" \
+ " .long (" #to ") - . + " _EXPAND_EXTABLE_BIAS(bias) "\n" \
" .popsection\n"
#endif

+#define _ASM_EXTABLE(from,to) \
+ _ASM_EXTABLE_CLASS(from, to, _EXTABLE_BIAS_DEFAULT)
+
+#define _ASM_EXTABLE_EX(from,to) \
+ _ASM_EXTABLE_CLASS(from, to, _EXTABLE_BIAS_EX)
+
#endif /* _ASM_X86_ASM_H */
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 82e4ae8..85f45d4 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -8,25 +8,34 @@ ex_insn_addr(const struct exception_table_entry *x)
{
return (unsigned long)&x->insn + x->insn;
}
+
+static inline unsigned int
+ex_class(const struct exception_table_entry *x)
+{
+ return (unsigned int)x->fixup & 0xC0000000;
+}
+
static inline unsigned long
ex_fixup_addr(const struct exception_table_entry *x)
{
- return (unsigned long)&x->fixup + x->fixup;
+ long offset = (long)((u32)x->fixup & 0x3fffffff) - (long)0x20000000;
+ return (unsigned long)&x->fixup + offset;
}

int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
unsigned long new_ip;
+ unsigned int class;

fixup = search_exception_tables(regs->ip);
if (fixup) {
+ class = ex_class(fixup);
new_ip = ex_fixup_addr(fixup);

- if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+ if (class == _EXTABLE_CLASS_EX) {
/* Special hack for uaccess_err */
current_thread_info()->uaccess_err = 1;
- new_ip -= 0x7ffffff0;
}
regs->ip = new_ip;
return 1;
@@ -39,18 +48,15 @@ int fixup_exception(struct pt_regs *regs)
int __init early_fixup_exception(unsigned long *ip)
{
const struct exception_table_entry *fixup;
- unsigned long new_ip;

fixup = search_exception_tables(*ip);
if (fixup) {
- new_ip = ex_fixup_addr(fixup);
-
- if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+ if (ex_class(fixup) == _EXTABLE_CLASS_EX) {
/* uaccess handling not supported during early boot */
return 0;
}

- *ip = new_ip;
+ *ip = ex_fixup_addr(fixup);
return 1;
}

--
1.8.1.4

2013-05-22 21:09:04

by Andy Lutomirski

[permalink] [raw]
Subject: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
it's a hack that steals a bit to indicate to other networking code
that a compat entry was used. So don't allow it from a non-compat
syscall.

This prevents an oops when running this code:

int main()
{
int s;
struct sockaddr_in addr;
struct msghdr *hdr;

char *highpage = mmap((void*)(TASK_SIZE_MAX - 4096), 4096,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (highpage == MAP_FAILED)
err(1, "mmap");

s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1)
err(1, "socket");

addr.sin_family = AF_INET;
addr.sin_port = htons(1);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) != 0)
err(1, "connect");

void *evil = highpage + 4096 - COMPAT_MSGHDR_SIZE;
printf("Evil address is %p\n", evil);

if (syscall(__NR_sendmmsg, s, evil, 1, MSG_CMSG_COMPAT) < 0)
err(1, "sendmmsg");

return 0;
}

Cc: David S. Miller <[email protected]>
Signed-off-by: Andy Lutomirski <[email protected]>
---
net/socket.c | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/net/socket.c b/net/socket.c
index 88f759a..0e16888 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2097,8 +2097,12 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, fla
{
int fput_needed, err;
struct msghdr msg_sys;
- struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ struct socket *sock;
+
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;

+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;

@@ -2171,6 +2175,8 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
unsigned int, vlen, unsigned int, flags)
{
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
return __sys_sendmmsg(fd, mmsg, vlen, flags);
}

@@ -2271,8 +2277,12 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
{
int fput_needed, err;
struct msghdr msg_sys;
- struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ struct socket *sock;
+
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;

+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;

@@ -2397,6 +2407,9 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
int datagrams;
struct timespec timeout_sys;

+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
+
if (!timeout)
return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);

@@ -2512,15 +2525,31 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
(int __user *)a[4]);
break;
case SYS_SENDMSG:
+ if (a[2] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
case SYS_SENDMMSG:
+ if (a[3] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
break;
case SYS_RECVMSG:
+ if (a[2] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
case SYS_RECVMMSG:
+ if (a[3] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
(struct timespec __user *)a[4]);
break;
--
1.8.1.4

2013-05-22 21:08:23

by Andy Lutomirski

[permalink] [raw]
Subject: [PATCH 3/5] x86: Annotate _ASM_EXTABLE users to distinguish uaccess from everything else

The idea is that the kernel can be much more careful fixing up
uaccess exceptions -- page faults on user addresses are the only
legitimate reason for a uaccess instruction to fault.

Signed-off-by: Andy Lutomirski <[email protected]>
---

I'm not 100% sure what's happening in the KVM code. Can someone familiar
with it take a look?

arch/x86/ia32/ia32entry.S | 4 +-
arch/x86/include/asm/asm.h | 13 ++-
arch/x86/include/asm/fpu-internal.h | 6 +-
arch/x86/include/asm/futex.h | 8 +-
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/include/asm/msr.h | 4 +-
arch/x86/include/asm/segment.h | 2 +-
arch/x86/include/asm/special_insns.h | 2 +-
arch/x86/include/asm/uaccess.h | 8 +-
arch/x86/include/asm/word-at-a-time.h | 2 +-
arch/x86/include/asm/xsave.h | 6 +-
arch/x86/kernel/entry_32.S | 26 ++---
arch/x86/kernel/entry_64.S | 6 +-
arch/x86/kernel/ftrace.c | 4 +-
arch/x86/kernel/test_nx.c | 2 +-
arch/x86/kernel/test_rodata.c | 2 +-
arch/x86/kvm/emulate.c | 4 +-
arch/x86/lib/checksum_32.S | 4 +-
arch/x86/lib/copy_user_64.S | 50 ++++----
arch/x86/lib/copy_user_nocache_64.S | 44 +++----
arch/x86/lib/csum-copy_64.S | 6 +-
arch/x86/lib/getuser.S | 12 +-
arch/x86/lib/mmx_32.c | 12 +-
arch/x86/lib/msr-reg.S | 4 +-
arch/x86/lib/putuser.S | 10 +-
arch/x86/lib/usercopy_32.c | 212 +++++++++++++++++-----------------
arch/x86/lib/usercopy_64.c | 4 +-
arch/x86/mm/init_32.c | 2 +-
arch/x86/um/checksum_32.S | 4 +-
arch/x86/xen/xen-asm_32.S | 2 +-
30 files changed, 236 insertions(+), 231 deletions(-)

diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 474dc1b..8d3b5c2 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -149,7 +149,7 @@ ENTRY(ia32_sysenter_target)
32bit zero extended */
ASM_STAC
1: movl (%rbp),%ebp
- _ASM_EXTABLE(1b,ia32_badarg)
+ _ASM_EXTABLE_UACCESS(1b,ia32_badarg)
ASM_CLAC
orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
@@ -306,7 +306,7 @@ ENTRY(ia32_cstar_target)
/* hardware stack frame is complete now */
ASM_STAC
1: movl (%r8),%r9d
- _ASM_EXTABLE(1b,ia32_badarg)
+ _ASM_EXTABLE_UACCESS(1b,ia32_badarg)
ASM_CLAC
orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index fa47fd4..f48a850 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -57,14 +57,16 @@
*/

/* There are two bits of extable entry class, added to a signed offset. */
-#define _EXTABLE_CLASS_DEFAULT 0 /* standard uaccess fixup */
+#define _EXTABLE_CLASS_UACCESS 0 /* standard uaccess fixup */
+#define _EXTABLE_CLASS_ANY 0x40000000 /* catch any exception */
#define _EXTABLE_CLASS_EX 0x80000000 /* uaccess + set uaccess_err */

/*
* The biases are the class constants + 0x20000000, as signed integers.
* This can't use ordinary arithmetic -- the assembler isn't that smart.
*/
-#define _EXTABLE_BIAS_DEFAULT 0x20000000
+#define _EXTABLE_BIAS_UACCESS 0x20000000
+#define _EXTABLE_BIAS_ANY 0x20000000 + 0x40000000
#define _EXTABLE_BIAS_EX 0x20000000 - 0x80000000

#ifdef __ASSEMBLY__
@@ -85,8 +87,11 @@
" .popsection\n"
#endif

-#define _ASM_EXTABLE(from,to) \
- _ASM_EXTABLE_CLASS(from, to, _EXTABLE_BIAS_DEFAULT)
+#define _ASM_EXTABLE_UACCESS(from,to) \
+ _ASM_EXTABLE_CLASS(from, to, _EXTABLE_BIAS_UACCESS)
+
+#define _ASM_EXTABLE_ANY(from,to) \
+ _ASM_EXTABLE_CLASS(from, to, _EXTABLE_BIAS_ANY)

#define _ASM_EXTABLE_EX(from,to) \
_ASM_EXTABLE_CLASS(from, to, _EXTABLE_BIAS_EX)
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index e25cc33..7f86031 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -133,7 +133,7 @@ static inline void sanitize_i387_state(struct task_struct *tsk)
"3: movl $-1,%[err]\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_UACCESS(1b, 3b) \
: [err] "=r" (err), output \
: "0"(0), input); \
err; \
@@ -148,7 +148,7 @@ static inline void sanitize_i387_state(struct task_struct *tsk)
"3: movl $-1,%[err]\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_ANY(1b, 3b) \
: [err] "=r" (err), output \
: "0"(0), input); \
err; \
@@ -356,7 +356,7 @@ static inline void __drop_fpu(struct task_struct *tsk)
/* Ignore delayed exceptions from user space */
asm volatile("1: fwait\n"
"2:\n"
- _ASM_EXTABLE(1b, 2b));
+ _ASM_EXTABLE_ANY(1b, 2b));
__thread_fpu_end(tsk);
}
}
diff --git a/arch/x86/include/asm/futex.h b/arch/x86/include/asm/futex.h
index be27ba1..606006c 100644
--- a/arch/x86/include/asm/futex.h
+++ b/arch/x86/include/asm/futex.h
@@ -19,7 +19,7 @@
"3:\tmov\t%3, %1\n" \
"\tjmp\t2b\n" \
"\t.previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_UACCESS(1b, 3b) \
: "=r" (oldval), "=r" (ret), "+m" (*uaddr) \
: "i" (-EFAULT), "0" (oparg), "1" (0))

@@ -35,8 +35,8 @@
"4:\tmov\t%5, %1\n" \
"\tjmp\t3b\n" \
"\t.previous\n" \
- _ASM_EXTABLE(1b, 4b) \
- _ASM_EXTABLE(2b, 4b) \
+ _ASM_EXTABLE_UACCESS(1b, 4b) \
+ _ASM_EXTABLE_UACCESS(2b, 4b) \
: "=&a" (oldval), "=&r" (ret), \
"+m" (*uaddr), "=&r" (tem) \
: "r" (oparg), "i" (-EFAULT), "1" (0))
@@ -122,7 +122,7 @@ static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
"3:\tmov %3, %0\n"
"\tjmp 2b\n"
"\t.previous\n"
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_UACCESS(1b, 3b)
: "+r" (ret), "=a" (oldval), "+m" (*uaddr)
: "i" (-EFAULT), "r" (newval), "1" (oldval)
: "memory"
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 4979778..96c576f 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -986,7 +986,7 @@ extern bool kvm_rebooting;
__ASM_SIZE(push) " $666b \n\t" \
"call kvm_spurious_fault \n\t" \
".popsection \n\t" \
- _ASM_EXTABLE(666b, 667b)
+ _ASM_EXTABLE_ANY(666b, 667b)

#define __kvm_handle_fault_on_reboot(insn) \
____kvm_handle_fault_on_reboot(insn, "")
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 9264802..54e4bea 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -75,7 +75,7 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
".section .fixup,\"ax\"\n\t"
"3: mov %[fault],%[err] ; jmp 1b\n\t"
".previous\n\t"
- _ASM_EXTABLE(2b, 3b)
+ _ASM_EXTABLE_ANY(2b, 3b)
: [err] "=r" (*err), EAX_EDX_RET(val, low, high)
: "c" (msr), [fault] "i" (-EIO));
return EAX_EDX_VAL(val, low, high);
@@ -97,7 +97,7 @@ notrace static inline int native_write_msr_safe(unsigned int msr,
".section .fixup,\"ax\"\n\t"
"3: mov %[fault],%[err] ; jmp 1b\n\t"
".previous\n\t"
- _ASM_EXTABLE(2b, 3b)
+ _ASM_EXTABLE_ANY(2b, 3b)
: [err] "=a" (err)
: "c" (msr), "0" (low), "d" (high),
[fault] "i" (-EIO)
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index c48a950..89cac10 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -231,7 +231,7 @@ do { \
" jmp 1b \n" \
".previous \n" \
\
- _ASM_EXTABLE(1b, 2b) \
+ _ASM_EXTABLE_ANY(1b, 2b) \
\
: "+r" (__val) : : "memory"); \
} while (0)
diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h
index 41fc93a..30b6f01 100644
--- a/arch/x86/include/asm/special_insns.h
+++ b/arch/x86/include/asm/special_insns.h
@@ -69,7 +69,7 @@ static inline unsigned long native_read_cr4_safe(void)
#ifdef CONFIG_X86_32
asm volatile("1: mov %%cr4, %0\n"
"2:\n"
- _ASM_EXTABLE(1b, 2b)
+ _ASM_EXTABLE_ANY(1b, 2b)
: "=r" (val), "=m" (__force_order) : "0" (0));
#else
val = native_read_cr4();
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 5ee2687..ed2d77a 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -188,8 +188,8 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
"4: movl %3,%0\n" \
" jmp 3b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 4b) \
- _ASM_EXTABLE(2b, 4b) \
+ _ASM_EXTABLE_UACCESS(1b, 4b) \
+ _ASM_EXTABLE_UACCESS(2b, 4b) \
: "=r" (err) \
: "A" (x), "r" (addr), "i" (errret), "0" (err))

@@ -352,7 +352,7 @@ do { \
" xor"itype" %"rtype"1,%"rtype"1\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_UACCESS(1b, 3b) \
: "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err))

@@ -416,7 +416,7 @@ struct __large_struct { unsigned long buf[100]; };
"3: mov %3,%0\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_UACCESS(1b, 3b) \
: "=r"(err) \
: ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))

diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h
index 5b238981..aa80911 100644
--- a/arch/x86/include/asm/word-at-a-time.h
+++ b/arch/x86/include/asm/word-at-a-time.h
@@ -94,7 +94,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
"shr %%cl,%0\n\t"
"jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_ANY(1b, 3b)
:"=&r" (ret),"=&c" (dummy)
:"m" (*(unsigned long *)addr),
"i" (-sizeof(unsigned long)),
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index 0415cda..7859666 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -50,7 +50,7 @@ static inline int fpu_xrstor_checking(struct xsave_struct *fx)
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_ANY(1b, 3b)
: [err] "=r" (err)
: "D" (fx), "m" (*fx), "a" (-1), "d" (-1), "0" (0)
: "memory");
@@ -77,7 +77,7 @@ static inline int xsave_user(struct xsave_struct __user *buf)
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b,3b)
+ _ASM_EXTABLE_UACCESS(1b,3b)
: [err] "=r" (err)
: "D" (buf), "a" (-1), "d" (-1), "0" (0)
: "memory");
@@ -98,7 +98,7 @@ static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b,3b)
+ _ASM_EXTABLE_UACCESS(1b,3b)
: [err] "=r" (err)
: "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
: "memory"); /* memory required? */
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 8f3e2de..fc85bb9 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -154,7 +154,7 @@
99: movl $0, (%esp)
jmp 98b
.popsection
- _ASM_EXTABLE(98b,99b)
+ _ASM_EXTABLE_ANY(98b,99b)
.endm

.macro PTGS_TO_GS
@@ -165,7 +165,7 @@
99: movl $0, PT_GS(%esp)
jmp 98b
.popsection
- _ASM_EXTABLE(98b,99b)
+ _ASM_EXTABLE_ANY(98b,99b)
.endm

.macro GS_TO_REG reg
@@ -248,9 +248,9 @@
6: movl $0, (%esp)
jmp 3b
.popsection
- _ASM_EXTABLE(1b,4b)
- _ASM_EXTABLE(2b,5b)
- _ASM_EXTABLE(3b,6b)
+ _ASM_EXTABLE_ANY(1b,4b)
+ _ASM_EXTABLE_ANY(2b,5b)
+ _ASM_EXTABLE_ANY(3b,6b)
POP_GS_EX
.endm

@@ -426,7 +426,7 @@ sysenter_past_esp:
1: movl (%ebp),%ebp
ASM_CLAC
movl %ebp,PT_EBP(%esp)
- _ASM_EXTABLE(1b,syscall_fault)
+ _ASM_EXTABLE_UACCESS(1b,syscall_fault)

GET_THREAD_INFO(%ebp)

@@ -494,7 +494,7 @@ sysexit_audit:
2: movl $0,PT_FS(%esp)
jmp 1b
.popsection
- _ASM_EXTABLE(1b,2b)
+ _ASM_EXTABLE_ANY(1b,2b)
PTGS_TO_GS_EX
ENDPROC(ia32_sysenter_target)

@@ -550,7 +550,7 @@ ENTRY(iret_exc)
pushl $do_iret_error
jmp error_code
.previous
- _ASM_EXTABLE(irq_return,iret_exc)
+ _ASM_EXTABLE_ANY(irq_return,iret_exc)

CFI_RESTORE_STATE
ldt_ss:
@@ -849,7 +849,7 @@ END(device_not_available)
#ifdef CONFIG_PARAVIRT
ENTRY(native_iret)
iret
- _ASM_EXTABLE(native_iret, iret_exc)
+ _ASM_EXTABLE_ANY(native_iret, iret_exc)
END(native_iret)

ENTRY(native_irq_enable_sysexit)
@@ -1040,10 +1040,10 @@ ENTRY(xen_failsafe_callback)
movl %eax,16(%esp)
jmp 4b
.previous
- _ASM_EXTABLE(1b,6b)
- _ASM_EXTABLE(2b,7b)
- _ASM_EXTABLE(3b,8b)
- _ASM_EXTABLE(4b,9b)
+ _ASM_EXTABLE_ANY(1b,6b)
+ _ASM_EXTABLE_ANY(2b,7b)
+ _ASM_EXTABLE_ANY(3b,8b)
+ _ASM_EXTABLE_ANY(4b,9b)
ENDPROC(xen_failsafe_callback)

BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR,
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index c1d01e6..be185cd 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -1056,12 +1056,12 @@ restore_args:

irq_return:
INTERRUPT_RETURN
- _ASM_EXTABLE(irq_return, bad_iret)
+ _ASM_EXTABLE_ANY(irq_return, bad_iret)

#ifdef CONFIG_PARAVIRT
ENTRY(native_iret)
iretq
- _ASM_EXTABLE(native_iret, bad_iret)
+ _ASM_EXTABLE_ANY(native_iret, bad_iret)
#endif

.section .fixup,"ax"
@@ -1319,7 +1319,7 @@ gs_change:
CFI_ENDPROC
END(native_load_gs_index)

- _ASM_EXTABLE(gs_change,bad_gs)
+ _ASM_EXTABLE_ANY(gs_change,bad_gs)
.section .fixup,"ax"
/* running with kernelgs */
bad_gs:
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 42a392a..c6c4ebf 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -740,8 +740,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
" jmp 3b\n"
".previous\n"

- _ASM_EXTABLE(1b, 4b)
- _ASM_EXTABLE(2b, 4b)
+ _ASM_EXTABLE_ANY(1b, 4b)
+ _ASM_EXTABLE_ANY(2b, 4b)

: [old] "=&r" (old), [faulted] "=r" (faulted)
: [parent] "r" (parent), [return_hooker] "r" (return_hooker)
diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c
index 3f92ce0..770cb68 100644
--- a/arch/x86/kernel/test_nx.c
+++ b/arch/x86/kernel/test_nx.c
@@ -92,7 +92,7 @@ static noinline int test_address(void *address)
"2: mov %[zero], %[rslt]\n"
" ret\n"
".previous\n"
- _ASM_EXTABLE(0b,2b)
+ _ASM_EXTABLE_ANY(0b,2b)
: [rslt] "=r" (result)
: [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
);
diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c
index b79133a..624e6af 100644
--- a/arch/x86/kernel/test_rodata.c
+++ b/arch/x86/kernel/test_rodata.c
@@ -43,7 +43,7 @@ int rodata_test(void)
".section .fixup,\"ax\"\n"
"2: jmp 1b\n"
".previous\n"
- _ASM_EXTABLE(0b,2b)
+ _ASM_EXTABLE_ANY(0b,2b)
: [rslt] "=r" (result)
: [rodata_test] "r" (&rodata_test_data), [zero] "r" (0UL)
);
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index a9c9d3e..fa7f66a 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -548,7 +548,7 @@ FOP_END;
"3: movb $1, %4 \n\t" \
"jmp 2b \n\t" \
".popsection \n\t" \
- _ASM_EXTABLE(1b, 3b) \
+ _ASM_EXTABLE_UACCESS(1b, 3b) \
: "=m" ((ctxt)->eflags), "=&r" (_tmp), \
"+a" (*rax), "+d" (*rdx), "+qm"(_ex) \
: "i" (EFLAGS_MASK), "m" ((ctxt)->src.val)); \
@@ -4479,7 +4479,7 @@ static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt)
"movb $1, %[fault] \n\t"
"jmp 2b \n\t"
".popsection \n\t"
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_ANY(1b, 3b)
: [fault]"+qm"(fault));
ctxt->ops->put_fpu(ctxt);

diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S
index 2af5df3..20523f0 100644
--- a/arch/x86/lib/checksum_32.S
+++ b/arch/x86/lib/checksum_32.S
@@ -283,11 +283,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,

#define SRC(y...) \
9999: y; \
- _ASM_EXTABLE(9999b, 6001f)
+ _ASM_EXTABLE_UACCESS(9999b, 6001f)

#define DST(y...) \
9999: y; \
- _ASM_EXTABLE(9999b, 6002f)
+ _ASM_EXTABLE_UACCESS(9999b, 6002f)

#ifndef CONFIG_X86_USE_PPRO_CHECKSUM

diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index a30ca15..20c0258 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -65,8 +65,8 @@
jmp copy_user_handle_tail
.previous

- _ASM_EXTABLE(100b,103b)
- _ASM_EXTABLE(101b,103b)
+ _ASM_EXTABLE_UACCESS(100b,103b)
+ _ASM_EXTABLE_UACCESS(101b,103b)
#endif
.endm

@@ -192,26 +192,26 @@ ENTRY(copy_user_generic_unrolled)
60: jmp copy_user_handle_tail /* ecx is zerorest also */
.previous

- _ASM_EXTABLE(1b,30b)
- _ASM_EXTABLE(2b,30b)
- _ASM_EXTABLE(3b,30b)
- _ASM_EXTABLE(4b,30b)
- _ASM_EXTABLE(5b,30b)
- _ASM_EXTABLE(6b,30b)
- _ASM_EXTABLE(7b,30b)
- _ASM_EXTABLE(8b,30b)
- _ASM_EXTABLE(9b,30b)
- _ASM_EXTABLE(10b,30b)
- _ASM_EXTABLE(11b,30b)
- _ASM_EXTABLE(12b,30b)
- _ASM_EXTABLE(13b,30b)
- _ASM_EXTABLE(14b,30b)
- _ASM_EXTABLE(15b,30b)
- _ASM_EXTABLE(16b,30b)
- _ASM_EXTABLE(18b,40b)
- _ASM_EXTABLE(19b,40b)
- _ASM_EXTABLE(21b,50b)
- _ASM_EXTABLE(22b,50b)
+ _ASM_EXTABLE_UACCESS(1b,30b)
+ _ASM_EXTABLE_UACCESS(2b,30b)
+ _ASM_EXTABLE_UACCESS(3b,30b)
+ _ASM_EXTABLE_UACCESS(4b,30b)
+ _ASM_EXTABLE_UACCESS(5b,30b)
+ _ASM_EXTABLE_UACCESS(6b,30b)
+ _ASM_EXTABLE_UACCESS(7b,30b)
+ _ASM_EXTABLE_UACCESS(8b,30b)
+ _ASM_EXTABLE_UACCESS(9b,30b)
+ _ASM_EXTABLE_UACCESS(10b,30b)
+ _ASM_EXTABLE_UACCESS(11b,30b)
+ _ASM_EXTABLE_UACCESS(12b,30b)
+ _ASM_EXTABLE_UACCESS(13b,30b)
+ _ASM_EXTABLE_UACCESS(14b,30b)
+ _ASM_EXTABLE_UACCESS(15b,30b)
+ _ASM_EXTABLE_UACCESS(16b,30b)
+ _ASM_EXTABLE_UACCESS(18b,40b)
+ _ASM_EXTABLE_UACCESS(19b,40b)
+ _ASM_EXTABLE_UACCESS(21b,50b)
+ _ASM_EXTABLE_UACCESS(22b,50b)
CFI_ENDPROC
ENDPROC(copy_user_generic_unrolled)

@@ -259,8 +259,8 @@ ENTRY(copy_user_generic_string)
jmp copy_user_handle_tail
.previous

- _ASM_EXTABLE(1b,11b)
- _ASM_EXTABLE(3b,12b)
+ _ASM_EXTABLE_UACCESS(1b,11b)
+ _ASM_EXTABLE_UACCESS(3b,12b)
CFI_ENDPROC
ENDPROC(copy_user_generic_string)

@@ -293,6 +293,6 @@ ENTRY(copy_user_enhanced_fast_string)
jmp copy_user_handle_tail
.previous

- _ASM_EXTABLE(1b,12b)
+ _ASM_EXTABLE_UACCESS(1b,12b)
CFI_ENDPROC
ENDPROC(copy_user_enhanced_fast_string)
diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S
index 6a4f43c..c9b8193 100644
--- a/arch/x86/lib/copy_user_nocache_64.S
+++ b/arch/x86/lib/copy_user_nocache_64.S
@@ -38,8 +38,8 @@
jmp copy_user_handle_tail
.previous

- _ASM_EXTABLE(100b,103b)
- _ASM_EXTABLE(101b,103b)
+ _ASM_EXTABLE_UACCESS(100b,103b)
+ _ASM_EXTABLE_UACCESS(101b,103b)
#endif
.endm

@@ -112,25 +112,25 @@ ENTRY(__copy_user_nocache)
jmp copy_user_handle_tail
.previous

- _ASM_EXTABLE(1b,30b)
- _ASM_EXTABLE(2b,30b)
- _ASM_EXTABLE(3b,30b)
- _ASM_EXTABLE(4b,30b)
- _ASM_EXTABLE(5b,30b)
- _ASM_EXTABLE(6b,30b)
- _ASM_EXTABLE(7b,30b)
- _ASM_EXTABLE(8b,30b)
- _ASM_EXTABLE(9b,30b)
- _ASM_EXTABLE(10b,30b)
- _ASM_EXTABLE(11b,30b)
- _ASM_EXTABLE(12b,30b)
- _ASM_EXTABLE(13b,30b)
- _ASM_EXTABLE(14b,30b)
- _ASM_EXTABLE(15b,30b)
- _ASM_EXTABLE(16b,30b)
- _ASM_EXTABLE(18b,40b)
- _ASM_EXTABLE(19b,40b)
- _ASM_EXTABLE(21b,50b)
- _ASM_EXTABLE(22b,50b)
+ _ASM_EXTABLE_UACCESS(1b,30b)
+ _ASM_EXTABLE_UACCESS(2b,30b)
+ _ASM_EXTABLE_UACCESS(3b,30b)
+ _ASM_EXTABLE_UACCESS(4b,30b)
+ _ASM_EXTABLE_UACCESS(5b,30b)
+ _ASM_EXTABLE_UACCESS(6b,30b)
+ _ASM_EXTABLE_UACCESS(7b,30b)
+ _ASM_EXTABLE_UACCESS(8b,30b)
+ _ASM_EXTABLE_UACCESS(9b,30b)
+ _ASM_EXTABLE_UACCESS(10b,30b)
+ _ASM_EXTABLE_UACCESS(11b,30b)
+ _ASM_EXTABLE_UACCESS(12b,30b)
+ _ASM_EXTABLE_UACCESS(13b,30b)
+ _ASM_EXTABLE_UACCESS(14b,30b)
+ _ASM_EXTABLE_UACCESS(15b,30b)
+ _ASM_EXTABLE_UACCESS(16b,30b)
+ _ASM_EXTABLE_UACCESS(18b,40b)
+ _ASM_EXTABLE_UACCESS(19b,40b)
+ _ASM_EXTABLE_UACCESS(21b,50b)
+ _ASM_EXTABLE_UACCESS(22b,50b)
CFI_ENDPROC
ENDPROC(__copy_user_nocache)
diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S
index 2419d5f..e6ecfc9 100644
--- a/arch/x86/lib/csum-copy_64.S
+++ b/arch/x86/lib/csum-copy_64.S
@@ -32,17 +32,17 @@

.macro source
10:
- _ASM_EXTABLE(10b, .Lbad_source)
+ _ASM_EXTABLE_UACCESS(10b, .Lbad_source)
.endm

.macro dest
20:
- _ASM_EXTABLE(20b, .Lbad_dest)
+ _ASM_EXTABLE_UACCESS(20b, .Lbad_dest)
.endm

.macro ignore L=.Lignore
30:
- _ASM_EXTABLE(30b, \L)
+ _ASM_EXTABLE_UACCESS(30b, \L)
.endm


diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index a451235..8f15607 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -129,12 +129,12 @@ bad_get_user_8:
END(bad_get_user_8)
#endif

- _ASM_EXTABLE(1b,bad_get_user)
- _ASM_EXTABLE(2b,bad_get_user)
- _ASM_EXTABLE(3b,bad_get_user)
+ _ASM_EXTABLE_UACCESS(1b,bad_get_user)
+ _ASM_EXTABLE_UACCESS(2b,bad_get_user)
+ _ASM_EXTABLE_UACCESS(3b,bad_get_user)
#ifdef CONFIG_X86_64
- _ASM_EXTABLE(4b,bad_get_user)
+ _ASM_EXTABLE_UACCESS(4b,bad_get_user)
#else
- _ASM_EXTABLE(4b,bad_get_user_8)
- _ASM_EXTABLE(5b,bad_get_user_8)
+ _ASM_EXTABLE_UACCESS(4b,bad_get_user_8)
+ _ASM_EXTABLE_UACCESS(5b,bad_get_user_8)
#endif
diff --git a/arch/x86/lib/mmx_32.c b/arch/x86/lib/mmx_32.c
index c9f2d9b..d1a21f7 100644
--- a/arch/x86/lib/mmx_32.c
+++ b/arch/x86/lib/mmx_32.c
@@ -49,7 +49,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len)
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_UACCESS(1b, 3b)
: : "r" (from));

for ( ; i > 5; i--) {
@@ -75,7 +75,7 @@ void *_mmx_memcpy(void *to, const void *from, size_t len)
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_UACCESS(1b, 3b)
: : "r" (from), "r" (to) : "memory");

from += 64;
@@ -176,7 +176,7 @@ static void fast_copy_page(void *to, void *from)
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b) : : "r" (from));
+ _ASM_EXTABLE_UACCESS(1b, 3b) : : "r" (from));

for (i = 0; i < (4096-320)/64; i++) {
__asm__ __volatile__ (
@@ -201,7 +201,7 @@ static void fast_copy_page(void *to, void *from)
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b) : : "r" (from), "r" (to) : "memory");
+ _ASM_EXTABLE_UACCESS(1b, 3b) : : "r" (from), "r" (to) : "memory");

from += 64;
to += 64;
@@ -294,7 +294,7 @@ static void fast_copy_page(void *to, void *from)
"3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b) : : "r" (from));
+ _ASM_EXTABLE_UACCESS(1b, 3b) : : "r" (from));

for (i = 0; i < 4096/64; i++) {
__asm__ __volatile__ (
@@ -319,7 +319,7 @@ static void fast_copy_page(void *to, void *from)
"3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_UACCESS(1b, 3b)
: : "r" (from), "r" (to) : "memory");

from += 64;
diff --git a/arch/x86/lib/msr-reg.S b/arch/x86/lib/msr-reg.S
index f6d13ee..ded3bd5 100644
--- a/arch/x86/lib/msr-reg.S
+++ b/arch/x86/lib/msr-reg.S
@@ -43,7 +43,7 @@ ENTRY(\op\()_safe_regs)
movl $-EIO, %r11d
jmp 2b

- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_ANY(1b, 3b)
CFI_ENDPROC
ENDPROC(\op\()_safe_regs)
.endm
@@ -90,7 +90,7 @@ ENTRY(\op\()_safe_regs)
movl $-EIO, 4(%esp)
jmp 2b

- _ASM_EXTABLE(1b, 3b)
+ _ASM_EXTABLE_ANY(1b, 3b)
CFI_ENDPROC
ENDPROC(\op\()_safe_regs)
.endm
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
index fc6ba17..b2fbb72 100644
--- a/arch/x86/lib/putuser.S
+++ b/arch/x86/lib/putuser.S
@@ -92,10 +92,10 @@ bad_put_user:
EXIT
END(bad_put_user)

- _ASM_EXTABLE(1b,bad_put_user)
- _ASM_EXTABLE(2b,bad_put_user)
- _ASM_EXTABLE(3b,bad_put_user)
- _ASM_EXTABLE(4b,bad_put_user)
+ _ASM_EXTABLE_UACCESS(1b,bad_put_user)
+ _ASM_EXTABLE_UACCESS(2b,bad_put_user)
+ _ASM_EXTABLE_UACCESS(3b,bad_put_user)
+ _ASM_EXTABLE_UACCESS(4b,bad_put_user)
#ifdef CONFIG_X86_32
- _ASM_EXTABLE(5b,bad_put_user)
+ _ASM_EXTABLE_UACCESS(5b,bad_put_user)
#endif
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index f0312d7..0884951 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -51,8 +51,8 @@ do { \
"3: lea 0(%2,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(0b,3b) \
- _ASM_EXTABLE(1b,2b) \
+ _ASM_EXTABLE_UACCESS(0b,3b) \
+ _ASM_EXTABLE_UACCESS(1b,2b) \
: "=&c"(size), "=&D" (__d0) \
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
} while (0)
@@ -157,44 +157,44 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size)
"101: lea 0(%%eax,%0,4),%0\n"
" jmp 100b\n"
".previous\n"
- _ASM_EXTABLE(1b,100b)
- _ASM_EXTABLE(2b,100b)
- _ASM_EXTABLE(3b,100b)
- _ASM_EXTABLE(4b,100b)
- _ASM_EXTABLE(5b,100b)
- _ASM_EXTABLE(6b,100b)
- _ASM_EXTABLE(7b,100b)
- _ASM_EXTABLE(8b,100b)
- _ASM_EXTABLE(9b,100b)
- _ASM_EXTABLE(10b,100b)
- _ASM_EXTABLE(11b,100b)
- _ASM_EXTABLE(12b,100b)
- _ASM_EXTABLE(13b,100b)
- _ASM_EXTABLE(14b,100b)
- _ASM_EXTABLE(15b,100b)
- _ASM_EXTABLE(16b,100b)
- _ASM_EXTABLE(17b,100b)
- _ASM_EXTABLE(18b,100b)
- _ASM_EXTABLE(19b,100b)
- _ASM_EXTABLE(20b,100b)
- _ASM_EXTABLE(21b,100b)
- _ASM_EXTABLE(22b,100b)
- _ASM_EXTABLE(23b,100b)
- _ASM_EXTABLE(24b,100b)
- _ASM_EXTABLE(25b,100b)
- _ASM_EXTABLE(26b,100b)
- _ASM_EXTABLE(27b,100b)
- _ASM_EXTABLE(28b,100b)
- _ASM_EXTABLE(29b,100b)
- _ASM_EXTABLE(30b,100b)
- _ASM_EXTABLE(31b,100b)
- _ASM_EXTABLE(32b,100b)
- _ASM_EXTABLE(33b,100b)
- _ASM_EXTABLE(34b,100b)
- _ASM_EXTABLE(35b,100b)
- _ASM_EXTABLE(36b,100b)
- _ASM_EXTABLE(37b,100b)
- _ASM_EXTABLE(99b,101b)
+ _ASM_EXTABLE_UACCESS(1b,100b)
+ _ASM_EXTABLE_UACCESS(2b,100b)
+ _ASM_EXTABLE_UACCESS(3b,100b)
+ _ASM_EXTABLE_UACCESS(4b,100b)
+ _ASM_EXTABLE_UACCESS(5b,100b)
+ _ASM_EXTABLE_UACCESS(6b,100b)
+ _ASM_EXTABLE_UACCESS(7b,100b)
+ _ASM_EXTABLE_UACCESS(8b,100b)
+ _ASM_EXTABLE_UACCESS(9b,100b)
+ _ASM_EXTABLE_UACCESS(10b,100b)
+ _ASM_EXTABLE_UACCESS(11b,100b)
+ _ASM_EXTABLE_UACCESS(12b,100b)
+ _ASM_EXTABLE_UACCESS(13b,100b)
+ _ASM_EXTABLE_UACCESS(14b,100b)
+ _ASM_EXTABLE_UACCESS(15b,100b)
+ _ASM_EXTABLE_UACCESS(16b,100b)
+ _ASM_EXTABLE_UACCESS(17b,100b)
+ _ASM_EXTABLE_UACCESS(18b,100b)
+ _ASM_EXTABLE_UACCESS(19b,100b)
+ _ASM_EXTABLE_UACCESS(20b,100b)
+ _ASM_EXTABLE_UACCESS(21b,100b)
+ _ASM_EXTABLE_UACCESS(22b,100b)
+ _ASM_EXTABLE_UACCESS(23b,100b)
+ _ASM_EXTABLE_UACCESS(24b,100b)
+ _ASM_EXTABLE_UACCESS(25b,100b)
+ _ASM_EXTABLE_UACCESS(26b,100b)
+ _ASM_EXTABLE_UACCESS(27b,100b)
+ _ASM_EXTABLE_UACCESS(28b,100b)
+ _ASM_EXTABLE_UACCESS(29b,100b)
+ _ASM_EXTABLE_UACCESS(30b,100b)
+ _ASM_EXTABLE_UACCESS(31b,100b)
+ _ASM_EXTABLE_UACCESS(32b,100b)
+ _ASM_EXTABLE_UACCESS(33b,100b)
+ _ASM_EXTABLE_UACCESS(34b,100b)
+ _ASM_EXTABLE_UACCESS(35b,100b)
+ _ASM_EXTABLE_UACCESS(36b,100b)
+ _ASM_EXTABLE_UACCESS(37b,100b)
+ _ASM_EXTABLE_UACCESS(99b,101b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -267,26 +267,26 @@ __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size)
" popl %0\n"
" jmp 8b\n"
".previous\n"
- _ASM_EXTABLE(0b,16b)
- _ASM_EXTABLE(1b,16b)
- _ASM_EXTABLE(2b,16b)
- _ASM_EXTABLE(21b,16b)
- _ASM_EXTABLE(3b,16b)
- _ASM_EXTABLE(31b,16b)
- _ASM_EXTABLE(4b,16b)
- _ASM_EXTABLE(41b,16b)
- _ASM_EXTABLE(10b,16b)
- _ASM_EXTABLE(51b,16b)
- _ASM_EXTABLE(11b,16b)
- _ASM_EXTABLE(61b,16b)
- _ASM_EXTABLE(12b,16b)
- _ASM_EXTABLE(71b,16b)
- _ASM_EXTABLE(13b,16b)
- _ASM_EXTABLE(81b,16b)
- _ASM_EXTABLE(14b,16b)
- _ASM_EXTABLE(91b,16b)
- _ASM_EXTABLE(6b,9b)
- _ASM_EXTABLE(7b,16b)
+ _ASM_EXTABLE_UACCESS(0b,16b)
+ _ASM_EXTABLE_UACCESS(1b,16b)
+ _ASM_EXTABLE_UACCESS(2b,16b)
+ _ASM_EXTABLE_UACCESS(21b,16b)
+ _ASM_EXTABLE_UACCESS(3b,16b)
+ _ASM_EXTABLE_UACCESS(31b,16b)
+ _ASM_EXTABLE_UACCESS(4b,16b)
+ _ASM_EXTABLE_UACCESS(41b,16b)
+ _ASM_EXTABLE_UACCESS(10b,16b)
+ _ASM_EXTABLE_UACCESS(51b,16b)
+ _ASM_EXTABLE_UACCESS(11b,16b)
+ _ASM_EXTABLE_UACCESS(61b,16b)
+ _ASM_EXTABLE_UACCESS(12b,16b)
+ _ASM_EXTABLE_UACCESS(71b,16b)
+ _ASM_EXTABLE_UACCESS(13b,16b)
+ _ASM_EXTABLE_UACCESS(81b,16b)
+ _ASM_EXTABLE_UACCESS(14b,16b)
+ _ASM_EXTABLE_UACCESS(91b,16b)
+ _ASM_EXTABLE_UACCESS(6b,9b)
+ _ASM_EXTABLE_UACCESS(7b,16b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -366,26 +366,26 @@ static unsigned long __copy_user_zeroing_intel_nocache(void *to,
" popl %0\n"
" jmp 8b\n"
".previous\n"
- _ASM_EXTABLE(0b,16b)
- _ASM_EXTABLE(1b,16b)
- _ASM_EXTABLE(2b,16b)
- _ASM_EXTABLE(21b,16b)
- _ASM_EXTABLE(3b,16b)
- _ASM_EXTABLE(31b,16b)
- _ASM_EXTABLE(4b,16b)
- _ASM_EXTABLE(41b,16b)
- _ASM_EXTABLE(10b,16b)
- _ASM_EXTABLE(51b,16b)
- _ASM_EXTABLE(11b,16b)
- _ASM_EXTABLE(61b,16b)
- _ASM_EXTABLE(12b,16b)
- _ASM_EXTABLE(71b,16b)
- _ASM_EXTABLE(13b,16b)
- _ASM_EXTABLE(81b,16b)
- _ASM_EXTABLE(14b,16b)
- _ASM_EXTABLE(91b,16b)
- _ASM_EXTABLE(6b,9b)
- _ASM_EXTABLE(7b,16b)
+ _ASM_EXTABLE_UACCESS(0b,16b)
+ _ASM_EXTABLE_UACCESS(1b,16b)
+ _ASM_EXTABLE_UACCESS(2b,16b)
+ _ASM_EXTABLE_UACCESS(21b,16b)
+ _ASM_EXTABLE_UACCESS(3b,16b)
+ _ASM_EXTABLE_UACCESS(31b,16b)
+ _ASM_EXTABLE_UACCESS(4b,16b)
+ _ASM_EXTABLE_UACCESS(41b,16b)
+ _ASM_EXTABLE_UACCESS(10b,16b)
+ _ASM_EXTABLE_UACCESS(51b,16b)
+ _ASM_EXTABLE_UACCESS(11b,16b)
+ _ASM_EXTABLE_UACCESS(61b,16b)
+ _ASM_EXTABLE_UACCESS(12b,16b)
+ _ASM_EXTABLE_UACCESS(71b,16b)
+ _ASM_EXTABLE_UACCESS(13b,16b)
+ _ASM_EXTABLE_UACCESS(81b,16b)
+ _ASM_EXTABLE_UACCESS(14b,16b)
+ _ASM_EXTABLE_UACCESS(91b,16b)
+ _ASM_EXTABLE_UACCESS(6b,9b)
+ _ASM_EXTABLE_UACCESS(7b,16b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -454,26 +454,26 @@ static unsigned long __copy_user_intel_nocache(void *to,
"9: lea 0(%%eax,%0,4),%0\n"
"16: jmp 8b\n"
".previous\n"
- _ASM_EXTABLE(0b,16b)
- _ASM_EXTABLE(1b,16b)
- _ASM_EXTABLE(2b,16b)
- _ASM_EXTABLE(21b,16b)
- _ASM_EXTABLE(3b,16b)
- _ASM_EXTABLE(31b,16b)
- _ASM_EXTABLE(4b,16b)
- _ASM_EXTABLE(41b,16b)
- _ASM_EXTABLE(10b,16b)
- _ASM_EXTABLE(51b,16b)
- _ASM_EXTABLE(11b,16b)
- _ASM_EXTABLE(61b,16b)
- _ASM_EXTABLE(12b,16b)
- _ASM_EXTABLE(71b,16b)
- _ASM_EXTABLE(13b,16b)
- _ASM_EXTABLE(81b,16b)
- _ASM_EXTABLE(14b,16b)
- _ASM_EXTABLE(91b,16b)
- _ASM_EXTABLE(6b,9b)
- _ASM_EXTABLE(7b,16b)
+ _ASM_EXTABLE_UACCESS(0b,16b)
+ _ASM_EXTABLE_UACCESS(1b,16b)
+ _ASM_EXTABLE_UACCESS(2b,16b)
+ _ASM_EXTABLE_UACCESS(21b,16b)
+ _ASM_EXTABLE_UACCESS(3b,16b)
+ _ASM_EXTABLE_UACCESS(31b,16b)
+ _ASM_EXTABLE_UACCESS(4b,16b)
+ _ASM_EXTABLE_UACCESS(41b,16b)
+ _ASM_EXTABLE_UACCESS(10b,16b)
+ _ASM_EXTABLE_UACCESS(51b,16b)
+ _ASM_EXTABLE_UACCESS(11b,16b)
+ _ASM_EXTABLE_UACCESS(61b,16b)
+ _ASM_EXTABLE_UACCESS(12b,16b)
+ _ASM_EXTABLE_UACCESS(71b,16b)
+ _ASM_EXTABLE_UACCESS(13b,16b)
+ _ASM_EXTABLE_UACCESS(81b,16b)
+ _ASM_EXTABLE_UACCESS(14b,16b)
+ _ASM_EXTABLE_UACCESS(91b,16b)
+ _ASM_EXTABLE_UACCESS(6b,9b)
+ _ASM_EXTABLE_UACCESS(7b,16b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -520,9 +520,9 @@ do { \
"3: lea 0(%3,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(4b,5b) \
- _ASM_EXTABLE(0b,3b) \
- _ASM_EXTABLE(1b,2b) \
+ _ASM_EXTABLE_UACCESS(4b,5b) \
+ _ASM_EXTABLE_UACCESS(0b,3b) \
+ _ASM_EXTABLE_UACCESS(1b,2b) \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \
@@ -559,9 +559,9 @@ do { \
" popl %0\n" \
" jmp 2b\n" \
".previous\n" \
- _ASM_EXTABLE(4b,5b) \
- _ASM_EXTABLE(0b,3b) \
- _ASM_EXTABLE(1b,6b) \
+ _ASM_EXTABLE_UACCESS(4b,5b) \
+ _ASM_EXTABLE_UACCESS(0b,3b) \
+ _ASM_EXTABLE_UACCESS(1b,6b) \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c
index 906fea3..bcc15a1 100644
--- a/arch/x86/lib/usercopy_64.c
+++ b/arch/x86/lib/usercopy_64.c
@@ -36,8 +36,8 @@ unsigned long __clear_user(void __user *addr, unsigned long size)
"3: lea 0(%[size1],%[size8],8),%[size8]\n"
" jmp 2b\n"
".previous\n"
- _ASM_EXTABLE(0b,3b)
- _ASM_EXTABLE(1b,2b)
+ _ASM_EXTABLE_UACCESS(0b,3b)
+ _ASM_EXTABLE_UACCESS(1b,2b)
: [size8] "=&c"(size), [dst] "=&D" (__d0)
: [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
[zero] "r" (0UL), [eight] "r" (8UL));
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 2d19001..47471d0 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -890,7 +890,7 @@ static noinline int do_test_wp_bit(void)
"1: movb %1, %0 \n"
" xorl %2, %2 \n"
"2: \n"
- _ASM_EXTABLE(1b,2b)
+ _ASM_EXTABLE_ANY(1b,2b)
:"=m" (*(char *)fix_to_virt(FIX_WP_TEST)),
"=q" (tmp_reg),
"=r" (flag)
diff --git a/arch/x86/um/checksum_32.S b/arch/x86/um/checksum_32.S
index 8d0c420..30289b8 100644
--- a/arch/x86/um/checksum_32.S
+++ b/arch/x86/um/checksum_32.S
@@ -233,11 +233,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,

#define SRC(y...) \
9999: y; \
- _ASM_EXTABLE(9999b, 6001f)
+ _ASM_EXTABLE_UACCESS(9999b, 6001f)

#define DST(y...) \
9999: y; \
- _ASM_EXTABLE(9999b, 6002f)
+ _ASM_EXTABLE_UACCESS(9999b, 6002f)

.align 4

diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index 33ca6e4..57c63ac 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -138,7 +138,7 @@ iret_restore_end:

1: iret
xen_iret_end_crit:
- _ASM_EXTABLE(1b, iret_exc)
+ _ASM_EXTABLE_ANY(1b, iret_exc)

hyper_iret:
/* put this out of line since its very rarely used */
--
1.8.1.4

2013-05-22 21:09:44

by Andy Lutomirski

[permalink] [raw]
Subject: [PATCH 4/5] x86: Don't fixup uaccess faults to kernel or non-canonical addresses

These don't inherently cause crashes, but they're bugs and, if
there's one triggerable from userspace, it can be used to probe
KASLR.

Signed-off-by: Andy Lutomirski <[email protected]>
---

I don't know what the kprobes code is doing, so I made the conservative
change. This can probably be improved.

Kprobes people: what does this code do?

arch/x86/include/asm/uaccess.h | 2 +-
arch/x86/kernel/kprobes/core.c | 4 +++-
arch/x86/kernel/traps.c | 10 +++++++---
arch/x86/mm/extable.c | 7 +++++--
arch/x86/mm/fault.c | 17 ++++++++++-------
5 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index ed2d77a..a2a92d8 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -101,7 +101,7 @@ struct exception_table_entry {
#define ARCH_HAS_SORT_EXTABLE
#define ARCH_HAS_SEARCH_EXTABLE

-extern int fixup_exception(struct pt_regs *regs);
+extern int fixup_exception(struct pt_regs *regs, bool uaccess_ok);
extern int early_fixup_exception(unsigned long *ip);

/*
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 7bfe318..64932d2 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -927,8 +927,10 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
/*
* In case the user-specified fault handler returned
* zero, try to fix up.
+ *
+ * XXX: This could be much more conservative.
*/
- if (fixup_exception(regs))
+ if (fixup_exception(regs, true))
return 1;

/*
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 8647670..a9453b0 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -124,7 +124,7 @@ do_trap_no_signal(struct task_struct *tsk, int trapnr, char *str,
}
#endif
if (!user_mode(regs)) {
- if (!fixup_exception(regs)) {
+ if (!fixup_exception(regs, false)) {
tsk->thread.error_code = error_code;
tsk->thread.trap_nr = trapnr;
die(str, regs, error_code);
@@ -277,7 +277,11 @@ do_general_protection(struct pt_regs *regs, long error_code)
if (!user_mode(regs)) {
fixup_pnpbios_exception(regs); /* Might not return */

- if (fixup_exception(regs))
+ /*
+ * This could be a non-canonical address in uaccess. If so,
+ * this is bad.
+ */
+ if (fixup_exception(regs, false))
goto exit;

tsk->thread.error_code = error_code;
@@ -491,7 +495,7 @@ void math_error(struct pt_regs *regs, int error_code, int trapnr)

if (!user_mode_vm(regs))
{
- if (!fixup_exception(regs)) {
+ if (!fixup_exception(regs, false)) {
task->thread.error_code = error_code;
task->thread.trap_nr = trapnr;
die(str, regs, error_code);
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 85f45d4..05e078a 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -22,7 +22,7 @@ ex_fixup_addr(const struct exception_table_entry *x)
return (unsigned long)&x->fixup + offset;
}

-int fixup_exception(struct pt_regs *regs)
+int fixup_exception(struct pt_regs *regs, bool uaccess_ok)
{
const struct exception_table_entry *fixup;
unsigned long new_ip;
@@ -33,6 +33,9 @@ int fixup_exception(struct pt_regs *regs)
class = ex_class(fixup);
new_ip = ex_fixup_addr(fixup);

+ if (class != _EXTABLE_CLASS_ANY && !uaccess_ok)
+ return 0;
+
if (class == _EXTABLE_CLASS_EX) {
/* Special hack for uaccess_err */
current_thread_info()->uaccess_err = 1;
@@ -51,7 +54,7 @@ int __init early_fixup_exception(unsigned long *ip)

fixup = search_exception_tables(*ip);
if (fixup) {
- if (ex_class(fixup) == _EXTABLE_CLASS_EX) {
+ if (ex_class(fixup) != _EXTABLE_CLASS_ANY) {
/* uaccess handling not supported during early boot */
return 0;
}
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 58afb50..c9fdf7d 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -644,6 +644,11 @@ pgtable_bad(struct pt_regs *regs, unsigned long error_code,
oops_end(flags, regs, sig);
}

+static int fault_in_kernel_space(unsigned long address)
+{
+ return address >= TASK_SIZE_MAX;
+}
+
static noinline void
no_context(struct pt_regs *regs, unsigned long error_code,
unsigned long address, int signal, int si_code)
@@ -655,8 +660,11 @@ no_context(struct pt_regs *regs, unsigned long error_code,

fixup_pnpbios_exception(regs); /* Might not return */

- /* Are we prepared to handle this kernel fault? */
- if (fixup_exception(regs)) {
+ /*
+ * Are we prepared to handle this kernel fault? If this is a
+ * uaccess fault, then the faulting address must be in user space.
+ */
+ if (fixup_exception(regs, !fault_in_kernel_space(address))) {
if (current_thread_info()->sig_on_uaccess_error && signal) {
tsk->thread.trap_nr = X86_TRAP_PF;
tsk->thread.error_code = error_code | PF_USER;
@@ -1001,11 +1009,6 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)
return 0;
}

-static int fault_in_kernel_space(unsigned long address)
-{
- return address >= TASK_SIZE_MAX;
-}
-
static inline bool smap_violation(int error_code, struct pt_regs *regs)
{
if (error_code & PF_USER)
--
1.8.1.4

2013-05-22 21:28:50

by David Miller

[permalink] [raw]
Subject: Re: [PATCH 0/5] x86: oops on uaccess faults outside of user addresses


Please don't mix networking and non-networking changes into a patch
series.

Submit the networking patch to [email protected]

Thanks.

2013-05-28 08:25:20

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 0/5] x86: oops on uaccess faults outside of user addresses


* David Miller <[email protected]> wrote:

> Please don't mix networking and non-networking changes into a patch
> series.

As explained in 0/5 the networking fix justifies the first 4 patches. The
networking fix is independent of the first 4 patches.

> Submit the networking patch to [email protected]

He Cc:-ed the patch to [email protected]. If you agree with it then
the fix should probably be picked up ASAP.

Thanks,

Ingo

2013-05-28 08:51:09

by David Miller

[permalink] [raw]
Subject: Re: [PATCH 0/5] x86: oops on uaccess faults outside of user addresses

From: Ingo Molnar <[email protected]>
Date: Tue, 28 May 2013 10:25:14 +0200

>
> * David Miller <[email protected]> wrote:
>
>> Please don't mix networking and non-networking changes into a patch
>> series.
>
> As explained in 0/5 the networking fix justifies the first 4 patches. The
> networking fix is independent of the first 4 patches.
>
>> Submit the networking patch to [email protected]
>
> He Cc:-ed the patch to [email protected]. If you agree with it then
> the fix should probably be picked up ASAP.

He submitted it as part of a series which implies that it belongs together
with the others.

If it does not, he should submit it seperately.

If they belong together, then the entire series should be CC:'d to netdev
so that networking developers can see all of the context and participate
in the patches that the networking "enables".

2013-05-28 08:54:41

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH 0/5] x86: oops on uaccess faults outside of user addresses


* David Miller <[email protected]> wrote:

> From: Ingo Molnar <[email protected]>
> Date: Tue, 28 May 2013 10:25:14 +0200
>
> >
> > * David Miller <[email protected]> wrote:
> >
> >> Please don't mix networking and non-networking changes into a patch
> >> series.
> >
> > As explained in 0/5 the networking fix justifies the first 4 patches. The
> > networking fix is independent of the first 4 patches.
> >
> >> Submit the networking patch to [email protected]
> >
> > He Cc:-ed the patch to [email protected]. If you agree with it then
> > the fix should probably be picked up ASAP.
>
> He submitted it as part of a series which implies that it belongs together
> with the others.

And then described it in the 0/5 patch that it's not. It's also visible
from the title, the changelog and the diff of the 5/5 patch that it's a
separate fix.

So please consider it submitted.

Thanks,

Ingo

2013-05-28 08:56:07

by Ingo Molnar

[permalink] [raw]
Subject: [PATCH/FIX] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg


(edited the title to make sure everyone sees that this fix is standalone.)

----- Forwarded message from Andy Lutomirski <[email protected]> -----

Date: Wed, 22 May 2013 14:07:44 -0700
From: Andy Lutomirski <[email protected]>
To: [email protected]
Cc: [email protected], [email protected], Andy Lutomirski <[email protected]>, [email protected], "David S.
Miller" <[email protected]>
Subject: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
it's a hack that steals a bit to indicate to other networking code
that a compat entry was used. So don't allow it from a non-compat
syscall.

This prevents an oops when running this code:

int main()
{
int s;
struct sockaddr_in addr;
struct msghdr *hdr;

char *highpage = mmap((void*)(TASK_SIZE_MAX - 4096), 4096,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (highpage == MAP_FAILED)
err(1, "mmap");

s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s == -1)
err(1, "socket");

addr.sin_family = AF_INET;
addr.sin_port = htons(1);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) != 0)
err(1, "connect");

void *evil = highpage + 4096 - COMPAT_MSGHDR_SIZE;
printf("Evil address is %p\n", evil);

if (syscall(__NR_sendmmsg, s, evil, 1, MSG_CMSG_COMPAT) < 0)
err(1, "sendmmsg");

return 0;
}

Cc: David S. Miller <[email protected]>
Signed-off-by: Andy Lutomirski <[email protected]>
---
net/socket.c | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/net/socket.c b/net/socket.c
index 88f759a..0e16888 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2097,8 +2097,12 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, fla
{
int fput_needed, err;
struct msghdr msg_sys;
- struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ struct socket *sock;
+
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;

+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;

@@ -2171,6 +2175,8 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
unsigned int, vlen, unsigned int, flags)
{
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
return __sys_sendmmsg(fd, mmsg, vlen, flags);
}

@@ -2271,8 +2277,12 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
{
int fput_needed, err;
struct msghdr msg_sys;
- struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ struct socket *sock;
+
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;

+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;

@@ -2397,6 +2407,9 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
int datagrams;
struct timespec timeout_sys;

+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
+
if (!timeout)
return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);

@@ -2512,15 +2525,31 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
(int __user *)a[4]);
break;
case SYS_SENDMSG:
+ if (a[2] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
case SYS_SENDMMSG:
+ if (a[3] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
break;
case SYS_RECVMSG:
+ if (a[2] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
case SYS_RECVMMSG:
+ if (a[3] & MSG_CMSG_COMPAT) {
+ err = -EINVAL;
+ break;
+ }
err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
(struct timespec __user *)a[4]);
break;
--
1.8.1.4

2013-05-29 06:56:31

by David Miller

[permalink] [raw]
Subject: Re: [PATCH/FIX] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

From: Ingo Molnar <[email protected]>
Date: Tue, 28 May 2013 10:56:00 +0200

> MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
> it's a hack that steals a bit to indicate to other networking code
> that a compat entry was used. So don't allow it from a non-compat
> syscall.
>
> This prevents an oops when running this code:
...
> Cc: David S. Miller <[email protected]>
> Signed-off-by: Andy Lutomirski <[email protected]>

Applied and queued up for -stable.

2013-05-29 08:11:55

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH/FIX] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg


* David Miller <[email protected]> wrote:

> From: Ingo Molnar <[email protected]>
> Date: Tue, 28 May 2013 10:56:00 +0200
>
> > MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
> > it's a hack that steals a bit to indicate to other networking code
> > that a compat entry was used. So don't allow it from a non-compat
> > syscall.
> >
> > This prevents an oops when running this code:
> ...
> > Cc: David S. Miller <[email protected]>
> > Signed-off-by: Andy Lutomirski <[email protected]>
>
> Applied and queued up for -stable.

Thanks David!

Ingo

2013-06-06 02:56:50

by Michael Neuling

[permalink] [raw]
Subject: Re: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

On Thu, May 23, 2013 at 7:07 AM, Andy Lutomirski <[email protected]> wrote:
> MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
> it's a hack that steals a bit to indicate to other networking code
> that a compat entry was used. So don't allow it from a non-compat
> syscall.

Dave & Linus

This is causing a regression on 64bit powerpc with 32bit usermode.
When I hit userspace, udev is broken and I suspect all networking is
broken as well.

Can we please revert 1be374a0518a288147c6a7398792583200a67261 upstream?

Found via bisect.

Mikey

>
> This prevents an oops when running this code:
>
> int main()
> {
> int s;
> struct sockaddr_in addr;
> struct msghdr *hdr;
>
> char *highpage = mmap((void*)(TASK_SIZE_MAX - 4096), 4096,
> PROT_READ | PROT_WRITE,
> MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
> if (highpage == MAP_FAILED)
> err(1, "mmap");
>
> s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
> if (s == -1)
> err(1, "socket");
>
> addr.sin_family = AF_INET;
> addr.sin_port = htons(1);
> addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);This is upster

> if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) != 0)
> err(1, "connect");
>
> void *evil = highpage + 4096 - COMPAT_MSGHDR_SIZE;
> printf("Evil address is %p\n", evil);
>
> if (syscall(__NR_sendmmsg, s, evil, 1, MSG_CMSG_COMPAT) < 0)
> err(1, "sendmmsg");
>
> return 0;
> }
>
> Cc: David S. Miller <[email protected]>
> Signed-off-by: Andy Lutomirski <[email protected]>
> ---
> net/socket.c | 33 +++++++++++++++++++++++++++++++--
> 1 file changed, 31 insertions(+), 2 deletions(-)
>
> diff --git a/net/socket.c b/net/socket.c
> index 88f759a..0e16888 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -2097,8 +2097,12 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, fla
> {
> int fput_needed, err;
> struct msghdr msg_sys;
> - struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
> + struct socket *sock;
> +
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
>
> + sock = sockfd_lookup_light(fd, &err, &fput_needed);
> if (!sock)
> goto out;
>
> @@ -2171,6 +2175,8 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
> SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
> unsigned int, vlen, unsigned int, flags)
> {
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> return __sys_sendmmsg(fd, mmsg, vlen, flags);
> }
>
> @@ -2271,8 +2277,12 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
> {
> int fput_needed, err;
> struct msghdr msg_sys;
> - struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
> + struct socket *sock;
> +
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
>
> + sock = sockfd_lookup_light(fd, &err, &fput_needed);
> if (!sock)
> goto out;
>
> @@ -2397,6 +2407,9 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
> int datagrams;
> struct timespec timeout_sys;
>
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> +
> if (!timeout)
> return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);
>
> @@ -2512,15 +2525,31 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
> (int __user *)a[4]);
> break;
> case SYS_SENDMSG:
> + if (a[2] & MSG_CMSG_COMPAT) {
> + err = -EINVAL;
> + break;
> + }
> err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
> break;
> case SYS_SENDMMSG:
> + if (a[3] & MSG_CMSG_COMPAT) {
> + err = -EINVAL;
> + break;
> + }
> err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
> break;
> case SYS_RECVMSG:
> + if (a[2] & MSG_CMSG_COMPAT) {
> + err = -EINVAL;
> + break;
> + }
> err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
> break;
> case SYS_RECVMMSG:
> + if (a[3] & MSG_CMSG_COMPAT) {
> + err = -EINVAL;
> + break;
> + }
> err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
> (struct timespec __user *)a[4]);
> break;
> --
> 1.8.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2013-06-06 03:01:08

by Anton Blanchard

[permalink] [raw]
Subject: Re: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

Hi,

> This is causing a regression on 64bit powerpc with 32bit usermode.
> When I hit userspace, udev is broken and I suspect all networking is
> broken as well.
>
> Can we please revert 1be374a0518a288147c6a7398792583200a67261
> upstream?
>
> Found via bisect.

Doesn't this patch break compat_sys_sendmsg and compat_sys_recvmsg?
We'd need to move the guts of sys_* into compat_sys_* to fix it.

Anton

2013-06-06 03:29:47

by Stephen Rothwell

[permalink] [raw]
Subject: Re: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

Hi Anton,

On Thu, 6 Jun 2013 13:01:05 +1000 Anton Blanchard <[email protected]> wrote:
>
> > This is causing a regression on 64bit powerpc with 32bit usermode.
> > When I hit userspace, udev is broken and I suspect all networking is
> > broken as well.
> >
> > Can we please revert 1be374a0518a288147c6a7398792583200a67261
> > upstream?
> >
> > Found via bisect.
>
> Doesn't this patch break compat_sys_sendmsg and compat_sys_recvmsg?
> We'd need to move the guts of sys_* into compat_sys_* to fix it.

What you really need is a set of common functions that the sys_ and
compat_sys_ functions can call - with the sys_ funtions forbidding
MSG_CMSG_COMPAT and the compat_sys_ functions setting it.

--
Cheers,
Stephen Rothwell [email protected]
http://www.canb.auug.org.au/~sfr/


Attachments:
(No filename) (802.00 B)
(No filename) (836.00 B)
Download all attachments

2013-06-06 04:35:30

by Eric Dumazet

[permalink] [raw]
Subject: Re: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

On Thu, 2013-06-06 at 12:56 +1000, Michael Neuling wrote:
> On Thu, May 23, 2013 at 7:07 AM, Andy Lutomirski <[email protected]> wrote:
> > MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
> > it's a hack that steals a bit to indicate to other networking code
> > that a compat entry was used. So don't allow it from a non-compat
> > syscall.
>
> Dave & Linus
>
> This is causing a regression on 64bit powerpc with 32bit usermode.
> When I hit userspace, udev is broken and I suspect all networking is
> broken as well.
>
> Can we please revert 1be374a0518a288147c6a7398792583200a67261 upstream?
>

It seems to also break x86_64, if using 32bit usermode.


2013-06-06 05:00:09

by David Miller

[permalink] [raw]
Subject: Re: [PATCH 5/5] net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

From: Eric Dumazet <[email protected]>
Date: Wed, 05 Jun 2013 21:35:25 -0700

> On Thu, 2013-06-06 at 12:56 +1000, Michael Neuling wrote:
>> On Thu, May 23, 2013 at 7:07 AM, Andy Lutomirski <[email protected]> wrote:
>> > MSG_CMSG_COMPAT is (AFAIK) not intended to be part of the API --
>> > it's a hack that steals a bit to indicate to other networking code
>> > that a compat entry was used. So don't allow it from a non-compat
>> > syscall.
>>
>> Dave & Linus
>>
>> This is causing a regression on 64bit powerpc with 32bit usermode.
>> When I hit userspace, udev is broken and I suspect all networking is
>> broken as well.
>>
>> Can we please revert 1be374a0518a288147c6a7398792583200a67261 upstream?
>>
>
> It seems to also break x86_64, if using 32bit usermode.

Sorry, I only merged this because Ingo Molnar and others kept beating
me over the head about merging this fix.

Linus please revert, and I will not bow to such pressure in the future,
I should know better.

2013-06-06 05:38:40

by Andy Lutomirski

[permalink] [raw]
Subject: [PATCH] net: Unbreak compat_sys_{send,recv}msg

I broke them in this commit:

commit 1be374a0518a288147c6a7398792583200a67261
Author: Andy Lutomirski <[email protected]>
Date: Wed May 22 14:07:44 2013 -0700

net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

This patch adds __sys_sendmsg and __sys_sendmsg as common helpers that accept
MSG_CMSG_COMPAT and blocks MSG_CMSG_COMPAT at the syscall entrypoints. It
also reverts some unnecessary checks in sys_socketcall.

Apparently I was suffering from underscore blindness the first time around.

Signed-off-by: Andy Lutomirski <[email protected]>
---

I've tested this a little, but I'm not sure I have a great test case.

If the decision is that it's better to leave this for the 3.11, I can send
a squashed version. Note that the oops that this fixes is only an oops if
the other patches in the original series are applied.

(FWIW, I wasn't sure how to submit this stuff in the first place. I submitted
some kernel hardening patches for the x86 tree that converted an access_ok
oddity in the net code into an actual oops. In a bit of looking, I couldn't
find any failure mode other than a -EFAULT return without the other patches
applied. This was clear in the patch series description but not in the
change log message for the net part.)

include/linux/socket.h | 3 +++
net/compat.c | 13 +++++++--
net/socket.c | 72 +++++++++++++++++++++++---------------------------
3 files changed, 47 insertions(+), 41 deletions(-)

diff --git a/include/linux/socket.h b/include/linux/socket.h
index 2b9f74b..e897bdc 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -321,6 +321,9 @@ extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);

struct timespec;

+/* The __sys_...msg variants allow MSG_CMSG_COMPAT */
+extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
+extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
unsigned int flags, struct timespec *timeout);
extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
diff --git a/net/compat.c b/net/compat.c
index 79ae884..f0a1ba6 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -734,19 +734,25 @@ static unsigned char nas[21] = {

asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
{
- return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
+ return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}

asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
unsigned int vlen, unsigned int flags)
{
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
flags | MSG_CMSG_COMPAT);
}

asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
{
- return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
+ return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
}

asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
@@ -768,6 +774,9 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
int datagrams;
struct timespec ktspec;

+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
+
if (COMPAT_USE_64BIT_TIME)
return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
flags | MSG_CMSG_COMPAT,
diff --git a/net/socket.c b/net/socket.c
index 0e16888..e216502 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1978,7 +1978,7 @@ struct used_address {
unsigned int name_len;
};

-static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
+static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
struct msghdr *msg_sys, unsigned int flags,
struct used_address *used_address)
{
@@ -2093,26 +2093,30 @@ out:
* BSD sendmsg interface
*/

-SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
+long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
{
int fput_needed, err;
struct msghdr msg_sys;
struct socket *sock;

- if (flags & MSG_CMSG_COMPAT)
- return -EINVAL;
-
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;

- err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
+ err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);

fput_light(sock->file, fput_needed);
out:
return err;
}

+SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
+{
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
+ return __sys_sendmsg(fd, msg, flags);
+}
+
/*
* Linux sendmmsg interface
*/
@@ -2143,15 +2147,16 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,

while (datagrams < vlen) {
if (MSG_CMSG_COMPAT & flags) {
- err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
- &msg_sys, flags, &used_address);
+ err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
+ &msg_sys, flags, &used_address);
if (err < 0)
break;
err = __put_user(err, &compat_entry->msg_len);
++compat_entry;
} else {
- err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
- &msg_sys, flags, &used_address);
+ err = ___sys_sendmsg(sock,
+ (struct msghdr __user *)entry,
+ &msg_sys, flags, &used_address);
if (err < 0)
break;
err = put_user(err, &entry->msg_len);
@@ -2180,7 +2185,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
return __sys_sendmmsg(fd, mmsg, vlen, flags);
}

-static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
+static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
struct msghdr *msg_sys, unsigned int flags, int nosec)
{
struct compat_msghdr __user *msg_compat =
@@ -2272,27 +2277,31 @@ out:
* BSD recvmsg interface
*/

-SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
- unsigned int, flags)
+long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
{
int fput_needed, err;
struct msghdr msg_sys;
struct socket *sock;

- if (flags & MSG_CMSG_COMPAT)
- return -EINVAL;
-
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;

- err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
+ err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);

fput_light(sock->file, fput_needed);
out:
return err;
}

+SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
+ unsigned int, flags)
+{
+ if (flags & MSG_CMSG_COMPAT)
+ return -EINVAL;
+ return __sys_recvmsg(fd, msg, flags);
+}
+
/*
* Linux recvmmsg interface
*/
@@ -2330,17 +2339,18 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
* No need to ask LSM for more than the first datagram.
*/
if (MSG_CMSG_COMPAT & flags) {
- err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
- &msg_sys, flags & ~MSG_WAITFORONE,
- datagrams);
+ err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
+ &msg_sys, flags & ~MSG_WAITFORONE,
+ datagrams);
if (err < 0)
break;
err = __put_user(err, &compat_entry->msg_len);
++compat_entry;
} else {
- err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
- &msg_sys, flags & ~MSG_WAITFORONE,
- datagrams);
+ err = ___sys_recvmsg(sock,
+ (struct msghdr __user *)entry,
+ &msg_sys, flags & ~MSG_WAITFORONE,
+ datagrams);
if (err < 0)
break;
err = put_user(err, &entry->msg_len);
@@ -2525,31 +2535,15 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
(int __user *)a[4]);
break;
case SYS_SENDMSG:
- if (a[2] & MSG_CMSG_COMPAT) {
- err = -EINVAL;
- break;
- }
err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
case SYS_SENDMMSG:
- if (a[3] & MSG_CMSG_COMPAT) {
- err = -EINVAL;
- break;
- }
err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
break;
case SYS_RECVMSG:
- if (a[2] & MSG_CMSG_COMPAT) {
- err = -EINVAL;
- break;
- }
err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
case SYS_RECVMMSG:
- if (a[3] & MSG_CMSG_COMPAT) {
- err = -EINVAL;
- break;
- }
err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
(struct timespec __user *)a[4]);
break;
--
1.8.1.4

2013-06-06 05:48:54

by Michael Neuling

[permalink] [raw]
Subject: Re: [PATCH] net: Unbreak compat_sys_{send,recv}msg

Andy Lutomirski <[email protected]> wrote:

> I broke them in this commit:
>
> commit 1be374a0518a288147c6a7398792583200a67261
> Author: Andy Lutomirski <[email protected]>
> Date: Wed May 22 14:07:44 2013 -0700
>
> net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
>
> This patch adds __sys_sendmsg and __sys_sendmsg as common helpers that accept
> MSG_CMSG_COMPAT and blocks MSG_CMSG_COMPAT at the syscall entrypoints. It
> also reverts some unnecessary checks in sys_socketcall.
>
> Apparently I was suffering from underscore blindness the first time around.

FWIW This fixes the problem I was seeing with powerpc 32bit user on 64
bit kernel.

Mikey

>
> Signed-off-by: Andy Lutomirski <[email protected]>
> ---
>
> I've tested this a little, but I'm not sure I have a great test case.
>
> If the decision is that it's better to leave this for the 3.11, I can send
> a squashed version. Note that the oops that this fixes is only an oops if
> the other patches in the original series are applied.
>
> (FWIW, I wasn't sure how to submit this stuff in the first place. I submitted
> some kernel hardening patches for the x86 tree that converted an access_ok
> oddity in the net code into an actual oops. In a bit of looking, I couldn't
> find any failure mode other than a -EFAULT return without the other patches
> applied. This was clear in the patch series description but not in the
> change log message for the net part.)
>
> include/linux/socket.h | 3 +++
> net/compat.c | 13 +++++++--
> net/socket.c | 72 +++++++++++++++++++++++---------------------------
> 3 files changed, 47 insertions(+), 41 deletions(-)
>
> diff --git a/include/linux/socket.h b/include/linux/socket.h
> index 2b9f74b..e897bdc 100644
> --- a/include/linux/socket.h
> +++ b/include/linux/socket.h
> @@ -321,6 +321,9 @@ extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
>
> struct timespec;
>
> +/* The __sys_...msg variants allow MSG_CMSG_COMPAT */
> +extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
> +extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
> extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
> unsigned int flags, struct timespec *timeout);
> extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
> diff --git a/net/compat.c b/net/compat.c
> index 79ae884..f0a1ba6 100644
> --- a/net/compat.c
> +++ b/net/compat.c
> @@ -734,19 +734,25 @@ static unsigned char nas[21] = {
>
> asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
> {
> - return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> }
>
> asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
> unsigned int vlen, unsigned int flags)
> {
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
> flags | MSG_CMSG_COMPAT);
> }
>
> asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
> {
> - return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> }
>
> asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
> @@ -768,6 +774,9 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
> int datagrams;
> struct timespec ktspec;
>
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> +
> if (COMPAT_USE_64BIT_TIME)
> return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
> flags | MSG_CMSG_COMPAT,
> diff --git a/net/socket.c b/net/socket.c
> index 0e16888..e216502 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -1978,7 +1978,7 @@ struct used_address {
> unsigned int name_len;
> };
>
> -static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
> +static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
> struct msghdr *msg_sys, unsigned int flags,
> struct used_address *used_address)
> {
> @@ -2093,26 +2093,30 @@ out:
> * BSD sendmsg interface
> */
>
> -SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
> +long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
> {
> int fput_needed, err;
> struct msghdr msg_sys;
> struct socket *sock;
>
> - if (flags & MSG_CMSG_COMPAT)
> - return -EINVAL;
> -
> sock = sockfd_lookup_light(fd, &err, &fput_needed);
> if (!sock)
> goto out;
>
> - err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
> + err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
>
> fput_light(sock->file, fput_needed);
> out:
> return err;
> }
>
> +SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
> +{
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_sendmsg(fd, msg, flags);
> +}
> +
> /*
> * Linux sendmmsg interface
> */
> @@ -2143,15 +2147,16 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
>
> while (datagrams < vlen) {
> if (MSG_CMSG_COMPAT & flags) {
> - err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
> - &msg_sys, flags, &used_address);
> + err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
> + &msg_sys, flags, &used_address);
> if (err < 0)
> break;
> err = __put_user(err, &compat_entry->msg_len);
> ++compat_entry;
> } else {
> - err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
> - &msg_sys, flags, &used_address);
> + err = ___sys_sendmsg(sock,
> + (struct msghdr __user *)entry,
> + &msg_sys, flags, &used_address);
> if (err < 0)
> break;
> err = put_user(err, &entry->msg_len);
> @@ -2180,7 +2185,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
> return __sys_sendmmsg(fd, mmsg, vlen, flags);
> }
>
> -static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
> +static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
> struct msghdr *msg_sys, unsigned int flags, int nosec)
> {
> struct compat_msghdr __user *msg_compat =
> @@ -2272,27 +2277,31 @@ out:
> * BSD recvmsg interface
> */
>
> -SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
> - unsigned int, flags)
> +long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
> {
> int fput_needed, err;
> struct msghdr msg_sys;
> struct socket *sock;
>
> - if (flags & MSG_CMSG_COMPAT)
> - return -EINVAL;
> -
> sock = sockfd_lookup_light(fd, &err, &fput_needed);
> if (!sock)
> goto out;
>
> - err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
> + err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
>
> fput_light(sock->file, fput_needed);
> out:
> return err;
> }
>
> +SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
> + unsigned int, flags)
> +{
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_recvmsg(fd, msg, flags);
> +}
> +
> /*
> * Linux recvmmsg interface
> */
> @@ -2330,17 +2339,18 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
> * No need to ask LSM for more than the first datagram.
> */
> if (MSG_CMSG_COMPAT & flags) {
> - err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
> - &msg_sys, flags & ~MSG_WAITFORONE,
> - datagrams);
> + err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
> + &msg_sys, flags & ~MSG_WAITFORONE,
> + datagrams);
> if (err < 0)
> break;
> err = __put_user(err, &compat_entry->msg_len);
> ++compat_entry;
> } else {
> - err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
> - &msg_sys, flags & ~MSG_WAITFORONE,
> - datagrams);
> + err = ___sys_recvmsg(sock,
> + (struct msghdr __user *)entry,
> + &msg_sys, flags & ~MSG_WAITFORONE,
> + datagrams);
> if (err < 0)
> break;
> err = put_user(err, &entry->msg_len);
> @@ -2525,31 +2535,15 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
> (int __user *)a[4]);
> break;
> case SYS_SENDMSG:
> - if (a[2] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
> break;
> case SYS_SENDMMSG:
> - if (a[3] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
> break;
> case SYS_RECVMSG:
> - if (a[2] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
> break;
> case SYS_RECVMMSG:
> - if (a[3] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
> (struct timespec __user *)a[4]);
> break;
> --
> 1.8.1.4
>

2013-06-06 07:26:30

by David Miller

[permalink] [raw]
Subject: Re: [PATCH] net: Unbreak compat_sys_{send,recv}msg

From: Andy Lutomirski <[email protected]>
Date: Wed, 5 Jun 2013 22:38:26 -0700

> I broke them in this commit:
>
> commit 1be374a0518a288147c6a7398792583200a67261
> Author: Andy Lutomirski <[email protected]>
> Date: Wed May 22 14:07:44 2013 -0700
>
> net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
>
> This patch adds __sys_sendmsg and __sys_sendmsg as common helpers that accept
> MSG_CMSG_COMPAT and blocks MSG_CMSG_COMPAT at the syscall entrypoints. It
> also reverts some unnecessary checks in sys_socketcall.
>
> Apparently I was suffering from underscore blindness the first time around.
>
> Signed-off-by: Andy Lutomirski <[email protected]>

Eric, can you test this patch too?

Thanks.

> ---
>
> I've tested this a little, but I'm not sure I have a great test case.
>
> If the decision is that it's better to leave this for the 3.11, I can send
> a squashed version. Note that the oops that this fixes is only an oops if
> the other patches in the original series are applied.
>
> (FWIW, I wasn't sure how to submit this stuff in the first place. I submitted
> some kernel hardening patches for the x86 tree that converted an access_ok
> oddity in the net code into an actual oops. In a bit of looking, I couldn't
> find any failure mode other than a -EFAULT return without the other patches
> applied. This was clear in the patch series description but not in the
> change log message for the net part.)
>
> include/linux/socket.h | 3 +++
> net/compat.c | 13 +++++++--
> net/socket.c | 72 +++++++++++++++++++++++---------------------------
> 3 files changed, 47 insertions(+), 41 deletions(-)
>
> diff --git a/include/linux/socket.h b/include/linux/socket.h
> index 2b9f74b..e897bdc 100644
> --- a/include/linux/socket.h
> +++ b/include/linux/socket.h
> @@ -321,6 +321,9 @@ extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
>
> struct timespec;
>
> +/* The __sys_...msg variants allow MSG_CMSG_COMPAT */
> +extern long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
> +extern long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
> extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
> unsigned int flags, struct timespec *timeout);
> extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg,
> diff --git a/net/compat.c b/net/compat.c
> index 79ae884..f0a1ba6 100644
> --- a/net/compat.c
> +++ b/net/compat.c
> @@ -734,19 +734,25 @@ static unsigned char nas[21] = {
>
> asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
> {
> - return sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_sendmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> }
>
> asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg,
> unsigned int vlen, unsigned int flags)
> {
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> return __sys_sendmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
> flags | MSG_CMSG_COMPAT);
> }
>
> asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, unsigned int flags)
> {
> - return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
> }
>
> asmlinkage long compat_sys_recv(int fd, void __user *buf, size_t len, unsigned int flags)
> @@ -768,6 +774,9 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
> int datagrams;
> struct timespec ktspec;
>
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> +
> if (COMPAT_USE_64BIT_TIME)
> return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
> flags | MSG_CMSG_COMPAT,
> diff --git a/net/socket.c b/net/socket.c
> index 0e16888..e216502 100644
> --- a/net/socket.c
> +++ b/net/socket.c
> @@ -1978,7 +1978,7 @@ struct used_address {
> unsigned int name_len;
> };
>
> -static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
> +static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
> struct msghdr *msg_sys, unsigned int flags,
> struct used_address *used_address)
> {
> @@ -2093,26 +2093,30 @@ out:
> * BSD sendmsg interface
> */
>
> -SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
> +long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
> {
> int fput_needed, err;
> struct msghdr msg_sys;
> struct socket *sock;
>
> - if (flags & MSG_CMSG_COMPAT)
> - return -EINVAL;
> -
> sock = sockfd_lookup_light(fd, &err, &fput_needed);
> if (!sock)
> goto out;
>
> - err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
> + err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
>
> fput_light(sock->file, fput_needed);
> out:
> return err;
> }
>
> +SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
> +{
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_sendmsg(fd, msg, flags);
> +}
> +
> /*
> * Linux sendmmsg interface
> */
> @@ -2143,15 +2147,16 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
>
> while (datagrams < vlen) {
> if (MSG_CMSG_COMPAT & flags) {
> - err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
> - &msg_sys, flags, &used_address);
> + err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
> + &msg_sys, flags, &used_address);
> if (err < 0)
> break;
> err = __put_user(err, &compat_entry->msg_len);
> ++compat_entry;
> } else {
> - err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
> - &msg_sys, flags, &used_address);
> + err = ___sys_sendmsg(sock,
> + (struct msghdr __user *)entry,
> + &msg_sys, flags, &used_address);
> if (err < 0)
> break;
> err = put_user(err, &entry->msg_len);
> @@ -2180,7 +2185,7 @@ SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
> return __sys_sendmmsg(fd, mmsg, vlen, flags);
> }
>
> -static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
> +static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
> struct msghdr *msg_sys, unsigned int flags, int nosec)
> {
> struct compat_msghdr __user *msg_compat =
> @@ -2272,27 +2277,31 @@ out:
> * BSD recvmsg interface
> */
>
> -SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
> - unsigned int, flags)
> +long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
> {
> int fput_needed, err;
> struct msghdr msg_sys;
> struct socket *sock;
>
> - if (flags & MSG_CMSG_COMPAT)
> - return -EINVAL;
> -
> sock = sockfd_lookup_light(fd, &err, &fput_needed);
> if (!sock)
> goto out;
>
> - err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
> + err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
>
> fput_light(sock->file, fput_needed);
> out:
> return err;
> }
>
> +SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
> + unsigned int, flags)
> +{
> + if (flags & MSG_CMSG_COMPAT)
> + return -EINVAL;
> + return __sys_recvmsg(fd, msg, flags);
> +}
> +
> /*
> * Linux recvmmsg interface
> */
> @@ -2330,17 +2339,18 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
> * No need to ask LSM for more than the first datagram.
> */
> if (MSG_CMSG_COMPAT & flags) {
> - err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
> - &msg_sys, flags & ~MSG_WAITFORONE,
> - datagrams);
> + err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
> + &msg_sys, flags & ~MSG_WAITFORONE,
> + datagrams);
> if (err < 0)
> break;
> err = __put_user(err, &compat_entry->msg_len);
> ++compat_entry;
> } else {
> - err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
> - &msg_sys, flags & ~MSG_WAITFORONE,
> - datagrams);
> + err = ___sys_recvmsg(sock,
> + (struct msghdr __user *)entry,
> + &msg_sys, flags & ~MSG_WAITFORONE,
> + datagrams);
> if (err < 0)
> break;
> err = put_user(err, &entry->msg_len);
> @@ -2525,31 +2535,15 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
> (int __user *)a[4]);
> break;
> case SYS_SENDMSG:
> - if (a[2] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
> break;
> case SYS_SENDMMSG:
> - if (a[3] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
> break;
> case SYS_RECVMSG:
> - if (a[2] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
> break;
> case SYS_RECVMMSG:
> - if (a[3] & MSG_CMSG_COMPAT) {
> - err = -EINVAL;
> - break;
> - }
> err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
> (struct timespec __user *)a[4]);
> break;
> --
> 1.8.1.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe trinity" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>

2013-06-06 13:45:41

by Eric Dumazet

[permalink] [raw]
Subject: Re: [PATCH] net: Unbreak compat_sys_{send,recv}msg

On Thu, 2013-06-06 at 00:26 -0700, David Miller wrote:
> From: Andy Lutomirski <[email protected]>
> Date: Wed, 5 Jun 2013 22:38:26 -0700
>
> > I broke them in this commit:
> >
> > commit 1be374a0518a288147c6a7398792583200a67261
> > Author: Andy Lutomirski <[email protected]>
> > Date: Wed May 22 14:07:44 2013 -0700
> >
> > net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
> >
> > This patch adds __sys_sendmsg and __sys_sendmsg as common helpers that accept
> > MSG_CMSG_COMPAT and blocks MSG_CMSG_COMPAT at the syscall entrypoints. It
> > also reverts some unnecessary checks in sys_socketcall.
> >
> > Apparently I was suffering from underscore blindness the first time around.
> >
> > Signed-off-by: Andy Lutomirski <[email protected]>
>
> Eric, can you test this patch too?

Yes, this fixes the problem as well on x86_64

Tested-by: Eric Dumazet <[email protected]>

Thanks !

PS: I had following fuzz while applying on Linus tree :

patching file include/linux/socket.h
Hunk #1 succeeded at 320 (offset -1 lines).
patching file net/compat.c
patching file net/socket.c
Hunk #1 succeeded at 1956 (offset -22 lines).
Hunk #2 succeeded at 2071 (offset -22 lines).
Hunk #3 succeeded at 2125 (offset -22 lines).
Hunk #4 succeeded at 2163 (offset -22 lines).
Hunk #5 succeeded at 2255 (offset -22 lines).
Hunk #6 succeeded at 2317 (offset -22 lines).
Hunk #7 succeeded at 2515 (offset -20 lines).

2013-06-06 18:54:09

by David Miller

[permalink] [raw]
Subject: Re: [PATCH] net: Unbreak compat_sys_{send,recv}msg

From: Eric Dumazet <[email protected]>
Date: Thu, 06 Jun 2013 06:45:37 -0700

> On Thu, 2013-06-06 at 00:26 -0700, David Miller wrote:
>> From: Andy Lutomirski <[email protected]>
>> Date: Wed, 5 Jun 2013 22:38:26 -0700
>>
>> > I broke them in this commit:
>> >
>> > commit 1be374a0518a288147c6a7398792583200a67261
>> > Author: Andy Lutomirski <[email protected]>
>> > Date: Wed May 22 14:07:44 2013 -0700
>> >
>> > net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg
>> >
>> > This patch adds __sys_sendmsg and __sys_sendmsg as common helpers that accept
>> > MSG_CMSG_COMPAT and blocks MSG_CMSG_COMPAT at the syscall entrypoints. It
>> > also reverts some unnecessary checks in sys_socketcall.
>> >
>> > Apparently I was suffering from underscore blindness the first time around.
>> >
>> > Signed-off-by: Andy Lutomirski <[email protected]>
>>
>> Eric, can you test this patch too?
>
> Yes, this fixes the problem as well on x86_64
>
> Tested-by: Eric Dumazet <[email protected]>

Applied, thanks.

2013-06-13 22:01:00

by Andy Lutomirski

[permalink] [raw]
Subject: Re: [PATCH 0/5] x86: oops on uaccess faults outside of user addresses

On Wed, May 22, 2013 at 2:07 PM, Andy Lutomirski <[email protected]> wrote:
> Currently, __get_user can't trigger an OOPS -- any exception will be
> caught and return -EFAULT. This means that, if an access_ok check is
> missing somewhere, then an attacker can freely use it to probe for valid
> kernel mappings.
>
> This series annotates all of the exception fixups as "catch anything" or
> "catch valid uaccess faults", and skips the fixup (and hence oopses) if
> an instruction of the latter type faults for any reason other than a
> page fault to a user address.
>
> I know of only one bug of this type; it's fixed in patch 5.
>
> Perhaps surprisingly, this seems to survive Trinity fairly well.
>
> Andy Lutomirski (5):
> x86: Split "utter crap" pnpbios fixup out of fixup_exception
> x86: Clean up extable entry format (and free up a bit)
> x86: Annotate _ASM_EXTABLE users to distinguish uaccess from
> everything else
> x86: Don't fixup uaccess faults to kernel or non-canonical addresses
> net: Block MSG_CMSG_COMPAT in send(m)msg and recv(m)msg

Patch 5 is (for better or for worse) in -linus now. What's the status
of the other four? (They're certainly not 3.10 material.)

--Andy