public inbox for glibc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libc/29863] New: Segmentation fault in memcmp-sse2.S if memory contents can concurrently change
@ 2022-12-07 10:49 nars at yottadb dot com
  2022-12-12 13:02 ` [Bug libc/29863] " nars at yottadb dot com
                   ` (23 more replies)
  0 siblings, 24 replies; 25+ messages in thread
From: nars at yottadb dot com @ 2022-12-07 10:49 UTC (permalink / raw)
  To: glibc-bugs

https://sourceware.org/bugzilla/show_bug.cgi?id=29863

            Bug ID: 29863
           Summary: Segmentation fault in memcmp-sse2.S if memory contents
                    can concurrently change
           Product: glibc
           Version: 2.36
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: libc
          Assignee: unassigned at sourceware dot org
          Reporter: nars at yottadb dot com
                CC: drepper.fsp at gmail dot com
  Target Milestone: ---

Created attachment 14486
  --> https://sourceware.org/bugzilla/attachment.cgi?id=14486&action=edit
Simple C program that demonstrates the SIG-11 in memcmp-sse2.S

Hi,

We saw a occasional test failure after upgrading to Ubuntu 22.10. And after
some investigation suspect the cause to be a GLIBC 2.36 regression.

On the system we run the test on, a call to memcmp() ended up invoking
sysdeps/x86_64/multiarch/memcmp-sse2.S in glibc. I have attached the
/proc/cpuinfo information below in case it helps determine why the sse2 version
of memcmp got invoked.

Attached is a simple C program test.c. It spawns 2 threads. Thread 1 does
memcmp() in a loop, 100,000 times. The memcmp() will return 0 most of the time
since it is coded to compare identical buffers. Thread 2 changes just 1 byte in
one of the buffers. It changes this byte to a different value and back again to
the original value. Keeps doing this repeatedly. This causes the memcmp() in
Thread 1 to alternately return 0 or 1 which is fine. But eventually, Thread 1
crashes with a Segmentation fault.

Below is an example output. In this example, Thread 1 crashed in the 58,234th
iteration.

$ gcc test.c
$ ./a.out
.
.
i = 58232 : result = 1
i = 58233 : result = 1
i = 58234 : result = 1
Segmentation fault (core dumped)

Below is the C stack and relevant register output from the crash.

(gdb) where
#0  __memcmp_sse2 () at ../sysdeps/x86_64/multiarch/memcmp-sse2.S:312
#1  0x000055efe46032d3 in childThread ()
#2  0x00007f6f45e90402 in start_thread (arg=<optimized out>) at
./nptl/pthread_create.c:442
#3  0x00007f6f45f1f590 in clone3 () at
../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

(gdb) info registers
rax            0xfffffff1          4294967281
rdx            0xfffffffffffffff1  -15
rsi            0x55efe4606040      94488817066048
rcx            0xffff              65535

I have pasted the memcmp-sse2.S source code with line numbers below
corresponding to the flow of the assembly instructions around the time of the
crash. That is, the memcmp() function call enters at line 59, executes line 71,
72 and then jumps to line 249 etc. The crash occurs in line 312 below.

sysdeps/x86_64/multiarch/memcmp-sse2.S
--------------------------------------
     59 ENTRY(MEMCMP)
     71         cmpq    $CHAR_PER_VEC, %rdx
     72         ja      L(more_1x_vec)
    249 L(more_1x_vec):
    255         movl    $0xffff, %ecx
    257         movups  (%rsi), %xmm0
    258         movups  (%rdi), %xmm1
    259         PCMPEQ  %xmm0, %xmm1
    260         pmovmskb %xmm1, %eax
    261         subl    %ecx, %eax
    262         jnz     L(ret_nonzero_vec_start_0)
    269         subq    $(CHAR_PER_VEC * 2), %rdx
    271         ja      L(more_2x_vec)
    273         movups  (VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rdx, CHAR_SIZE),
%xmm0
    274         movups  (VEC_SIZE * -1 + SIZE_OFFSET)(%rdi, %rdx, CHAR_SIZE),
%xmm1
    275         PCMPEQ  %xmm0, %xmm1
    276         pmovmskb %xmm1, %eax
    277         subl    %ecx, %eax
    281         jnz     L(ret_nonzero_vec_end_0)
    299 L(ret_nonzero_vec_end_0):
    300         bsfl    %eax, %eax
    311         addl    %edx, %eax
    312         movzbl  (VEC_SIZE * -1 + SIZE_OFFSET)(%rsi, %rax), %ecx

For the above failure to happen, the length of the memcmp() needs to be between
16 and 32.

If the contents of the buffer did not change between lines 59 to 312 above,
then we are guaranteed %rax holds a positive value at line 312.

But if the contents can change concurrently (as is the case in the test
program), we could end up with a negative value of %rax. And that causes the
pointer arithmetic in line 312 to result in a stray pointer instead of one
within the memcmp() buffer bounds.

In case it helps, below is the commit that made the above changes.

$ git log --graph --oneline --pretty=format:'%h%d; %ci; %cn; %s'
sysdeps/x86_64/multiarch/memcmp-sse2.S | head -1 
* ae308947ff; 2022-07-05 16:42:42 -0700; Noah Goldstein; x86: Add support for
building {w}memcmp{eq} with explicit ISA level

I have also added some more information below in case it helps.

$ grep PRETTY_NAME /etc/os-release
PRETTY_NAME="Ubuntu 22.10"

$ uname -a
Linux spencer 5.19.0-26-generic #27-Ubuntu SMP PREEMPT_DYNAMIC Wed Nov 23
20:44:15 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

$ ldd --version | head -1
ldd (Ubuntu GLIBC 2.36-0ubuntu4) 2.36

$ grep -E "model name|flags" /proc/cpuinfo | sort -u
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb
rdtscp lm constant_tsc rep_good acc_power nopl nonstop_tsc cpuid extd_apicid
aperfmperf pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes
xsave avx f16c lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse
3dnowprefetch osvw ibs xop skinit wdt lwp fma4 tce nodeid_msr tbm topoext
perfctr_core perfctr_nb bpext ptsc mwaitx cpb hw_pstate ssbd vmmcall fsgsbase
bmi1 avx2 smep bmi2 xsaveopt arat npt lbrv svm_lock nrip_save tsc_scale
vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic
v_vmsave_vmload vgif overflow_recov
model name      : AMD A12-9800E RADEON R7, 12 COMPUTE CORES 4C+8G

Let me know if you need any more information.

Thanks,
Narayanan.

-- 
You are receiving this mail because:
You are on the CC list for the bug.

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2023-05-14 21:49 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-07 10:49 [Bug libc/29863] New: Segmentation fault in memcmp-sse2.S if memory contents can concurrently change nars at yottadb dot com
2022-12-12 13:02 ` [Bug libc/29863] " nars at yottadb dot com
2022-12-13 18:26 ` pinskia at gcc dot gnu.org
2022-12-13 18:28 ` pinskia at gcc dot gnu.org
2022-12-13 18:33 ` nars at yottadb dot com
2022-12-13 18:39 ` pinskia at gcc dot gnu.org
2022-12-13 18:45 ` nars at yottadb dot com
2022-12-13 18:52 ` pinskia at gcc dot gnu.org
2022-12-13 19:13 ` goldstein.w.n at gmail dot com
2022-12-13 19:36 ` bhaskar at yottadb dot com
2022-12-13 20:09 ` goldstein.w.n at gmail dot com
2022-12-13 20:18 ` goldstein.w.n at gmail dot com
2022-12-13 20:46 ` nars at yottadb dot com
2022-12-13 21:09 ` hjl.tools at gmail dot com
2022-12-13 21:53 ` bhaskar at yottadb dot com
2022-12-13 23:01 ` goldstein.w.n at gmail dot com
2022-12-13 23:16 ` nars at yottadb dot com
2022-12-13 23:39 ` goldstein.w.n at gmail dot com
2022-12-14  0:14 ` goldstein.w.n at gmail dot com
2022-12-14  7:45 ` sam at gentoo dot org
2022-12-14 15:40 ` nars at yottadb dot com
2022-12-14 18:17 ` nars at yottadb dot com
2023-05-14 21:46 ` ppluzhnikov at google dot com
2023-05-14 21:48 ` ppluzhnikov at google dot com
2023-05-14 21:49 ` ppluzhnikov at google dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).