Bug #11642 [Patch]es x86 Assembler and text relocations
Submitted: 29 Jun 2005 14:57 Modified: 8 Aug 2005 12:43
Reporter: Miguel Solorzano Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:4.0/4.1/5.0 OS:Any (all)
Assigned to: Michael Widenius CPU Architecture:Any

[29 Jun 2005 14:57] Miguel Solorzano
Description:
Assembler code contained in some of the assembler string functions (used
if "configure --enable-assembler") contain text relocations.
This prevent the enforcement of some security policies if MySQL database
is used.
Full reference at "http://bugs.gentoo.org/42968"

The patches attached cover MySQL versions 4.0, 4.1, 5.0.

035_x86_asm-pic-fixes-r0.patch ==> mysql-4.0
strings/longlong2str-x86.s
strings/strings-x86.s

035_x86_asm-pic-fixes-r1.patch ==> mysql-4.1, mysql-5.0
strings/longlong2str-x86.s
strings/my_strtoll10-x86.s
strings/strings-x86.s

Tests done:
The environment described in the attached file
mysqlbug_hardened_mysql-5.0.6_beta.txt is running a slave database of a
production system. (and pass all the testsuite)
On another x86 box it has run in many /not/ hardened environments,
ranging from
gcc-3.3.5-20050130, glibc-2.3.4.20041102-r1
to
gcc-4.0.1-beta20050507, glibc-2.3.5.20050421
without problem related to these patches.

Benchmarking:
Performances seem unchanged, or with not measurable differences (after
few and quick tests).

regards
Francesco Riosa
vivo at gentoo.org

Environment:
        <machine, os, target, libraries (multiple lines)>
System: Linux aps 2.6.11-hardened-r13 #1 Tue Jun 14 07:17:35 CEST 2005 i686   GNU/Linux
Architecture: i686

Some paths:  /usr/bin/perl /usr/bin/make /usr/bin/gmake /usr/bin/gcc /usr/bin/cc
GCC: Reading specs from /usr/lib/gcc/i686-pc-linux-gnu/3.4.4/specs
Configured with: /var/tmp/portage/gcc-3.4.4/work/gcc-3.4.4/configure --enable-version-specific-runtime-libs --prefix=/usr --bindir=/usr/i686-p
c-linux-gnu/gcc-bin/3.4.4 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.4/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.4 --ma
ndir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.4/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.4/info --with-gxx-include-dir=/usr/li
b/gcc/i686-pc-linux-gnu/3.4.4/include/g++-v3 --host=i686-pc-linux-gnu --disable-altivec --enable-nls --without-included-gettext --with-system-
zlib --disable-checking --disable-werror --disable-libunwind-exceptions --disable-multilib --disable-libgcj --enable-languages=c,c++ --enable-
shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu
Thread model: posix
gcc version 3.4.4 (Gentoo Hardened 3.4.4, ssp-3.4.4-1.0, pie-8.7.8)
Compilation info: CC='i686-pc-linux-gnu-gcc'  CFLAGS='-O2 -march=athlon-xp -fomit-frame-pointer -fforce-addr -fstack-protector -DHAVE_ERRNO_AS
_DEFINE=1'  CXX='i686-pc-linux-gnu-g++'  CXXFLAGS='-O2 -march=athlon-xp -fomit-frame-pointer -fforce-addr -fstack-protector -DHAVE_ERRNO_AS_DE
FINE=1 -fno-implicit-templates -felide-constructors -fno-exceptions -fno-rtti'  LDFLAGS=''  ASFLAGS=''
LIBC:
lrwxrwxrwx  1 root root 13 Jun 14 14:01 /lib/libc.so.6 -> libc-2.3.5.so
-rwxr-xr-x  1 root root 1307808 Jun 14 05:09 /lib/libc-2.3.5.so
-rw-r--r--  1 root root 3162920 Jun 14 05:09 /usr/lib/libc.a
-rwxr-xr-x  1 root root 204 Jun 14 05:09 /usr/lib/libc.so
Configure command: ./configure '--prefix=/usr' '--host=i686-pc-linux-gnu' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--datadir=/us
r/share' '--sysconfdir=/etc' '--localstatedir=/var/lib' '--libexecdir=/usr/sbin' '--sysconfdir=/etc/mysql' '--localstatedir=/var/lib/mysql' '-
-with-low-memory' '--enable-assembler' '--enable-local-infile' '--with-mysqld-user=mysql' '--with-client-ldflags=-lstdc++' '--enable-thread-sa
fe-client' '--with-comment=Gentoo Linux mysql-5.0.6_beta-r1' '--with-unix-socket-path=/var/run/mysqld/mysqld.sock' '--with-zlib-dir=/usr' '--w
ith-lib-ccflags=-fPIC' '--without-embedded-server' '--without-readline' '--enable-shared' '--enable-static' '--with-libwrap' '--with-openssl'
'--without-debug' '--with-bench' '--with-server' '--with-embedded-server' '--with-extra-tools' '--with-innodb' '--with-raid' '--with-extra-cha
rsets=all' '--with-berkeley-db=./bdb' '--with-geometry' '--without-ndbcluster' '--with-big-tables' '--without-docs' '--with-archive-storage-en
gine' '--with-csv-storage-engine' '--with-federated-storage-engine' '--with-blackhole-storage-engine' 'CFLAGS=-O2 -march=athlon-xp -fomit-fram
e-pointer -fforce-addr -fstack-protector -DHAVE_ERRNO_AS_DEFINE=1' 'CXXFLAGS=-O2 -march=athlon-xp -fomit-frame-pointer -fforce-addr -fstack-pr
otector -DHAVE_ERRNO_AS_DEFINE=1 -fno-implicit-templates -felide-constructors -fno-exceptions -fno-rtti' 'host_alias=i686-pc-linux-gnu'

###MY_VER_RANGE [4.1,5.1_alpha)
diff -Nurp mysql/strings/longlong2str-x86.s mysql-fixed/strings/longlong2str-x86.s
--- mysql/strings/longlong2str-x86.s    2005-05-13 12:32:11.000000000 +0100
+++ mysql-fixed/strings/longlong2str-x86.s      2005-05-25 01:19:32.000000000 +0100
@@ -19,6 +19,13 @@
        .file   "longlong2str.s"
        .version "1.01"
 
+       .section        .rodata
+       .align 32
+       .type   _dig_vec_upper, @object
+       .size   _dig_vec_upper, 37
+_dig_vec_upper:
+       .string "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
 .text
        .align 4
 
@@ -31,11 +38,14 @@ longlong2str:
        pushl %esi
        pushl %edi
        pushl %ebx
+
+       call __i686.get_pc_thunk.bx
+       addl $_GLOBAL_OFFSET_TABLE_,%ebx
+
        movl 100(%esp),%esi     # Lower part of val 
        movl 104(%esp),%ebp     # Higher part of val 
        movl 108(%esp),%edi     # get dst 
-       movl 112(%esp),%ebx     # Radix 
-       movl %ebx,%eax
+       movl 112(%esp),%eax     # Radix 
        testl %eax,%eax
        jge .L144
 
@@ -50,7 +60,7 @@ longlong2str:
        adcl $0,%ebp
        negl %ebp
 .L146:
-       negl %ebx               # Change radix to positive 
+       negl 112(%esp)          # Change radix to positive 
        jmp .L148
        .align 4
 .L144:
@@ -77,13 +87,13 @@ longlong2str:
 
        movl %ebp,%eax          # High part of value 
        xorl %edx,%edx
-       divl %ebx
+       divl 112(%esp)
        movl %eax,%ebp
        movl %esi,%eax
-       divl %ebx
+       divl 112(%esp)
        decl %ecx
        movl %eax,%esi          # quotent in ebp:esi 
-       movb _dig_vec_upper(%edx),%al   # al is faster than dl 
+       movb _dig_vec_upper@GOTOFF(%ebx,%edx),%al   # al is faster than dl
        movb %al,(%ecx)         # store value in buff 
        .align 4
 .L155:
@@ -93,14 +103,13 @@ longlong2str:
        jl .L153
        je .L10_mov             # Ready 
        movl %esi,%eax
-       movl $_dig_vec_upper,%ebp
        .align 4
 
 .L154:                         # Do rest with integer precision 
        cltd
-       divl %ebx
+       divl 112(%esp)
        decl %ecx
-       movb (%edx,%ebp),%dl    # bh is always zero as ebx=radix < 36 
+       movb _dig_vec_upper@GOTOFF(%ebx,%edx),%dl
        testl %eax,%eax
        movb %dl,(%ecx)
        jne .L154
@@ -137,9 +146,6 @@ longlong2str:
 #      
 
        .align 4
-.Ltmp:
-        .long 0xcccccccd
-       .align 4
        
 .globl longlong10_to_str
        .type    longlong10_to_str,@function
@@ -202,7 +208,7 @@ longlong10_to_str:
 
        # The following code uses some tricks to change division by 10 to
        # multiplication and shifts
-       movl .Ltmp,%esi         # set %esi to 0xcccccccd
+       movl $0xcccccccd,%esi   # set %esi to 0xcccccccd
        
 .L10_40:
         movl %ebx,%eax
@@ -221,3 +227,13 @@ longlong10_to_str:
 
 .L10end:
        .size    longlong10_to_str,.L10end-longlong10_to_str
+
+       .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+.globl __i686.get_pc_thunk.bx
+       .hidden __i686.get_pc_thunk.bx
+       .type   __i686.get_pc_thunk.bx, @function
+__i686.get_pc_thunk.bx:
+       movl    (%esp), %ebx
+       ret
+
+       .section        .note.GNU-stack,"",@progbits
diff -Nurp mysql/strings/my_strtoll10-x86.s mysql-fixed/strings/my_strtoll10-x86.s
--- mysql/strings/my_strtoll10-x86.s    2005-05-13 12:32:22.000000000 +0100
+++ mysql-fixed/strings/my_strtoll10-x86.s      2005-05-25 01:13:23.000000000 +0100
@@ -18,7 +18,7 @@
        
        .file   "my_strtoll10-x86.s"
        .version "01.01"
-.data
+.section .rodata
        .align 32
        .type    lfactor,@object
        .size    lfactor,36
@@ -315,7 +315,11 @@ my_strtoll10:
 .Lend_i_and_j:
        movl %esi,%ecx
        subl -12(%ebp),%ecx     # ecx= number of digits in second part
-       movl lfactor(,%ecx,4),%eax
+
+       call __i686.get_pc_thunk.bx
+       addl $_GLOBAL_OFFSET_TABLE_,%ebx
+
+       movl lfactor@GOTOFF(%ebx,%ecx,4),%eax
        jmp .L523
 
        # Return -8(%ebp) * $1000000000 + edi
@@ -400,3 +404,13 @@ my_strtoll10:
         .comm   end_ptr,120,32
         .comm   error,120,32
        .ident  "Monty"
+
+       .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+.globl __i686.get_pc_thunk.bx
+       .hidden __i686.get_pc_thunk.bx
+       .type   __i686.get_pc_thunk.bx, @function
+__i686.get_pc_thunk.bx:
+       movl    (%esp), %ebx
+       ret
+
+       .section        .note.GNU-stack,"",@progbits
diff -Nurp mysql/strings/strings-x86.s mysql-fixed/strings/strings-x86.s
--- mysql/strings/strings-x86.s 2005-05-13 12:32:40.000000000 +0100
+++ mysql-fixed/strings/strings-x86.s   2005-05-23 23:19:13.000000000 +0100
@@ -415,3 +415,5 @@ next_str:
        ret
 .strxmov_end:
        .size    strxmov,.strxmov_end-strxmov
+
+       .section        .note.GNU-stack,"",@progbits

###MY_VER_RANGE [4.0.24,4.1_alpha)
--- mysql-4.0.24/strings/longlong2str-x86.s     2005-03-05 00:38:14.000000000 +0000
+++ mysql-4.0.24-fixed/strings/longlong2str-x86.s       2005-05-17 01:37:52.000000000 +0100
@@ -19,6 +19,13 @@
        .file   "longlong2str.s"
        .version "1.01"
 
+       .section        .rodata
+       .align 32
+       .type   _dig_vec, @object
+       .size   _dig_vec, 37
+_dig_vec:
+       .string "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
 .text
        .align 4
 
@@ -31,11 +38,14 @@ longlong2str:
        pushl %esi
        pushl %edi
        pushl %ebx
+
+       call __i686.get_pc_thunk.bx
+       addl $_GLOBAL_OFFSET_TABLE_,%ebx
+
        movl 100(%esp),%esi     # Lower part of val 
        movl 104(%esp),%ebp     # Higher part of val 
        movl 108(%esp),%edi     # get dst 
-       movl 112(%esp),%ebx     # Radix 
-       movl %ebx,%eax
+       movl 112(%esp),%eax     # Radix 
        testl %eax,%eax
        jge .L144
 
@@ -50,7 +60,7 @@ longlong2str:
        adcl $0,%ebp
        negl %ebp
 .L146:
-       negl %ebx               # Change radix to positive 
+       negl 112(%esp)          # Change radix to positive 
        jmp .L148
        .align 4
 .L144:
@@ -77,12 +87,12 @@ longlong2str:
 
        movl %ebp,%eax          # High part of value 
        xorl %edx,%edx
-       divl %ebx
+       divl 112(%esp)
        movl %eax,%ebp
        movl %esi,%eax
-       divl %ebx
+       divl 112(%esp)
        movl %eax,%esi          # quotent in ebp:esi 
-       movb _dig_vec(%edx),%al   # al is faster than dl 
+       movb _dig_vec@GOTOFF(%ebx,%edx),%al   # al is faster than dl 
        decl %ecx
        movb %al,(%ecx)         # store value in buff 
        .align 4
@@ -93,14 +103,13 @@ longlong2str:
        jl .L153
        je .L160                # Ready 
        movl %esi,%eax
-       movl $_dig_vec,%ebp
        .align 4
 
 .L154:                         # Do rest with integer precision 
        cltd
-       divl %ebx
+       divl 112(%esp)
        decl %ecx
-       movb (%edx,%ebp),%dl    # bh is always zero as ebx=radix < 36 
+       movb _dig_vec@GOTOFF(%ebx,%edx),%dl
        testl %eax,%eax
        movb %dl,(%ecx)
        jne .L154
@@ -138,3 +147,13 @@ longlong10_to_str:
 
 .L10end:
        .size    longlong10_to_str,.L10end-longlong10_to_str
+
+       .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+.globl __i686.get_pc_thunk.bx
+       .hidden __i686.get_pc_thunk.bx
+       .type   __i686.get_pc_thunk.bx, @function
+__i686.get_pc_thunk.bx:
+       movl    (%esp), %ebx
+       ret
+
+       .section        .note.GNU-stack,"",@progbits
diff -Nurp mysql-4.0.24/strings/strings-x86.s mysql-4.0.24-fixed/strings/strings-x86.s
--- mysql-4.0.24/strings/strings-x86.s  2005-03-05 00:38:15.000000000 +0000
+++ mysql-4.0.24-fixed/strings/strings-x86.s    2005-05-17 01:37:47.000000000 +0100
@@ -403,3 +403,5 @@ next_str:
        ret
 .strxmov_end:
        .size    strxmov,.strxmov_end-strxmov
+
+       .section        .note.GNU-stack,"",@progbits 

How to repeat:
see description

Suggested fix:
see description
[14 Jul 2005 21:37] Peter Gulutzan
Suggested new /strings/longlong2str-x86.s (#1)

Attachment: longlong2str-x86.s (text/plain), 5.79 KiB.

[14 Jul 2005 21:55] Peter Gulutzan
I believe there are two separable issues here: text relocations and executable-stack
notes. I will address them separately.

The text relocation issue. This appears to be the main issue. The problem is
dig_vec_upper in longlong2str-x86.s. The suggested patch
(call __i686.get_pc_thunk.bx, div by a memory location rather than a register)
makes me (a) fearful of some compatibility issue on some unthought-of
platform, (b) certain that there would be a tiny performance loss. Therefore
I propose a rewritten longlong2str-x86.s where there is no reference to
dig_vec_upper. It would require some further tests, but I am sure at least
that the external reference is gone, and it is slightly faster than the current
version on some tests that I've conducted. The inspiration was a remark
by Kevin F. Quinn on the gentoo.org forum. Please check the "Files" box
for this bug and see if it might be a start toward meeting your actual needs.

The executable-stack notes issue. The addition of
.section .note.GNU-stack, "", @progbits
in every .s file seems reasonable, but I get the impression that it was
thrown in because it seems reasonable, not because it's absolutely
necessary to solve the original problem. I have also seen the remark
(on a Red Hat forum) that this is "non-portable to non-GNU", and the
suggestion that using "as --noexecstack ..." is equally reasonable. In
this respect I am not pretending expertise, but admitting an ignorance
which makes me reluctant to change all our .s files immediately.
[17 Jul 2005 19:16] Peter Gulutzan
Suggested new longlong2str-x86s (#2)

Attachment: longlong2str-x86.s (text/plain), 5.79 KiB.

[17 Jul 2005 19:19] Peter Gulutzan
The first attached file ("longlong2str-x86.s (#1)") has an error. Use "longlong2str-x86.s (#2)".
[19 Jul 2005 12:03] Francesco Riosa
Replacing the mysql-4.0.25 ./strings/longlong2str-x86.s with the 2nd one provided generate a clean build.

mysql-test-run return successfull result for both normal and hardened system (gentoo 2005.0 updated 20050718) .

speaking only of the hardened system from now on:

The ELF files are free of textrels as shown from "eu-findtextrel" program from "elfutils-0.108" .

following the list of "[ skipped ]" tests:
bdb-alter-table-1
bdb-alter-table-2
bdb-crash
bdb-deadlock
bdb
bdb_cache
lowercase_table2
lowercase_table3
openssl_1
rpl000018
rpl_chain_temp_table
rpl_failsafe
rpl_heap
rpl_trunc_binlog

extract from the "mysqlbug" utility

C++ compiler:  i686-pc-linux-gnu-g++ (GCC) 3.4.4 (Gentoo Hardened 3.4.4, ssp-3.4.4-1.0, pie-8.7.8)

System: Linux pinksky 2.6.11-hardened-r15 #3 Mon Jul 18 19:09:16 CEST 2005 i686 AMD Athlon(tm) processor AuthenticAMD GNU/Linux
Architecture: i686

Configured with: /var/tmp/portage/gcc-3.4.4/work/gcc-3.4.4/configure --enable-version-specific-runtime-libs --prefix=/usr --bindir=/usr/i686-pc-linux-gnu/gcc-bin/3.4.4 --includedir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.4/include --datadir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.4 --mandir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.4/man --infodir=/usr/share/gcc-data/i686-pc-linux-gnu/3.4.4/info --with-gxx-include-dir=/usr/lib/gcc/i686-pc-linux-gnu/3.4.4/include/g++-v3 --host=i686-pc-linux-gnu --build=i686-pc-linux-gnu --disable-altivec --enable-nls --without-included-gettext --with-system-zlib --disable-checking --disable-werror --disable-libunwind-exceptions --disable-multilib --disable-libgcj --enable-languages=c,c++,f77 --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu
Thread model: posix
[21 Jul 2005 21:35] Peter Gulutzan
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

http://lists.mysql.com/internals/27447
[21 Jul 2005 21:44] Peter Gulutzan
The patch should take care of the assembler text relocations.
For gnu-stack, there will have to be a separate patch
because I regard that as a different issue, and because
it might have to be unapplied separately from the
text-relocations patch. so I have created a new bug report:
bug#12096 Add line for non-executable stack in .s files.
(http://bugs.mysql.com/bug.php?id=12096&edit=1)

The patch is for version 5.0. Backporting to 4.1 is recommended.
[22 Jul 2005 14:21] Francesco Riosa
The comments mentioned from MySQL bug #12096 (trimmed).
BTW the home page of the "gentoo expert" is http://pax.grsecurity.net/ , that's not me.

>>>The executable-stack notes issue. The addition of
>>>.section .note.GNU-stack, "", @progbits
>>>in every .s file seems reasonable, but I get the impression that it was
>>>thrown in because it seems reasonable, not because it's absolutely
>>>necessary to solve the original problem. I have also seen the remark
>>>(on a Red Hat forum) that this is "non-portable to non-GNU", and the
>>>suggestion that using "as --noexecstack ..." is equally reasonable. In
>>>this respect I am not pretending expertise, but admitting an ignorance
>>>which makes me reluctant to change all our .s files immediately.

all correct above, here's my take.

1. an extra section has to be portable to all ELF platforms, at most
   the linker will simply ignore it. on another note, how many i386
   platforms does mysql run on that are non-GNU toolchain based yet
   use AT&T (i.e., UNIX) style asm?

2. there're more than two ways to deal with GNU_STACK (which i personally
   find a poor solution to the wrong problem btw, but we have to deal with
   the breakage it causes).

   - add a GNU-stack section to the .S
   - pass --{,no}execstack to as
   - pass -Wa,--{,no}execstack to gcc (when building the .o)
   - pass -Wl,--{,no}execstack to gcc (when building an executable or library)
   - use execstack -[sc] after build or installation (on the executable or
     library)

   as you can see, the earliest moment we can fix the problem is by
   adding that extra section to the .S (gcc 3.3 itself produces such
   as well when compiling a .c), so it's the preferred solution in
   general. the other solutions are acceptable as they still put the
   burden on the package author (we're not talking about mysql only,
   but all packages that a distro maintainer has to worry about), but
   it means that you either have to use per object ASFLAGS/LDFLAGS
   or mark everything without regard to their true need for executable
   stack - all are bound to fail and cause problems in the long run.

   from a distro maintenance point of view, the simplest (but still
   burdensome) approach is the last one, i.e., explicitly marking
   the binaries at the distro level, this is what (hardened) gentoo
   has been doing for some time now but we'd like to push these and
   other changes upstream. it's up to you to decide what you pick,
   at least i hope to have helped explain our side of the coin.
[8 Aug 2005 10:18] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/internals/27988
[8 Aug 2005 12:43] Michael Widenius
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.

If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information 
about accessing the source trees is available at
    http://www.mysql.com/doc/en/Installing_source_tree.html

Additional info:

Have now pushed a slightly smaller and faster fix than the one that Peter suggested
Fix will be in 4.1.14 and 5.0.11