This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug libc/23682] New: Inline assembly bugs wrt to arrays being passed through register constraints in io.h
- From: "mpetch at capp-sysware dot com" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sourceware dot org
- Date: Wed, 19 Sep 2018 01:06:29 +0000
- Subject: [Bug libc/23682] New: Inline assembly bugs wrt to arrays being passed through register constraints in io.h
- Auto-submitted: auto-generated
https://sourceware.org/bugzilla/show_bug.cgi?id=23682
Bug ID: 23682
Summary: Inline assembly bugs wrt to arrays being passed
through register constraints in io.h
Product: glibc
Version: unspecified
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: libc
Assignee: unassigned at sourceware dot org
Reporter: mpetch@capp-sysware.com
CC: drepper.fsp at gmail dot com
Target Milestone: ---
Created attachment 11259
--> https://sourceware.org/bugzilla/attachment.cgi?id=11259&action=edit
Revised io.h
This is a subtle big that could cause grief for those people doing direct
hardware access with <sys/io.h> on the x86/x86-64 Linux targets. This bug may
exist in other inline assembly elsewhere and an audit would probably not be a
bad idea. At the moment the bug can manifest itself in the functions insb,
insw, insl, outsb, outsw, outsl all of which pass a void *_addr to inline
assembly with a "=D", "D", "=S", "S" constraint.
This bug wasn't found because of an existing project failing. Recently someone
suggested on Stackoverflow using <sys/io.h> from GLIBC for port IO. I happened
to audit the code quickly and noticed the bug. I had seen this problem manifest
in other ways and just happen to know a way to reproduce the undesirable effect
in a minimal example.
The bug itself comes about because passing an address to a given object or
array as an input/output/both constraint VIA a register doesn't actually
guarantee that what the pointer points at has been realized into memory before
the assembly template is emitted. The same is true when an extended inline
assembly template writes to memory pointed at by a register constraint. This is
discussed in the GCC documentation @
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html in the section 6.45.2.6
Clobbers and Scratch Registers.
The compiler may assume with optimizations on that memory wasn't actually
modified and make code generation assumptions around that. One can observe the
problematic behaviour with this code:
#include <sys/io.h>
int main()
{
char data[]="Hello There How are you?";
/* ioperm(0x80, 1, 1); */
outsb (0x80, data, sizeof(data));
insb (0x80, data, sizeof(data));
return data[0];
}
One would expect that the code generated would place a copy of the string on
the stack call outsb to send it out port 0x80, fill that same array with bytes
read from port 0x80 and then return the first byte of data returns by insb.
That's not what happens with optimizations on. GCC Code generated with a 32-bit
target (same thing applies to 64-bit) will look something like:
main:
push edi
push esi
mov eax, 25
mov edx, 128
mov ecx, eax
sub esp, 32
lea esi, [esp+7]
cld
rep outsb
lea edi, [esp+7]
mov ecx, eax
cld
rep insb
add esp, 32
mov eax, 72
pop esi
pop edi
ret
It should be observed that in this code GCC never emitted the actual string
into the buffer but it did allocate space for it. After reading in bytes from
port 0x80 is moved the value 72 (ASCII 'H') into EAX as a return value. The
compiler assumed the input buffer `data` wasn't modified so assumed that 'H'
was still the first item in the character array.
The GCC documentation suggests a couple of ways around this. On all of the
functions with an __addr parameter that is being passed into inline assembly
use "memory" in the clobber to ensure data is written to memory before the
inline assembly is emitted and read it back out of memory if need be.
See the attached io.h for a version with the memory clobbers. The generated
code would look something like this with a correct io.h:
main:
push edi
push esi
mov eax, 25
mov edx, 128
mov ecx, eax
sub esp, 32
mov DWORD PTR [esp+7], 1819043144
mov DWORD PTR [esp+11], 1750343791
lea esi, [esp+7]
mov DWORD PTR [esp+15], 543519333
mov DWORD PTR [esp+19], 544698184
mov DWORD PTR [esp+23], 543519329
mov DWORD PTR [esp+27], 1064660857
mov BYTE PTR [esp+31], 0
cld
rep outsb
lea edi, [esp+7]
mov ecx, eax
cld
rep insb
movsx eax, BYTE PTR [esp+7]
add esp, 32
pop esi
pop edi
ret
--
You are receiving this mail because:
You are on the CC list for the bug.