John Reiser jreiser BitWagon com
BitWagon Software LLC
November 28, 2010
revised November 30, 2010
This experimental patch implements one way for glibc to detect, diagnose, and work around the bug of specifying overlapping source and destination regions in a call to memcpy or mempcpy. If the environment variable MEMCPY_CHECK_ [note the trailing underscore] exists and is non-zero, then glibc will detect these errors. If the value is odd, then a diagnostic message is printed to stderr (file descriptor 2). The higher-order bits are a counter of the number of errors which are allowed before glibc forcibly terminates execution. If actual overlap occurs, then the patch implements the operation using memmove instead of memcpy or mempcpy. The work-around produces defined behavior which the programmer probably intended, instead of the undefined behavior that is allowed by the C language.
Environment variable |
Overlap in memcpy/mempcpy |
---|---|
Unset |
No detection |
MEMCPY_CHECK_=0 |
No detection |
MEMCPY_CHECK_=1 |
Detect; print a message on stderr; abort |
MEMCPY_CHECK_=10 |
Detect; no print; skip 5 instances before abort |
MEMCPY_CHECK_=51 |
Detect; print; abort on 26th instance |
The diagnostic message looks like:
*** memcpy overlap @0x8050267 (0x401250, 0x401253, 0x5) ***
which lists the return address and parameter values. The same text is used for mempcpy.
The patch implements this feature by extending the internal function __init_cpu_features to take a parameter getenv. This requires passing getenv as the first parameter to each STT_GNU_IFUNC indirect function. Thus some of the “CPU” features may be controlled by the software environment as well as by the hardware. When the implementation is selected for memcpy, then a non-zero MEMCPY_CHECK_ chooses the code which checks for overlap.
Detecting no overlap costs about 4 or 5 CPU cycles per call to memcpy or mempcpy. If overlap exists, then overhead and redirecting execution to memmove costs on the order of 100 cycles. The diagnostic message costs a couple hundred cycles plus the write() system call.
The present implementation supports x86_64 and i686 only. Other architectures are possible but not implemented due to not enough programmer time and resources for testing.
The getenv that is passed to a STT_GNU_IFUNC indirect function is the runtime loader's (rtld: ld-linux) getenv. At the beginning of execution (immediately after execve) this is equivalent to libc's getenv. However, calling putenv may cause the two subroutines to diverge. Specify what you want before execve; do not rely on some initialization function setting MEMCPY_CHECK_.
Downloads (based on Fedora 15 rawhide):
File |
Length |
Md5sum |
---|---|---|
96828 |
be86b7882356b79197ff8546e4f49cd5 |
|
36483 |
a83546adc996ab2aaeb4cd2235956bdf |
|
6080555 |
2b3edb00e3a330e5312a94617d6b8ec7 |
|
5562284 |
ca8c3d5d30ead1e89c0f8e9a61156bf7 |
|
11516311 |
b3cf7048b7abc08cc586cfa4002c8505 |
|
|
|
|
27058162 |
25af93e0d72434c7ddf3718db8e200ea |
|
27087972 |
b9fb6da52a7de89b2be3c33053f2dd88 |
|
25435861 |
ef98f4d51a8cfe9f10f4b1ed26188910 |
|
24962716 |
e93abdd639762d642746f9573e28d404 |
|
1045424 |
dc1dc28473545b971eed4936b3df93b4 |
|
1044539 |
0df617d8a42aa5ef4e55e9291ba7645b |
|
662823 |
3c775922d4150951c29ccba62103122e |
|
653431 |
75de90c5515a89ac66b06d3ddad1e6c5 |
|
1416669 |
3b5e5acb39a92fd804c716fa0721017b |
|
1827595 |
76f5a7267bebac7520128b2ca663d218 |
|
166694 |
0c3d30a47956310ff40fbe7e26cf1264 |
|
165770 |
1aaeb9b4f78f509cde168a260f5be88b |
|
216204 |
e7e15d4d9dda4bf5c59edad5bfbf4473 |
|
218869 |
7fe5c28802582fbd2f1a6ec28ce042bc |