Summary: | net-vpn/ocserv-1.0.1: test failures on arm64 due to stack smashing detection with LD_PRELOAD=libsocket_wrapper.so | ||
---|---|---|---|
Product: | Gentoo Linux | Reporter: | Sam James <sam> |
Component: | Current packages | Assignee: | Mike Gilbert <floppym> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | samba, toolchain, williamh |
Priority: | Normal | Keywords: | TESTFAILURE |
Version: | unspecified | ||
Hardware: | ARM64 | ||
OS: | Linux | ||
See Also: | https://bugs.gentoo.org/show_bug.cgi?id=722740 | ||
Whiteboard: | |||
Package list: | Runtime testing required: | --- | |
Bug Depends on: | |||
Bug Blocks: | 915000, 719108 | ||
Attachments: |
test-suite.log
build.log openconnect-8.06-get_cert_name-overflow.patch |
Description
Sam James
2020-05-08 00:51:42 UTC
Created attachment 636782 [details]
build.log
I cannot reproduce this. Please edit tests/test-pass-group-cert, and remove the redirection(s) to /dev/null. Then run the test script manually and post the output. (In reply to Mike Gilbert from comment #2) > I cannot reproduce this. > > Please edit tests/test-pass-group-cert, and remove the redirection(s) to > /dev/null. Then run the test script manually and post the output. # ./test-pass-group-cert Testing local backend with username-password and certificate... Connecting to obtain cookie (without certificate)... Server '127.0.0.2' requested Basic authentication which is disabled by default Failed to obtain WebVPN cookie ok Connecting to obtain cookie - group1 (with certificate)... *** stack smashing detected ***: <unknown> terminated ./test-pass-group-cert: line 40: 70583 Aborted LD_PRELOAD=libsocket_wrapper.so /usr/sbin/openconnect --authgroup group1 -q 127.0.0.2:6551 --sslkey ./certs/user-group-key.pem -c ./certs/user-group-cert.pem -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly Failure: Could not connect with certificate! # ./test-pass-group-cert-no-pass Testing local backend with username-password and certificate... Connecting to obtain cookie (without certificate)... Server '127.0.0.2' requested Basic authentication which is disabled by default Failed to obtain WebVPN cookie ok Connecting to obtain cookie - group1 (with certificate)... *** stack smashing detected ***: <unknown> terminated ./test-pass-group-cert-no-pass: line 41: 70603 Aborted LD_PRELOAD=libsocket_wrapper.so /usr/sbin/openconnect --authgroup group1 -q 127.0.0.2:6555 --sslkey ./certs/user-group-key.pem -c ./certs/user-group-cert.pem -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly Failure: Could not connect with certificate! ---- Note that running w/o LD_PRELOAD runs without crashing # /usr/sbin/openconnect --authgroup group1 -q 127.0.0.2:6555 --sslkey ./certs/user-group-key.pem -c ./certs/user-group-cert.pem -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly Failed to connect to host 127.0.0.2 Failed to open HTTPS connection to 127.0.0.2 Failed to obtain WebVPN cookie This is probably not a bug in openconnect or ocserv, so I am unblocking the stable request. Copying samba for net-libs/socket_wrapper, and toolchain for the stack smashing error. Can you provide any insight? (In reply to Sam James (sec padawan) from comment #3) > Connecting to obtain cookie - group1 (with certificate)... *** stack > smashing detected ***: <unknown> terminated Do you have a backtrace for that crash? (In reply to Sergei Trofimovich from comment #5) > (In reply to Sam James (sec padawan) from comment #3) > > Connecting to obtain cookie - group1 (with certificate)... *** stack > > smashing detected ***: <unknown> terminated > > Do you have a backtrace for that crash? Got it on arm64-build.arm.dev.gentoo.org: # ulimit -c unlimited # ./test-pass-group-cert-no-pass Testing local backend with username-password and certificate... Connecting to obtain cookie (without certificate)... Server '127.0.0.2' requested Basic authentication which is disabled by default Failed to obtain WebVPN cookie ok Connecting to obtain cookie - group1 (with certificate)... *** stack smashing detected ***: <unknown> terminated ./test-pass-group-cert-no-pass: line 41: 13204 Aborted (core dumped) LD_PRELOAD=libsocket_wrapper.so /usr/sbin/openconnect --authgroup group1 -q 127.0.0.2:6555 --sslkey ./certs/user-group-key.pem -c ./certs/user-group-cert.pem -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly Failure: Could not connect with certificate! # file core core: ELF 64-bit LSB core file, ARM aarch64, version 1 (SYSV), SVR4-style, from '/usr/sbin/openconnect --authgroup group1 -q 127.0.0.2:6555 --sslkey ./certs/use', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: '/usr/sbin/openconnect', platform: 'aarch64' # qfile /usr/sbin/openconnect net-vpn/openconnect: /usr/sbin/openconnect # gdb --quiet /usr/sbin/openconnect core Reading symbols from /usr/sbin/openconnect... Reading symbols from /usr/lib/debug//usr/sbin/openconnect.debug... [New LWP 13204] [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib64/libthread_db.so.1". Core was generated by `/usr/sbin/openconnect --authgroup group1 -q 127.0.0.2:6555 --sslkey ./certs/use'. Program terminated with signal SIGABRT, Aborted. #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. (gdb) bt #0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 #1 0x0000ffff95a19728 in __GI_abort () at abort.c:79 #2 0x0000ffff95a65b6c in __libc_message (action=<optimized out>, fmt=fmt@entry=0xffff95b1bce8 "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:181 #3 0x0000ffff95ad526c in __GI___fortify_fail_abort (need_backtrace=need_backtrace@entry=false, msg=msg@entry=0xffff95b1bcc0 "stack smashing detected") at fortify_fail.c:33 #4 0x0000ffff95ad5220 in __stack_chk_fail () at stack_chk_fail.c:29 #5 0x0000ffff95ed7a40 in load_certificate (vpninfo=vpninfo@entry=0xaaaaffb09140) at gnutls.c:1356 #6 0x0000ffff95ed92e0 in openconnect_open_https (vpninfo=vpninfo@entry=0xaaaaffb09140) at gnutls.c:2158 #7 0x0000ffff95eb2258 in do_https_request (vpninfo=vpninfo@entry=0xaaaaffb09140, method=method@entry=0xffff95ede8a8 "POST", request_body_type=request_body_type@entry=0xffff95edfeb8 "application/xml; charset=utf-8", request_body=request_body@entry=0xaaaaffb02eb0, form_buf=form_buf@entry=0xffffe36cbf58, fetch_redirect=fetch_redirect@entry=0) at http.c:1056 #8 0x0000ffff95ec3734 in cstp_obtain_cookie (vpninfo=0xaaaaffb09140) at auth.c:1312 #9 0x0000aaaadc89eda4 in main (argc=13, argv=0xffffe36cc408) at main.c:1599 valgrind did not find any problems. asan refused to work with LD_PRELOADED libraries that manually load libc.so.6. Resorting to tracking who stack canary on stack. Before looking at the specifics here is how stack canary usually looks like on arm64: // cat a.c void g(const char *); void f(void) { char b[128]; g(b); } $ aarch64-unknown-linux-gnu-gcc -O2 -c -S a.c; cat a.s ... f: stp x29, x30, [sp, -176]! mov x29, sp str x19, [sp, 16] adrp x19, :got:__stack_chk_guard add x0, sp, 40 ldr x19, [x19, #:got_lo12:__stack_chk_guard] ldr x1, [x19] str x1, [sp, 168] mov x1,0 bl g ldr x1, [sp, 168] ldr x0, [x19] eor x0, x1, x0 cbnz x0, .L5 ldr x19, [sp, 16] ldp x29, x30, [sp], 176 ret .L5: bl __stack_chk_fail It's a very verbose way to: - load value by '__stack_chk_guard' absolute address into 'x19' register - store canary copy on stack at '[sp +168]' address - restore canary from stack and from address at 'x19' and compare it back. A good hint here is that right after the store 'x1' value is zeroed out with 'mov x1,0'. Let's track life of a canary in 'load_certificate' and see where it gets corrupted: I added 'gdb --args' to openconnect call in test-pass-group-cert-no-pass and removed a few unused evals. LD_PRELOAD="libsocket_wrapper.so" gdb --args $OPENCONNECT --authgroup group1 ... # bash -x ./test-pass-group-cert-no-pass ... Connecting to obtain cookie - group1 (with certificate)... + LD_PRELOAD=libsocket_wrapper.so + gdb --args /usr/sbin/openconnect --authgroup group1 -q 127.0.0.2:6555 --sslkey ./certs/user-group-key.pem -c ./certs/user-group-cert.pem -u test --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3 --cookieonly (gdb) start (gdb) break load_certificate (gdb) continue Breakpoint 2, load_certificate (vpninfo=vpninfo@entry=0xaaaaaaae5140) at gnutls.c:916 Dump of assembler code for function load_certificate: => 0x0000ffffb7f88d08 <+0>: sub sp, sp, #0x200 0x0000ffffb7f88d0c <+4>: mov x3, #0x14 // #20 0x0000ffffb7f88d10 <+8>: mov x2, #0x7 // #7 0x0000ffffb7f88d14 <+12>: stp x29, x30, [sp, #16] 0x0000ffffb7f88d18 <+16>: add x29, sp, #0x10 0x0000ffffb7f88d1c <+20>: stp x21, x22, [sp, #48] 0x0000ffffb7f88d20 <+24>: adrp x21, 0xffffb7faf000 0x0000ffffb7f88d24 <+28>: stp x19, x20, [sp, #32] 0x0000ffffb7f88d28 <+32>: mov x19, x0 0x0000ffffb7f88d2c <+36>: adrp x20, 0xffffb7f97000 0x0000ffffb7f88d30 <+40>: ldr x0, [x21, #3992] 0x0000ffffb7f88d34 <+44>: stp x23, x24, [sp, #64] 0x0000ffffb7f88d38 <+48>: add x20, x20, #0x918 0x0000ffffb7f88d3c <+52>: ldr x24, [x19, #1128] 0x0000ffffb7f88d40 <+56>: ldr x1, [x0] 0x0000ffffb7f88d44 <+60>: str x1, [sp, #504] 0x0000ffffb7f88d48 <+64>: mov x1, #0x0 // #0 0x0000ffffb7f88d4c <+68>: ldr x23, [x19, #1120] 0x0000ffffb7f88d50 <+72>: mov x1, x20 0x0000ffffb7f88d54 <+76>: mov x0, x24 0x0000ffffb7f88d58 <+80>: stp x25, x26, [sp, #80] 0x0000ffffb7f88d5c <+84>: mov w26, #0x0 // #0 Here is our canary store: 0x0000ffffb7f88d40 <+56>: ldr x1, [x0] 0x0000ffffb7f88d44 <+60>: str x1, [sp, #504] 0x0000ffffb7f88d48 <+64>: mov x1, #0x0 // #0 Absolute address of canary copy on stack is '[sp, #504]'. Let's find it out and trace it's life: (gdb) break *0x0000ffffb7f88d48 Breakpoint 3 at 0xffffb7f88d48: file gnutls.c, line 916. (gdb) continue Continuing. Breakpoint 3, 0x0000ffffb7f88d48 in load_certificate (vpninfo=vpninfo@entry=0xaaaaaaae5140) at gnutls.c:916 Looks like a valid canary in register, stack and global variable: (gdb) print (void*)$x1 $3 = (void *) 0xb9b1883f29832000 (gdb) print *(void**)($sp+504) $4 = (void *) 0xb9b1883f29832000 (gdb) print *(void**)&__stack_chk_guard $6 = (void *) 0xb9b1883f2983200 Print stack address and add a watch point on it: (gdb) print (void*)($sp+504) $7 = (void *) 0xffffffffea (gdb) watch *(void**)0xffffffffeaa8 Hardware watchpoint 3: *(void**)0xffffffffeaa8 (gdb) continue Continuing. Hardware watchpoint 3: *(void**)0xffffffffeaa8 Old value = (void *) 0xffffb7f8c2b4 <openconnect_open_https+572> New value = (void *) 0xc9d1f41373228800 0x0000ffffb7f88d48 in load_certificate (vpninfo=vpninfo@entry=0xaaaaaaae5140) at gnutls.c:916 916 in gnutls.c (gdb) bt #0 0x0000ffffb7f88d48 in load_certificate (vpninfo=vpninfo@entry=0xaaaaaaae5140) at gnutls.c:916 #1 0x0000ffffb7f8c2e0 in openconnect_open_https (vpninfo=vpninfo@entry=0xaaaaaaae5140) at gnutls.c:2158 (gdb) bt #0 get_cert_name (cert=0xaaaaaaaea2f0, name=name@entry=0xffffffffea58 "", namelen=<optimized out>) at gnutls.c:563 #1 0x0000ffffb7f89408 in load_certificate (vpninfo=vpninfo@entry=0xaaaaaaae5140) at gnutls.c:1545 ... 557 static int get_cert_name(gnutls_x509_crt_t cert, char *name, size_t namelen) 558 { 559 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 560 0, 0, name, &namelen) && 561 gnutls_x509_crt_get_dn(cert, name, &namelen)) { 562 name[namelen-1] = 0; 563 snprintf(name, namelen-1, "<unknown>"); 564 return -EINVAL; 565 } 566 return 0; 567 } (gdb) disassemble 0x0000ffffb7f88ab8 <+160>: sub x1, x1, #0x1 0x0000ffffb7f88abc <+164>: strb wzr, [x20, x1] => 0x0000ffffb7f88ac0 <+168>: bl 0xffffb7f5f590 <snprintf@plt> I think it tells us that 'name[namelen-1] = 0;' corrupted the stack. Probably 'name' value: (gdb) printf "%#x\n", (void*)$x20 0xffffea58 Probably 'namelen-1' value: (gdb) printf "%#x\n", (void*)$x1 0x54 # 84 But get_cert_name is ever called against 'name' with namelen=80. Let's see if I can find if 'namelen' is inflated by 'gnutls_x509_crt_get_dn' when it fails or somewhere else. Created attachment 636836 [details, diff]
openconnect-8.06-get_cert_name-overflow.patch
openconnect-8.06-get_cert_name-overflow.patch shoud fix the overflow in net-vpn/openconnect
From http://man7.org/linux/man-pages/man3/gnutls_x509_crt_get_dn_by_oid.3.html : """ RETURNS GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not long enough, and in that case the buf_size will be updated with the required size. GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE if there are no data in the current index. On success 0 is returned. """ In our case 'namelen' is extended from 80 to 84 chars. Then corrupts one byte with 'name[namelen-1] = 0;'. 557 static int get_cert_name(gnutls_x509_crt_t cert, char *name, size_t namelen) 558 { 559 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 560 0, 0, name, &namelen) && 561 gnutls_x509_crt_get_dn(cert, name, &namelen)) { 562 name[namelen-1] = 0; 563 snprintf(name, namelen-1, "<unknown>"); 564 return -EINVAL; 565 } 566 return 0; 567 } The bug has been closed via the following commit(s): https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=27513d77015771f8604d9a21f388e9846c8c650a commit 27513d77015771f8604d9a21f388e9846c8c650a Author: Mike Gilbert <floppym@gentoo.org> AuthorDate: 2020-05-12 16:01:57 +0000 Commit: Mike Gilbert <floppym@gentoo.org> CommitDate: 2020-05-12 16:02:48 +0000 net-vpn/openconnect: fix buffer overflow in get_cert_name Closes: https://bugs.gentoo.org/721570 Signed-off-by: Mike Gilbert <floppym@gentoo.org> .../files/8.09-gnutls-buffer-overflow.patch | 62 ++++++++++++++++++++++ ...nect-8.09.ebuild => openconnect-8.09-r1.ebuild} | 3 ++ 2 files changed, 65 insertions(+) |