Disable TLS 1.3 for ocserv's segfault workaround

ocserv is an open-source VPN software compatible to many proprietary solutions including Cisco AnyConnect, so I use it for my iOS devices.

Recently I noticed that my ocserv service was not working after upgrading to Ubuntu 22.04, and got this message:

[Tue Sep 26 17:35:27 2023] traps: ocserv-worker[6826] general protection fault ip:7f09bab28898 sp:7ffd36c9add0 error:0 in libc.so.6[7f09bab28000+195000]

It looked not a good sign for a security software.

After some trials, I found it's easy to reproduce the message via openssl s_client -connect vpn.example.com:1234 from another Ubuntu server.

So next was trying to catch its stack with debug information before segfault. I set up Debug Symbol Packages and then installed all related dbg packages, then run gdb with set follow-fork-mode child to catch issues including the ones in child processes.

Just few seconds, I got one:

(gdb) bt
#0  __GI_abort () at ./stdlib/abort.c:107
#1  0x00007fe81996545c in __libc_message (action=do_abort, fmt=0x7fe819ab77b1 "%s", 
    fmt=0x7fe819ab77b1 "%s", action=do_abort) at ../sysdeps/posix/libc_fatal.c:155
#2  0x00007fe819965770 in __GI___libc_fatal (
    message=message@entry=0x7fe819ab9d28 "The futex facility returned an unexpected error code.\n")
    at ../sysdeps/posix/libc_fatal.c:164
#3  0x00007fe819975f1a in futex_fatal_error () at ../sysdeps/nptl/futex-internal.h:87
#4  futex_wait (private=<optimized out>, expected=<optimized out>, futex_word=<optimized out>)
    at ../sysdeps/nptl/futex-internal.h:162
#5  futex_wait_simple (private=<optimized out>, expected=<optimized out>, futex_word=<optimized out>)
    at ../sysdeps/nptl/futex-internal.h:177
#6  __pthread_once_slow (once_control=0x7fe819eb5d88 <keylog_once>, 
    init_routine=0x7fe819d17020 <keylog_once_init>) at ./nptl/pthread_once.c:105
#7  0x00007fe819d1ea3d in gnutls_once (once=0x7fe819eb5d88 <keylog_once>, 
    init_func=0x7fe819d17020 <keylog_once_init>) at ../../lib/locks.c:115
#8  _gnutls_nss_keylog_write (secret_size=48, 
    secret=0x55de435c717c "x", label=0x7fe819e36af8 "CLIENT_HANDSHAKE_TRAFFIC_SECRET", 
    session=0x55de435c5970) at ../../lib/kx.c:158
#9  _gnutls_nss_keylog_func (secret=<optimized out>, secret=<optimized out>, 
    label=0x7fe819e36af8 "CLIENT_HANDSHAKE_TRAFFIC_SECRET", session=0x55de435c5970) at ../../lib/kx.c:131
#10 _gnutls_nss_keylog_func (session=0x55de435c5970, 
    label=0x7fe819e36af8 "CLIENT_HANDSHAKE_TRAFFIC_SECRET", secret=<optimized out>) at ../../lib/kx.c:121
#11 0x00007fe819d3c824 in _gnutls_call_keylog_func (size=<optimized out>, 
    data=0x55de435c717c "x", label=0x7fe819e36af8 "CLIENT_HANDSHAKE_TRAFFIC_SECRET", 
    session=0x55de435c5970) at ../../lib/kx.c:115
#12 _tls13_set_keys (key_size=32, iv_size=12, params=0x55de435c0e70, stage=STAGE_HS, 
    session=0x55de435c5970) at ../../lib/constate.c:438
#13 _gnutls_epoch_set_keys (session=session@entry=0x55de435c5970, epoch=epoch@entry=1, 
    stage=stage@entry=STAGE_HS) at ../../lib/constate.c:714
#14 0x00007fe819d3dcc0 in _tls13_connection_state_init (session=0x55de435c5970, stage=STAGE_HS)
    at ../../lib/constate.c:1208
#15 0x00007fe819d070e5 in _gnutls13_handshake_server (session=0x55de435c5970)
    at ../../lib/handshake-tls13.c:423
#16 0x00007fe819d1bda0 in gnutls_handshake (session=0x55de435c5970) at ../../lib/handshake.c:2874
#17 0x000055de422ea402 in vpn_server (ws=0x55de435aec20) at ./src/worker-vpn.c:859
#18 main (argc=<optimized out>, argv=<optimized out>) at ./src/worker.c:189

There was a _tls13_set_keys() called so I immediately gave it a try to see whether TLS 1.2 was working:

openssl s_client -tls1_2 -connect vpn.example.com:1234

And yes, it's working now.

So back to trace the bug and I saw gnutls_once() was called in ../../lib/locks.c:115, which you can see in locks.c's L115. But it's actaully completely rewritten in the next version 3.7.4.

Anyway, I needed a workaround allowing clients able to connect to my VPN server. The workaround I choose is to disable TLS 1.3, so it will not touch the problematic code path. Added -VERS-TLS1.3 to tls-priorities and everything goes back to normal:

tls-priorities = "NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128:-VERS-TLS1.3"

It's not optimal, but okay for now.