diff options
author | Mark Wielaard <mjw@redhat.com> | 2014-08-27 17:07:58 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2014-08-28 09:53:08 +0200 |
commit | 9570bc53fcc11d3cfe028989e611266e8d55bd09 (patch) | |
tree | b282e160fc7057dcb9b8a5ea9fa3f5c5fea73de7 /sysdeps/i386 | |
parent | b0f955c9ac70181532e93aa78c49c204c2a31dfd (diff) | |
download | glibc-9570bc53fcc11d3cfe028989e611266e8d55bd09.tar glibc-9570bc53fcc11d3cfe028989e611266e8d55bd09.tar.gz glibc-9570bc53fcc11d3cfe028989e611266e8d55bd09.tar.bz2 glibc-9570bc53fcc11d3cfe028989e611266e8d55bd09.zip |
i386 TLS_INIT_TP might produce bogus asm changing stack pointer [BZ #17319]
TLS_INIT_TP in sysdeps/i386/nptl/tls.h uses some hand written asm to
generate a set_thread_area that might result in exchanging ebx and esp
around the syscall causing introspection tools like valgrind to loose
track of the user stack. Just use INTERNAL_SYSCALL which makes sure
esp isn't changed arbitrarily.
Before the patch the code would generate:
mov $0xf3,%eax
movl $0xfffff,0x8(%esp)
movl $0x51,0xc(%esp)
xchg %esp,%ebx
int $0x80
xchg %esp,%ebx
Using INTERNAL_SYSCALL instead will generate:
movl $0xfffff,0x8(%esp)
movl $0x51,0xc(%esp)
xchg %ecx,%ebx
mov $0xf3,%eax
int $0x80
xchg %ecx,%ebx
Thanks to Florian Weimer for analysing why the original code generated
the bogus esp usage:
_segdescr.desc happens to be at the top of the stack, so its address
is in %esp. The asm statement says that %3 is an input, so its value
will not change, and GCC can use %esp as the input register for the
expression &_segdescr.desc. But the constraints do not fully describe
the asm statement because the %3 register is actually modified, albeit
only temporarily.
[BZ #17319]
* sysdeps/i386/nptl/tls.h (TLS_INIT_TP): Use INTERNAL_SYSCALL
to call set_thread_area instead of hand written asm.
(__NR_set_thread_area): Removed define.
(TLS_FLAG_WRITABLE): Likewise.
(__ASSUME_SET_THREAD_AREA): Remove check.
(TLS_EBX_ARG): Remove define.
(TLS_LOAD_EBX): Likewise.
Diffstat (limited to 'sysdeps/i386')
-rw-r--r-- | sysdeps/i386/nptl/tls.h | 31 |
1 files changed, 2 insertions, 29 deletions
diff --git a/sysdeps/i386/nptl/tls.h b/sysdeps/i386/nptl/tls.h index ac9c9a22f9..d7302ba8aa 100644 --- a/sysdeps/i386/nptl/tls.h +++ b/sysdeps/i386/nptl/tls.h @@ -154,29 +154,6 @@ union user_desc_init __asm ("movw %w0, %%gs" :: "q" (val)) # endif - -# ifndef __NR_set_thread_area -# define __NR_set_thread_area 243 -# endif -# ifndef TLS_FLAG_WRITABLE -# define TLS_FLAG_WRITABLE 0x00000001 -# endif - -// XXX Enable for the real world. -#if 0 -# ifndef __ASSUME_SET_THREAD_AREA -# error "we need set_thread_area" -# endif -#endif - -# ifdef __PIC__ -# define TLS_EBX_ARG "r" -# define TLS_LOAD_EBX "xchgl %3, %%ebx\n\t" -# else -# define TLS_EBX_ARG "b" -# define TLS_LOAD_EBX -# endif - #if defined NEED_DL_SYSINFO # define INIT_SYSINFO \ _head->sysinfo = GLRO(dl_sysinfo) @@ -231,12 +208,8 @@ tls_fill_user_desc (union user_desc_init *desc, tls_fill_user_desc (&_segdescr, -1, _thrdescr); \ \ /* Install the TLS. */ \ - asm volatile (TLS_LOAD_EBX \ - "int $0x80\n\t" \ - TLS_LOAD_EBX \ - : "=a" (_result), "=m" (_segdescr.desc.entry_number) \ - : "0" (__NR_set_thread_area), \ - TLS_EBX_ARG (&_segdescr.desc), "m" (_segdescr.desc)); \ + INTERNAL_SYSCALL_DECL (err); \ + _result = INTERNAL_SYSCALL (set_thread_area, err, 1, &_segdescr.desc); \ \ if (_result == 0) \ /* We know the index in the GDT, now load the segment register. \ |