2016-03-09 17:22:39

by Benjamin LaHaise

[permalink] [raw]
Subject: [PATCH] x86_32: add support for 64 bit __get_user()

The existing __get_user() implementation does not support fetching
64 bit values on 32 bit x86. Implement this in a way that does not
generate any incorrect warnings as cautioned by Russell King. Test
code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .

Signed-off-by: Benjamin LaHaise <[email protected]>

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index a4a30e4..2d0607a 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -333,7 +333,23 @@ do { \
} while (0)

#ifdef CONFIG_X86_32
-#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad()
+#define __get_user_asm_u64(x, addr, err, errret) \
+ asm volatile(ASM_STAC "\n" \
+ "1: movl %2,%%eax\n" \
+ "2: movl %3,%%edx\n" \
+ "3: " ASM_CLAC "\n" \
+ ".section .fixup,\"ax\"\n" \
+ "4: mov %4,%0\n" \
+ " xorl %%eax,%%eax\n" \
+ " xorl %%edx,%%edx\n" \
+ " jmp 3b\n" \
+ ".previous\n" \
+ _ASM_EXTABLE(1b, 4b) \
+ _ASM_EXTABLE(2b, 4b) \
+ : "=r" (err), "=A"(x) \
+ : "m" (__m(addr)), "m" __m(((u32 *)(addr)) + 1), \
+ "i" (errret), "0" (err))
+
#define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
#else
#define __get_user_asm_u64(x, ptr, retval, errret) \
@@ -420,11 +436,20 @@ do { \
#define __get_user_nocheck(x, ptr, size) \
({ \
int __gu_err; \
- unsigned long __gu_val; \
- __uaccess_begin(); \
- __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
- __uaccess_end(); \
- (x) = (__force __typeof__(*(ptr)))__gu_val; \
+ if (size == 8) { \
+ unsigned long __gu_val[2]; \
+ __gu_err = 0; \
+ __uaccess_begin(); \
+ __get_user_asm_u64(__gu_val, ptr, __gu_err, -EFAULT); \
+ __uaccess_end(); \
+ (x) = *(__force __typeof__((ptr)))__gu_val; \
+ } else { \
+ unsigned long __gu_val; \
+ __uaccess_begin(); \
+ __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
+ __uaccess_end(); \
+ (x) = (__force __typeof__(*(ptr)))__gu_val; \
+ } \
__builtin_expect(__gu_err, 0); \
})

--
"Thought is the essence of where you are now."


2016-03-09 17:39:15

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user()

On March 9, 2016 9:22:25 AM PST, Benjamin LaHaise <[email protected]> wrote:
>The existing __get_user() implementation does not support fetching
>64 bit values on 32 bit x86. Implement this in a way that does not
>generate any incorrect warnings as cautioned by Russell King. Test
>code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .
>
>Signed-off-by: Benjamin LaHaise <[email protected]>
>
>diff --git a/arch/x86/include/asm/uaccess.h
>b/arch/x86/include/asm/uaccess.h
>index a4a30e4..2d0607a 100644
>--- a/arch/x86/include/asm/uaccess.h
>+++ b/arch/x86/include/asm/uaccess.h
>@@ -333,7 +333,23 @@ do { \
> } while (0)
>
> #ifdef CONFIG_X86_32
>-#define __get_user_asm_u64(x, ptr, retval, errret) (x) =
>__get_user_bad()
>+#define __get_user_asm_u64(x, addr, err, errret) \
>+ asm volatile(ASM_STAC "\n" \
>+ "1: movl %2,%%eax\n" \
>+ "2: movl %3,%%edx\n" \
>+ "3: " ASM_CLAC "\n" \
>+ ".section .fixup,\"ax\"\n" \
>+ "4: mov %4,%0\n" \
>+ " xorl %%eax,%%eax\n" \
>+ " xorl %%edx,%%edx\n" \
>+ " jmp 3b\n" \
>+ ".previous\n" \
>+ _ASM_EXTABLE(1b, 4b) \
>+ _ASM_EXTABLE(2b, 4b) \
>+ : "=r" (err), "=A"(x) \
>+ : "m" (__m(addr)), "m" __m(((u32 *)(addr)) + 1), \
>+ "i" (errret), "0" (err))
>+
> #define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
> #else
> #define __get_user_asm_u64(x, ptr, retval, errret) \
>@@ -420,11 +436,20 @@ do { \
> #define __get_user_nocheck(x, ptr, size) \
> ({ \
> int __gu_err; \
>- unsigned long __gu_val; \
>- __uaccess_begin(); \
>- __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
>- __uaccess_end(); \
>- (x) = (__force __typeof__(*(ptr)))__gu_val; \
>+ if (size == 8) { \
>+ unsigned long __gu_val[2]; \
>+ __gu_err = 0; \
>+ __uaccess_begin(); \
>+ __get_user_asm_u64(__gu_val, ptr, __gu_err, -EFAULT); \
>+ __uaccess_end(); \
>+ (x) = *(__force __typeof__((ptr)))__gu_val; \
>+ } else { \
>+ unsigned long __gu_val; \
>+ __uaccess_begin(); \
>+ __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
>+ __uaccess_end(); \
>+ (x) = (__force __typeof__(*(ptr)))__gu_val; \
>+ } \
> __builtin_expect(__gu_err, 0); \
> })
>

Weird. I could swear we had already fixed this a few years ago.
--
Sent from my Android device with K-9 Mail. Please excuse brevity and formatting.

2016-03-09 17:50:27

by Benjamin LaHaise

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user()

On Wed, Mar 09, 2016 at 09:36:30AM -0800, H. Peter Anvin wrote:
> On March 9, 2016 9:22:25 AM PST, Benjamin LaHaise <[email protected]> wrote:
> >The existing __get_user() implementation does not support fetching
> >64 bit values on 32 bit x86. Implement this in a way that does not
> >generate any incorrect warnings as cautioned by Russell King. Test
> >code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .
...
> Weird. I could swear we had already fixed this a few years ago.

That surprised me as well, but Russell raised the fact that the approaches
previously tried on 32 bit architectures had caused various incorrect
compiler warnings for certain obscure cases -- see the code in test_module.c
in that URL that Russell provided to demonstrate the problem across all the
corner cases.

-ben
--
"Thought is the essence of where you are now."

2016-03-09 18:19:17

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user()

Hi Benjamin,

[auto build test ERROR on tip/x86/core]
[also build test ERROR on v4.5-rc7 next-20160309]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Benjamin-LaHaise/x86_32-add-support-for-64-bit-__get_user/20160310-012551
config: x86_64-alldefconfig (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

All errors (new ones prefixed by >>):

fs/select.c: Assembler messages:
>> fs/select.c:710: Error: operand type mismatch for `movq'
>> fs/select.c:714: Error: incorrect register `%cx' used with `q' suffix
fs/select.c:711: Error: operand type mismatch for `movq'
>> fs/select.c:715: Error: incorrect register `%si' used with `q' suffix
--
fs/aio.c: Assembler messages:
>> fs/aio.c:1606: Error: operand type mismatch for `movq'
>> fs/aio.c:1610: Error: incorrect register `%si' used with `q' suffix

vim +710 fs/select.c

9f72949f David Woodhouse 2006-01-18 704 size_t sigsetsize = 0;
9f72949f David Woodhouse 2006-01-18 705 sigset_t __user *up = NULL;
9f72949f David Woodhouse 2006-01-18 706
9f72949f David Woodhouse 2006-01-18 707 if (sig) {
9f72949f David Woodhouse 2006-01-18 708 if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t))
e110ab94 Al Viro 2006-02-01 709 || __get_user(up, (sigset_t __user * __user *)sig)
9f72949f David Woodhouse 2006-01-18 @710 || __get_user(sigsetsize,
e110ab94 Al Viro 2006-02-01 711 (size_t __user *)(sig+sizeof(void *))))
9f72949f David Woodhouse 2006-01-18 712 return -EFAULT;
9f72949f David Woodhouse 2006-01-18 713 }
9f72949f David Woodhouse 2006-01-18 @714
c9da9f21 Heiko Carstens 2009-01-14 @715 return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize);
9f72949f David Woodhouse 2006-01-18 716 }
9f72949f David Woodhouse 2006-01-18 717
5d0e5283 Christoph Hellwig 2010-03-10 718 #ifdef __ARCH_WANT_SYS_OLD_SELECT

:::::: The code at line 710 was first introduced by commit
:::::: 9f72949f679df06021c9e43886c9191494fdb007 [PATCH] Add pselect/ppoll system call implementation

:::::: TO: David Woodhouse <[email protected]>
:::::: CC: Linus Torvalds <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (2.41 kB)
.config.gz (9.52 kB)
Download all attachments

2016-03-09 18:23:05

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user()

Hi Benjamin,

[auto build test ERROR on tip/x86/core]
[also build test ERROR on v4.5-rc7 next-20160309]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Benjamin-LaHaise/x86_32-add-support-for-64-bit-__get_user/20160310-012551
config: x86_64-randconfig-s3-03100205 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

All errors (new ones prefixed by >>):

kernel/ptrace.c: Assembler messages:
kernel/ptrace.c:1039: Error: operand type mismatch for `movq'
>> kernel/ptrace.c:1043: Error: incorrect register `%cx' used with `q' suffix
kernel/ptrace.c:1040: Error: operand type mismatch for `movq'
kernel/ptrace.c:1044: Error: incorrect register `%cx' used with `q' suffix

vim +1043 kernel/ptrace.c

9fed81dc Namhyung Kim 2010-10-27 1033 struct iovec __user *uiov = datavp;
2225a122 Suresh Siddha 2010-02-11 1034
2225a122 Suresh Siddha 2010-02-11 1035 if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov)))
2225a122 Suresh Siddha 2010-02-11 1036 return -EFAULT;
2225a122 Suresh Siddha 2010-02-11 1037
2225a122 Suresh Siddha 2010-02-11 1038 if (__get_user(kiov.iov_base, &uiov->iov_base) ||
2225a122 Suresh Siddha 2010-02-11 @1039 __get_user(kiov.iov_len, &uiov->iov_len))
2225a122 Suresh Siddha 2010-02-11 1040 return -EFAULT;
2225a122 Suresh Siddha 2010-02-11 1041
2225a122 Suresh Siddha 2010-02-11 1042 ret = ptrace_regset(child, request, addr, &kiov);
2225a122 Suresh Siddha 2010-02-11 @1043 if (!ret)
2225a122 Suresh Siddha 2010-02-11 1044 ret = __put_user(kiov.iov_len, &uiov->iov_len);
2225a122 Suresh Siddha 2010-02-11 1045 break;
2225a122 Suresh Siddha 2010-02-11 1046 }

:::::: The code at line 1043 was first introduced by commit
:::::: 2225a122ae26d542bdce523d9d87a4a7ba10e07b ptrace: Add support for generic PTRACE_GETREGSET/PTRACE_SETREGSET

:::::: TO: Suresh Siddha <[email protected]>
:::::: CC: H. Peter Anvin <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (2.19 kB)
.config.gz (24.56 kB)
Download all attachments

2016-03-09 18:23:14

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user()

On 03/09/2016 09:50 AM, Benjamin LaHaise wrote:
> On Wed, Mar 09, 2016 at 09:36:30AM -0800, H. Peter Anvin wrote:
>> On March 9, 2016 9:22:25 AM PST, Benjamin LaHaise <[email protected]> wrote:
>>> The existing __get_user() implementation does not support fetching
>>> 64 bit values on 32 bit x86. Implement this in a way that does not
>>> generate any incorrect warnings as cautioned by Russell King. Test
>>> code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .
> ...
>> Weird. I could swear we had already fixed this a few years ago.
>
> That surprised me as well, but Russell raised the fact that the approaches
> previously tried on 32 bit architectures had caused various incorrect
> compiler warnings for certain obscure cases -- see the code in test_module.c
> in that URL that Russell provided to demonstrate the problem across all the
> corner cases.

Oh, I see... I implemented it for put but not get... weird. You may
want to look at the __inttype() macro defined earlier in this file; it
might be useful.

I presume you have already seen:

>> fs/select.c:710: Error: operand type mismatch for `movq'
>> fs/select.c:714: Error: incorrect register `%cx' used with `q' suffix
fs/select.c:711: Error: operand type mismatch for `movq'
>> fs/select.c:715: Error: incorrect register `%si' used with `q' suffix
--
fs/aio.c: Assembler messages:
>> fs/aio.c:1606: Error: operand type mismatch for `movq'
>> fs/aio.c:1610: Error: incorrect register `%si' used with `q' suffix

... which implies it used 16-bit registers for 64-bit operations when
compiling for 64 bits.

-hpa

2016-03-09 18:24:37

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user()

Hi Benjamin,

[auto build test ERROR on tip/x86/core]
[also build test ERROR on v4.5-rc7 next-20160309]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Benjamin-LaHaise/x86_32-add-support-for-64-bit-__get_user/20160310-012551
config: x86_64-randconfig-s0-03100154 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

All error/warnings (new ones prefixed by >>):

arch/x86/kernel/ptrace.c: Assembler messages:
>> arch/x86/kernel/ptrace.c:531: Error: operand type mismatch for `movq'
>> arch/x86/kernel/ptrace.c:535: Error: incorrect register `%dx' used with `q' suffix
--
In file included from include/linux/thread_info.h:11:0,
from arch/x86/include/asm/preempt.h:6,
from include/linux/preempt.h:59,
from include/linux/spinlock.h:50,
from include/linux/seqlock.h:35,
from include/linux/time.h:5,
from include/uapi/linux/timex.h:56,
from include/linux/timex.h:56,
from include/linux/sched.h:19,
from fs/select.c:18:
fs/select.c: In function 'SyS_pselect6':
>> include/linux/bug.h:33:45: error: unsupported operand size for extended register
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
>> include/linux/syscalls.h:108:31: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))
^
>> include/linux/syscalls.h:93:23: note: in expansion of macro '__SC_TEST'
#define __MAP1(m,t,a) m(t,a)
^
include/linux/syscalls.h:94:35: note: in expansion of macro '__MAP1'
#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
^
include/linux/syscalls.h:95:35: note: in expansion of macro '__MAP2'
#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
^
include/linux/syscalls.h:96:35: note: in expansion of macro '__MAP3'
#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
^
include/linux/syscalls.h:97:35: note: in expansion of macro '__MAP4'
#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
^
>> include/linux/syscalls.h:98:35: note: in expansion of macro '__MAP5'
#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
^
>> include/linux/syscalls.h:99:22: note: in expansion of macro '__MAP6'
#define __MAP(n,...) __MAP##n(__VA_ARGS__)
^
include/linux/syscalls.h:202:3: note: in expansion of macro '__MAP'
__MAP(x,__SC_TEST,__VA_ARGS__); \
^
include/linux/syscalls.h:191:2: note: in expansion of macro '__SYSCALL_DEFINEx'
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
^
include/linux/syscalls.h:187:36: note: in expansion of macro 'SYSCALL_DEFINEx'
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
^
>> fs/select.c:700:1: note: in expansion of macro 'SYSCALL_DEFINE6'
SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
^
>> include/linux/bug.h:33:45: error: unsupported operand size for extended register
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
>> include/linux/syscalls.h:108:31: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))
^
>> include/linux/syscalls.h:93:23: note: in expansion of macro '__SC_TEST'
#define __MAP1(m,t,a) m(t,a)
^
include/linux/syscalls.h:94:35: note: in expansion of macro '__MAP1'
#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
^
include/linux/syscalls.h:95:35: note: in expansion of macro '__MAP2'
#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
^
include/linux/syscalls.h:96:35: note: in expansion of macro '__MAP3'
#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
^
include/linux/syscalls.h:97:35: note: in expansion of macro '__MAP4'
#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
^
>> include/linux/syscalls.h:98:35: note: in expansion of macro '__MAP5'
#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
^
>> include/linux/syscalls.h:99:22: note: in expansion of macro '__MAP6'
#define __MAP(n,...) __MAP##n(__VA_ARGS__)
^
include/linux/syscalls.h:202:3: note: in expansion of macro '__MAP'
__MAP(x,__SC_TEST,__VA_ARGS__); \
^
include/linux/syscalls.h:191:2: note: in expansion of macro '__SYSCALL_DEFINEx'
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
^
include/linux/syscalls.h:187:36: note: in expansion of macro 'SYSCALL_DEFINEx'
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
^
>> fs/select.c:700:1: note: in expansion of macro 'SYSCALL_DEFINE6'
SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
^
>> include/linux/bug.h:33:45: error: unsupported operand size for extended register
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
>> include/linux/syscalls.h:108:31: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))
^
>> include/linux/syscalls.h:93:23: note: in expansion of macro '__SC_TEST'
#define __MAP1(m,t,a) m(t,a)
^
include/linux/syscalls.h:94:35: note: in expansion of macro '__MAP1'
#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
^
include/linux/syscalls.h:95:35: note: in expansion of macro '__MAP2'
#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
^
include/linux/syscalls.h:96:35: note: in expansion of macro '__MAP3'
#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
^
include/linux/syscalls.h:97:35: note: in expansion of macro '__MAP4'
#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
^
>> include/linux/syscalls.h:98:35: note: in expansion of macro '__MAP5'
#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
^
>> include/linux/syscalls.h:99:22: note: in expansion of macro '__MAP6'
#define __MAP(n,...) __MAP##n(__VA_ARGS__)
^
include/linux/syscalls.h:202:3: note: in expansion of macro '__MAP'
__MAP(x,__SC_TEST,__VA_ARGS__); \
^
include/linux/syscalls.h:191:2: note: in expansion of macro '__SYSCALL_DEFINEx'
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
^
include/linux/syscalls.h:187:36: note: in expansion of macro 'SYSCALL_DEFINEx'
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
^
>> fs/select.c:700:1: note: in expansion of macro 'SYSCALL_DEFINE6'
SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp,
^
>> include/linux/bug.h:33:45: error: unsupported operand size for extended register
#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
^
>> include/linux/syscalls.h:108:31: note: in expansion of macro 'BUILD_BUG_ON_ZERO'
#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))
^
--
fs/compat.c: In function 'compat_SyS_fcntl64':
>> fs/compat.c:417:1: error: unsupported operand size for extended register
COMPAT_SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
^
>> fs/compat.c:417:1: error: unsupported operand size for extended register
>> fs/compat.c:417:1: error: unsupported operand size for extended register
>> fs/compat.c:417:1: error: unsupported operand size for extended register
>> fs/compat.c:417:1: error: unsupported operand size for extended register
>> fs/compat.c:417:1: error: unsupported operand size for extended register
--
kernel/ptrace.c: In function 'ptrace_request':
>> kernel/ptrace.c:1058:1: error: unsupported operand size for extended register
}
^
>> kernel/ptrace.c:1058:1: error: unsupported operand size for extended register
>> kernel/ptrace.c:1058:1: error: unsupported operand size for extended register
>> kernel/ptrace.c:1058:1: error: unsupported operand size for extended register
>> kernel/ptrace.c:1058:1: error: unsupported operand size for extended register
>> kernel/ptrace.c:1058:1: error: unsupported operand size for extended register
--
kernel/signal.c: In function 'do_sigaltstack':
>> kernel/signal.c:3154:1: error: unsupported operand size for extended register
}
^
>> kernel/signal.c:3154:1: error: unsupported operand size for extended register
>> kernel/signal.c:3154:1: error: unsupported operand size for extended register
>> kernel/signal.c:3154:1: error: unsupported operand size for extended register
>> kernel/signal.c:3154:1: error: unsupported operand size for extended register
>> kernel/signal.c:3154:1: error: unsupported operand size for extended register
--
net/socket.c: In function 'copy_msghdr_from_user':
>> net/socket.c:1873:1: error: unsupported operand size for extended register
}
^
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register
>> net/socket.c:1873:1: error: unsupported operand size for extended register

vim +531 arch/x86/kernel/ptrace.c

91e7b707 Roland McGrath 2008-01-30 525 }
91e7b707 Roland McGrath 2008-01-30 526 } else {
91e7b707 Roland McGrath 2008-01-30 527 const unsigned long __user *u = ubuf;
04a1e62c Linus Torvalds 2009-12-17 528 while (count >= sizeof(*u) && !ret) {
91e7b707 Roland McGrath 2008-01-30 529 unsigned long word;
91e7b707 Roland McGrath 2008-01-30 530 ret = __get_user(word, u++);
91e7b707 Roland McGrath 2008-01-30 @531 if (ret)
91e7b707 Roland McGrath 2008-01-30 532 break;
91e7b707 Roland McGrath 2008-01-30 533 ret = putreg(target, pos, word);
91e7b707 Roland McGrath 2008-01-30 534 count -= sizeof(*u);
91e7b707 Roland McGrath 2008-01-30 @535 pos += sizeof(*u);
91e7b707 Roland McGrath 2008-01-30 536 }
91e7b707 Roland McGrath 2008-01-30 537 }
91e7b707 Roland McGrath 2008-01-30 538 return ret;

:::::: The code at line 531 was first introduced by commit
:::::: 91e7b707a4776185f91f03bd052aa53af820094e x86: x86 user_regset general regs

:::::: TO: Roland McGrath <[email protected]>
:::::: CC: Ingo Molnar <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (12.17 kB)
.config.gz (22.20 kB)
Download all attachments

2016-03-09 18:27:17

by Benjamin LaHaise

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user()

On Wed, Mar 09, 2016 at 10:22:50AM -0800, H. Peter Anvin wrote:
> On 03/09/2016 09:50 AM, Benjamin LaHaise wrote:
> > On Wed, Mar 09, 2016 at 09:36:30AM -0800, H. Peter Anvin wrote:
> >> On March 9, 2016 9:22:25 AM PST, Benjamin LaHaise <[email protected]> wrote:
> >>> The existing __get_user() implementation does not support fetching
> >>> 64 bit values on 32 bit x86. Implement this in a way that does not
> >>> generate any incorrect warnings as cautioned by Russell King. Test
> >>> code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .
> > ...
> >> Weird. I could swear we had already fixed this a few years ago.
> >
> > That surprised me as well, but Russell raised the fact that the approaches
> > previously tried on 32 bit architectures had caused various incorrect
> > compiler warnings for certain obscure cases -- see the code in test_module.c
> > in that URL that Russell provided to demonstrate the problem across all the
> > corner cases.
>
> Oh, I see... I implemented it for put but not get... weird. You may
> want to look at the __inttype() macro defined earlier in this file; it
> might be useful.

Ah, interesting. I'll look at that.

> I presume you have already seen:
>
> >> fs/select.c:710: Error: operand type mismatch for `movq'
> >> fs/select.c:714: Error: incorrect register `%cx' used with `q' suffix
> fs/select.c:711: Error: operand type mismatch for `movq'
> >> fs/select.c:715: Error: incorrect register `%si' used with `q' suffix
> --
> fs/aio.c: Assembler messages:
> >> fs/aio.c:1606: Error: operand type mismatch for `movq'
> >> fs/aio.c:1610: Error: incorrect register `%si' used with `q' suffix
>
> ... which implies it used 16-bit registers for 64-bit operations when
> compiling for 64 bits.

Yup, will respin shortly.

-ben
--
"Thought is the essence of where you are now."

2016-03-09 19:30:41

by Benjamin LaHaise

[permalink] [raw]
Subject: [PATCH] x86_32: add support for 64 bit __get_user() v2

The existing __get_user() implementation does not support fetching
64 bit values on 32 bit x86. Implement this in a way that does not
generate any incorrect warnings as cautioned by Russell King. Test
code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .

v2: use __inttype() as suggested by H. Peter Anvin, which cleans the
code up nicely, and fix things to work on x86_64 as well. Tested on
both 32 bit and 64 bit x86.

Signed-off-by: Benjamin LaHaise <[email protected]>

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index a4a30e4..1284da2 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -333,7 +333,25 @@ do { \
} while (0)

#ifdef CONFIG_X86_32
-#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad()
+#define __get_user_asm_u64(x, ptr, retval, errret) \
+({ \
+ asm volatile(ASM_STAC "\n" \
+ "1: movl %2,%%eax\n" \
+ "2: movl %3,%%edx\n" \
+ "3: " ASM_CLAC "\n" \
+ ".section .fixup,\"ax\"\n" \
+ "4: mov %4,%0\n" \
+ " xorl %%eax,%%eax\n" \
+ " xorl %%edx,%%edx\n" \
+ " jmp 3b\n" \
+ ".previous\n" \
+ _ASM_EXTABLE(1b, 4b) \
+ _ASM_EXTABLE(2b, 4b) \
+ : "=r" (retval), "=A"(x) \
+ : "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
+ "i" (errret), "0" (retval)); \
+})
+
#define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
#else
#define __get_user_asm_u64(x, ptr, retval, errret) \
@@ -420,7 +438,7 @@ do { \
#define __get_user_nocheck(x, ptr, size) \
({ \
int __gu_err; \
- unsigned long __gu_val; \
+ __inttype(*(ptr)) __gu_val; \
__uaccess_begin(); \
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
__uaccess_end(); \

--
"Thought is the essence of where you are now."

2016-03-09 19:43:05

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user() v2

Hi Benjamin,

[auto build test WARNING on tip/x86/core]
[also build test WARNING on v4.5-rc7 next-20160309]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Benjamin-LaHaise/x86_32-add-support-for-64-bit-__get_user-v2/20160310-033507
config: i386-tinyconfig (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All warnings (new ones prefixed by >>):

In file included from arch/x86/include/asm/sections.h:5:0,
from arch/x86/include/asm/hw_irq.h:26,
from include/linux/irq.h:418,
from arch/x86/include/asm/hardirq.h:5,
from include/linux/hardirq.h:8,
from include/linux/memcontrol.h:24,
from include/linux/tracehook.h:53,
from arch/x86/kernel/ptrace.c:14:
arch/x86/kernel/ptrace.c: In function 'genregs_set':
>> arch/x86/kernel/ptrace.c:530:28: warning: operation on 'u' may be undefined [-Wsequence-point]
ret = __get_user(word, u++);
^
arch/x86/include/asm/uaccess.h:451:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
>> arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
>> arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
>> arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
>> arch/x86/kernel/ptrace.c:530:10: note: in expansion of macro '__get_user'
ret = __get_user(word, u++);
^
--
In file included from lib/bitmap.c:17:0:
lib/bitmap.c: In function '__bitmap_parse':
>> lib/bitmap.c:377:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
arch/x86/include/asm/uaccess.h:451:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
>> arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
>> arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
>> arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
>> lib/bitmap.c:377:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^
lib/bitmap.c: In function '__bitmap_parselist':
lib/bitmap.c:525:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
arch/x86/include/asm/uaccess.h:451:51: note: in definition of macro '__m'
#define __m(x) (*(struct __large_struct __user *)(x))
^
>> arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
>> arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
>> arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
lib/bitmap.c:525:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^

vim +/__get_user_asm_u64 +378 arch/x86/include/asm/uaccess.h

3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 372 __get_user_asm(x, ptr, retval, "w", "w", "=r", errret); \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 373 break; \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 374 case 4: \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 375 __get_user_asm(x, ptr, retval, "l", "k", "=r", errret); \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 376 break; \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 377 case 8: \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 @378 __get_user_asm_u64(x, ptr, retval, errret); \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 379 break; \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 380 default: \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 381 (x) = __get_user_bad(); \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 382 } \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 383 } while (0)
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 384
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 385 #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 386 asm volatile("\n" \
63bcff2a arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-09-21 387 "1: mov"itype" %2,%"rtype"1\n" \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 388 "2:\n" \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 389 ".section .fixup,\"ax\"\n" \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 390 "3: mov %3,%0\n" \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 391 " xor"itype" %"rtype"1,%"rtype"1\n" \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 392 " jmp 2b\n" \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 393 ".previous\n" \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 394 _ASM_EXTABLE(1b, 3b) \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 395 : "=r" (err), ltype(x) \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 396 : "m" (__m(addr)), "i" (errret), "0" (err))
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 397
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 398 /*
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 399 * This doesn't do __uaccess_begin/end - the exception handling
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 400 * around it must do that.
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 401 */
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 402 #define __get_user_size_ex(x, ptr, size) \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 403 do { \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 404 __chk_user_ptr(ptr); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 405 switch (size) { \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 406 case 1: \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 407 __get_user_asm_ex(x, ptr, "b", "b", "=q"); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 408 break; \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 409 case 2: \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 410 __get_user_asm_ex(x, ptr, "w", "w", "=r"); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 411 break; \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 412 case 4: \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 413 __get_user_asm_ex(x, ptr, "l", "k", "=r"); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 414 break; \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 415 case 8: \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 416 __get_user_asm_ex_u64(x, ptr); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 417 break; \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 418 default: \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 419 (x) = __get_user_bad(); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 420 } \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 421 } while (0)
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 422
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 423 #define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
5e88353d arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-09-21 424 asm volatile("1: mov"itype" %1,%"rtype"0\n" \
5e88353d arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-09-21 425 "2:\n" \
535c0c34 arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-04-20 426 _ASM_EXTABLE_EX(1b, 2b) \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 427 : ltype(x) : "m" (__m(addr)))
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 428
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 429 #define __put_user_nocheck(x, ptr, size) \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 430 ({ \
16855f87 arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2008-12-08 431 int __pu_err; \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 432 __uaccess_begin(); \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 433 __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 434 __uaccess_end(); \
a76cf66e arch/x86/include/asm/uaccess.h Andy Lutomirski 2015-10-05 435 __builtin_expect(__pu_err, 0); \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 436 })
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 437
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 438 #define __get_user_nocheck(x, ptr, size) \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 439 ({ \
16855f87 arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2008-12-08 440 int __gu_err; \
7dd119d0 arch/x86/include/asm/uaccess.h Benjamin LaHaise 2016-03-09 441 __inttype(*(ptr)) __gu_val; \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 442 __uaccess_begin(); \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 @443 __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 444 __uaccess_end(); \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 445 (x) = (__force __typeof__(*(ptr)))__gu_val; \
a76cf66e arch/x86/include/asm/uaccess.h Andy Lutomirski 2015-10-05 446 __builtin_expect(__gu_err, 0); \
3f168221 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 447 })
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 448
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 449 /* FIXME: this hack is definitely wrong -AK */
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 450 struct __large_struct { unsigned long buf[100]; };
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 @451 #define __m(x) (*(struct __large_struct __user *)(x))
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 452
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 453 /*
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 454 * Tell gcc we read from memory instead of writing: this is because
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 455 * we do not write to any memory gcc knows about, so there are no
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 456 * aliasing issues.
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 457 */
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 458 #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 459 asm volatile("\n" \
63bcff2a arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-09-21 460 "1: mov"itype" %"rtype"1,%2\n" \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 461 "2:\n" \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 462 ".section .fixup,\"ax\"\n" \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 463 "3: mov %3,%0\n" \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 464 " jmp 2b\n" \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 465 ".previous\n" \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 466 _ASM_EXTABLE(1b, 3b) \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 467 : "=r"(err) \
dc70ddf4 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 468 : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 469
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 470 #define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
5e88353d arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-09-21 471 asm volatile("1: mov"itype" %"rtype"0,%1\n" \
5e88353d arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-09-21 472 "2:\n" \
535c0c34 arch/x86/include/asm/uaccess.h H. Peter Anvin 2012-04-20 473 _ASM_EXTABLE_EX(1b, 2b) \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 474 : : ltype(x), "m" (__m(addr)))
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 475
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 476 /*
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 477 * uaccess_try and catch
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 478 */
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 479 #define uaccess_try do { \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 480 current_thread_info()->uaccess_err = 0; \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 481 __uaccess_begin(); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 482 barrier();
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 483
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 484 #define uaccess_catch(err) \
11f1a4b9 arch/x86/include/asm/uaccess.h Linus Torvalds 2015-12-17 485 __uaccess_end(); \
4fc34901 arch/x86/include/asm/uaccess.h Andy Lutomirski 2011-11-07 486 (err) |= (current_thread_info()->uaccess_err ? -EFAULT : 0); \
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 487 } while (0)
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 488
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 489 /**
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 490 * __get_user: - Get a simple variable from user space, with less checking.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 491 * @x: Variable to store result.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 492 * @ptr: Source address, in user space.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 493 *
b3c395ef arch/x86/include/asm/uaccess.h David Hildenbrand 2015-05-11 494 * Context: User context only. This function may sleep if pagefaults are
b3c395ef arch/x86/include/asm/uaccess.h David Hildenbrand 2015-05-11 495 * enabled.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 496 *
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 497 * This macro copies a single simple variable from user space to kernel
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 498 * space. It supports simple types like char and int, but not larger
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 499 * data types like structures or arrays.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 500 *
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 501 * @ptr must have pointer-to-simple-variable type, and the result of
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 502 * dereferencing @ptr must be assignable to @x without a cast.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 503 *
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 504 * Caller must check the pointer with access_ok() before calling this
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 505 * function.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 506 *
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 507 * Returns zero on success, or -EFAULT on error.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 508 * On error, the variable @x is set to zero.
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 509 */
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 510
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 511 #define __get_user(x, ptr) \
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 @512 __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
fe40c0af arch/x86/include/asm/uaccess.h Hiroshi Shimamoto 2009-01-23 513
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 514 /**
8cb834e9 include/asm-x86/uaccess.h Glauber Costa 2008-06-25 515 * __put_user: - Write a simple value into user space, with less checking.

:::::: The code at line 378 was first introduced by commit
:::::: 3f168221167ca7a844fde3bf58e1c7ca0bf9741e x86: merge __get_user_asm and its users.

:::::: TO: Glauber Costa <[email protected]>
:::::: CC: Ingo Molnar <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (19.02 kB)
.config.gz (6.06 kB)
Download all attachments

2016-03-09 20:06:11

by Benjamin LaHaise

[permalink] [raw]
Subject: [PATCH] x86_32: add support for 64 bit __get_user() v3

The existing __get_user() implementation does not support fetching
64 bit values on 32 bit x86. Implement this in a way that does not
generate any incorrect warnings as cautioned by Russell King. Test
code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .

v2: use __inttype() as suggested by H. Peter Anvin, which cleans the
code up nicely, and fix things to work on x86_64 as well.

v3: fix undefined behaviour on 32 bit x86 caused by multiple expansion
of ptr in the 64 bit case.

Signed-off-by: Benjamin LaHaise <[email protected]>

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index a4a30e4..8743552 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -333,7 +333,26 @@ do { \
} while (0)

#ifdef CONFIG_X86_32
-#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad()
+#define __get_user_asm_u64(x, ptr, retval, errret) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ asm volatile(ASM_STAC "\n" \
+ "1: movl %2,%%eax\n" \
+ "2: movl %3,%%edx\n" \
+ "3: " ASM_CLAC "\n" \
+ ".section .fixup,\"ax\"\n" \
+ "4: mov %4,%0\n" \
+ " xorl %%eax,%%eax\n" \
+ " xorl %%edx,%%edx\n" \
+ " jmp 3b\n" \
+ ".previous\n" \
+ _ASM_EXTABLE(1b, 4b) \
+ _ASM_EXTABLE(2b, 4b) \
+ : "=r" (retval), "=A"(x) \
+ : "m" (__m(__ptr)), "m" __m(((u32 *)(__ptr)) + 1), \
+ "i" (errret), "0" (retval)); \
+})
+
#define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
#else
#define __get_user_asm_u64(x, ptr, retval, errret) \
@@ -420,7 +439,7 @@ do { \
#define __get_user_nocheck(x, ptr, size) \
({ \
int __gu_err; \
- unsigned long __gu_val; \
+ __inttype(*(ptr)) __gu_val; \
__uaccess_begin(); \
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
__uaccess_end(); \

--
"Thought is the essence of where you are now."

2016-03-09 20:25:16

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user() v2

Hi Benjamin,

[auto build test WARNING on tip/x86/core]
[also build test WARNING on v4.5-rc7 next-20160309]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]

url: https://github.com/0day-ci/linux/commits/Benjamin-LaHaise/x86_32-add-support-for-64-bit-__get_user-v2/20160310-033507
config: i386-randconfig-s1-201610 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All warnings (new ones prefixed by >>):

In file included from include/uapi/linux/stddef.h:1:0,
from include/linux/stddef.h:4,
from include/uapi/linux/posix_types.h:4,
from include/uapi/linux/types.h:13,
from include/linux/types.h:5,
from include/linux/thread_info.h:10,
from lib/bitmap.c:9:
lib/bitmap.c: In function '__bitmap_parse':
lib/bitmap.c:377:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
include/linux/compiler.h:147:28: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
>> lib/bitmap.c:377:5: note: in expansion of macro 'if'
if (__get_user(c, ubuf++))
^
>> arch/x86/include/asm/uaccess.h:351:15: note: in expansion of macro '__m'
: "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
^
arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
lib/bitmap.c:377:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^
lib/bitmap.c:377:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
include/linux/compiler.h:147:40: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
>> lib/bitmap.c:377:5: note: in expansion of macro 'if'
if (__get_user(c, ubuf++))
^
>> arch/x86/include/asm/uaccess.h:351:15: note: in expansion of macro '__m'
: "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
^
arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
lib/bitmap.c:377:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^
lib/bitmap.c:377:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
include/linux/compiler.h:158:16: note: in definition of macro '__trace_if'
______r = !!(cond); \
^
>> lib/bitmap.c:377:5: note: in expansion of macro 'if'
if (__get_user(c, ubuf++))
^
>> arch/x86/include/asm/uaccess.h:351:15: note: in expansion of macro '__m'
: "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
^
arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
lib/bitmap.c:377:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^
lib/bitmap.c: In function '__bitmap_parselist':
lib/bitmap.c:525:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
include/linux/compiler.h:147:28: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
lib/bitmap.c:525:5: note: in expansion of macro 'if'
if (__get_user(c, ubuf++))
^
>> arch/x86/include/asm/uaccess.h:351:15: note: in expansion of macro '__m'
: "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
^
arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
lib/bitmap.c:525:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^
lib/bitmap.c:525:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
include/linux/compiler.h:147:40: note: in definition of macro '__trace_if'
if (__builtin_constant_p((cond)) ? !!(cond) : \
^
lib/bitmap.c:525:5: note: in expansion of macro 'if'
if (__get_user(c, ubuf++))
^
>> arch/x86/include/asm/uaccess.h:351:15: note: in expansion of macro '__m'
: "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
^
arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
lib/bitmap.c:525:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^
lib/bitmap.c:525:27: warning: operation on 'ubuf' may be undefined [-Wsequence-point]
if (__get_user(c, ubuf++))
^
include/linux/compiler.h:158:16: note: in definition of macro '__trace_if'
______r = !!(cond); \
^
lib/bitmap.c:525:5: note: in expansion of macro 'if'
if (__get_user(c, ubuf++))
^
>> arch/x86/include/asm/uaccess.h:351:15: note: in expansion of macro '__m'
: "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
^
arch/x86/include/asm/uaccess.h:378:3: note: in expansion of macro '__get_user_asm_u64'
__get_user_asm_u64(x, ptr, retval, errret); \
^
arch/x86/include/asm/uaccess.h:443:2: note: in expansion of macro '__get_user_size'
__get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
^
arch/x86/include/asm/uaccess.h:512:2: note: in expansion of macro '__get_user_nocheck'
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
^
lib/bitmap.c:525:9: note: in expansion of macro '__get_user'
if (__get_user(c, ubuf++))
^

vim +/__m +351 arch/x86/include/asm/uaccess.h

335 #ifdef CONFIG_X86_32
336 #define __get_user_asm_u64(x, ptr, retval, errret) \
337 ({ \
338 asm volatile(ASM_STAC "\n" \
339 "1: movl %2,%%eax\n" \
340 "2: movl %3,%%edx\n" \
341 "3: " ASM_CLAC "\n" \
342 ".section .fixup,\"ax\"\n" \
343 "4: mov %4,%0\n" \
344 " xorl %%eax,%%eax\n" \
345 " xorl %%edx,%%edx\n" \
346 " jmp 3b\n" \
347 ".previous\n" \
348 _ASM_EXTABLE(1b, 4b) \
349 _ASM_EXTABLE(2b, 4b) \
350 : "=r" (retval), "=A"(x) \
> 351 : "m" (__m(ptr)), "m" __m(((u32 *)(ptr)) + 1), \
352 "i" (errret), "0" (retval)); \
353 })
354
355 #define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
356 #else
357 #define __get_user_asm_u64(x, ptr, retval, errret) \
358 __get_user_asm(x, ptr, retval, "q", "", "=r", errret)
359 #define __get_user_asm_ex_u64(x, ptr) \

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (8.88 kB)
.config.gz (21.08 kB)
Download all attachments

2016-03-14 15:37:51

by Benjamin LaHaise

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user() v3

Any more comments/feedback on this? Can this be merged for 4.6?

-ben

On Wed, Mar 09, 2016 at 03:05:56PM -0500, Benjamin LaHaise wrote:
> The existing __get_user() implementation does not support fetching
> 64 bit values on 32 bit x86. Implement this in a way that does not
> generate any incorrect warnings as cautioned by Russell King. Test
> code available at http://www.kvack.org/~bcrl/x86_32-get_user.tar .
>
> v2: use __inttype() as suggested by H. Peter Anvin, which cleans the
> code up nicely, and fix things to work on x86_64 as well.
>
> v3: fix undefined behaviour on 32 bit x86 caused by multiple expansion
> of ptr in the 64 bit case.
>
> Signed-off-by: Benjamin LaHaise <[email protected]>
>
> diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
> index a4a30e4..8743552 100644
> --- a/arch/x86/include/asm/uaccess.h
> +++ b/arch/x86/include/asm/uaccess.h
> @@ -333,7 +333,26 @@ do { \
> } while (0)
>
> #ifdef CONFIG_X86_32
> -#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad()
> +#define __get_user_asm_u64(x, ptr, retval, errret) \
> +({ \
> + __typeof__(ptr) __ptr = (ptr); \
> + asm volatile(ASM_STAC "\n" \
> + "1: movl %2,%%eax\n" \
> + "2: movl %3,%%edx\n" \
> + "3: " ASM_CLAC "\n" \
> + ".section .fixup,\"ax\"\n" \
> + "4: mov %4,%0\n" \
> + " xorl %%eax,%%eax\n" \
> + " xorl %%edx,%%edx\n" \
> + " jmp 3b\n" \
> + ".previous\n" \
> + _ASM_EXTABLE(1b, 4b) \
> + _ASM_EXTABLE(2b, 4b) \
> + : "=r" (retval), "=A"(x) \
> + : "m" (__m(__ptr)), "m" __m(((u32 *)(__ptr)) + 1), \
> + "i" (errret), "0" (retval)); \
> +})
> +
> #define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
> #else
> #define __get_user_asm_u64(x, ptr, retval, errret) \
> @@ -420,7 +439,7 @@ do { \
> #define __get_user_nocheck(x, ptr, size) \
> ({ \
> int __gu_err; \
> - unsigned long __gu_val; \
> + __inttype(*(ptr)) __gu_val; \
> __uaccess_begin(); \
> __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \
> __uaccess_end(); \
>
> --
> "Thought is the essence of where you are now."

--
"Thought is the essence of where you are now."

2016-03-14 16:39:39

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] x86_32: add support for 64 bit __get_user() v3


* Benjamin LaHaise <[email protected]> wrote:

> Any more comments/feedback on this? Can this be merged for 4.6?

Will get to it once the merge window calms down.

Thanks,

Ingo