Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault when closing clients by random order @1.7.1 and main #994

Closed
jzw-weride opened this issue Sep 29, 2022 · 3 comments
Closed
Labels

Comments

@jzw-weride
Copy link
Contributor

Describe the bug
ttyd exits with segmentation fault when closing clients by random order

To Reproduce
Steps to reproduce the behavior:

  1. Start ttyd bash
  2. Open 3 clients
  3. Close the clients directly (by hitting the X button on the browser tab) by the order of [client 2, client 1, client 3]
  4. See error, it seems lws uses a pointer after free

Logs

[2022/09/29 14:54:05:6764] N: ttyd 1.7.1-942bdab (libwebsockets 4.3.2-gibraltar_master_archive_220519-11022-ga20c0eff086)
[2022/09/29 14:54:05:6765] N: tty configuration:
[2022/09/29 14:54:05:6765] N:   start command: bash
[2022/09/29 14:54:05:6765] N:   close signal: SIGHUP (1)
[2022/09/29 14:54:05:6765] N:   terminal type: xterm-256color
[2022/09/29 14:54:05:6765] N:   max clients: 32
[2022/09/29 14:54:05:6766] N: lws_create_context: LWS: 4.3.2-gibraltar_master_archive_220519-11022-ga20c0eff086, NET SRV H1 WS MbedTLS ConMon IPV6-off
[2022/09/29 14:54:05:6768] N: elops_init_pt_uv:  Using foreign event loop...
[2022/09/29 14:54:05:6768] N: __lws_lc_tag:  ++ [wsi|0|pipe] (1)
[2022/09/29 14:54:05:6769] N: __lws_lc_tag:  ++ [vh|0|netlink] (1)
[2022/09/29 14:54:05:6770] N: __lws_lc_tag:  ++ [vh|1|default||7681] (2)
[2022/09/29 14:54:05:6771] N: [vh|1|default||7681]: lws_socket_bind: source ads 0.0.0.0
[2022/09/29 14:54:05:6771] N: __lws_lc_tag:  ++ [wsi|1|listen|default||7681] (2)
[2022/09/29 14:54:05:6771] N:  Listening on port: 7681
[2022/09/29 14:54:17:0118] N: __lws_lc_tag:  ++ [wsisrv|0|adopted] (1)
[2022/09/29 14:54:17:0119] N: HTTP / - 127.0.0.1
[2022/09/29 14:54:18:3312] N: HTTP / - 127.0.0.1
[2022/09/29 14:54:18:6912] N: __lws_lc_tag:  ++ [wsisrv|1|adopted] (2)
[2022/09/29 14:54:18:6916] N: WS   /ws - 127.0.0.1, clients: 1
[2022/09/29 14:54:18:7002] N: WS closed from 127.0.0.1, clients: 0
[2022/09/29 14:54:18:7003] N: __lws_lc_untag:  -- [wsisrv|1|adopted] (1) 9.055ms
[2022/09/29 14:54:19:4913] N: HTTP / - 127.0.0.1
[2022/09/29 14:54:19:7999] N: __lws_lc_tag:  ++ [wsisrv|2|adopted] (2)
[2022/09/29 14:54:19:8005] N: HTTP /token - 127.0.0.1
[2022/09/29 14:54:19:8395] N: HTTP /token - 127.0.0.1
[2022/09/29 14:54:19:8667] N: HTTP /token - 127.0.0.1
[2022/09/29 14:54:19:9861] N: __lws_lc_tag:  ++ [wsisrv|3|adopted] (3)
[2022/09/29 14:54:19:9866] N: WS   /ws - 127.0.0.1, clients: 1
[2022/09/29 14:54:20:0088] N: WS closed from 127.0.0.1, clients: 0
[2022/09/29 14:54:20:0088] N: __lws_lc_untag:  -- [wsisrv|3|adopted] (2) 22.733ms
[2022/09/29 14:54:20:2043] N: __lws_lc_tag:  ++ [wsisrv|4|adopted] (3)
[2022/09/29 14:54:20:2046] N: WS   /ws - 127.0.0.1, clients: 1
[2022/09/29 14:54:20:2215] N: started process, pid: 961280
[2022/09/29 14:54:20:5919] N: __lws_lc_tag:  ++ [wsisrv|5|adopted] (4)
[2022/09/29 14:54:20:5922] N: WS   /ws - 127.0.0.1, clients: 2
[2022/09/29 14:54:20:6039] N: started process, pid: 961335
[2022/09/29 14:54:20:8427] N: __lws_lc_tag:  ++ [wsisrv|6|adopted] (5)
[2022/09/29 14:54:20:8431] N: WS   /ws - 127.0.0.1, clients: 3
[2022/09/29 14:54:20:8718] N: started process, pid: 961390
[2022/09/29 14:54:24:8422] N: __lws_lc_untag:  -- [wsisrv|2|adopted] (4) 5.042s
[2022/09/29 14:54:24:8675] N: __lws_lc_untag:  -- [wsisrv|0|adopted] (3) 7.855s
[2022/09/29 14:54:37:6894] N: WS closed from 127.0.0.1, clients: 2
[2022/09/29 14:54:37:6894] N: killing process, pid: 961335
[2022/09/29 14:54:37:6895] N: __lws_lc_untag:  -- [wsisrv|5|adopted] (2) 17.097s
== uv_read failed with error -5: i/o error
[2022/09/29 14:54:37:6910] N: process killed with signal 1, pid: 961335
[2022/09/29 14:54:39:6832] N: __lws_lc_tag:  ++ [wsisrv|7|adopted] (3)
[2022/09/29 14:54:39:7966] N: __lws_lc_tag:  ++ [wsisrv|8|adopted] (4)
[2022/09/29 14:54:39:8422] N: HTTP / - 127.0.0.1
[2022/09/29 14:54:40:2021] N: HTTP /token - 127.0.0.1
[2022/09/29 14:54:40:6124] N: __lws_lc_tag:  ++ [wsisrv|9|adopted] (5)
[2022/09/29 14:54:40:6127] N: WS   /ws - 127.0.0.1, clients: 3
[2022/09/29 14:54:40:6347] N: started process, pid: 962171
[2022/09/29 14:54:41:8151] N: HTTP / - 127.0.0.1
[2022/09/29 14:54:41:8805] N: HTTP /token - 127.0.0.1
[2022/09/29 14:54:42:3749] N: __lws_lc_tag:  ++ [wsisrv|a|adopted] (6)
[2022/09/29 14:54:42:3753] N: WS   /ws - 127.0.0.1, clients: 4
[2022/09/29 14:54:42:4394] N: started process, pid: 962272
[2022/09/29 14:54:46:8051] N: WS closed from 127.0.0.1, clients: 3
[2022/09/29 14:54:46:8051] N: killing process, pid: 962171
[2022/09/29 14:54:46:8052] N: __lws_lc_untag:  -- [wsisrv|9|adopted] (5) 6.192s
== uv_read failed with error -5: i/o error
[2022/09/29 14:54:46:8064] N: process killed with signal 1, pid: 962171
[2022/09/29 14:54:46:8809] N: __lws_lc_untag:  -- [wsisrv|7|adopted] (4) 7.197s
[2022/09/29 14:54:49:2305] N: WS closed from 127.0.0.1, clients: 2
[2022/09/29 14:54:49:2306] N: killing process, pid: 961390
[2022/09/29 14:54:49:2306] N: __lws_lc_untag:  -- [wsisrv|6|adopted] (3) 28.387s
== uv_read failed with error -5: i/o error
[2022/09/29 14:54:49:2328] N: process killed with signal 1, pid: 961390
[2022/09/29 14:54:49:7979] N: __lws_lc_untag:  -- [wsisrv|8|adopted] (2) 10.001s
[2022/09/29 14:54:51:6486] N: WS closed from 127.0.0.1, clients: 1
[2022/09/29 14:54:51:6487] N: killing process, pid: 961280
[2022/09/29 14:54:51:6487] N: __lws_lc_untag:  -- [wsisrv|4|adopted] (1) 31.444s
== uv_read failed with error -5: i/o error
[2022/09/29 14:54:51:6538] N: process killed with signal 1, pid: 961280
[1]    960595 segmentation fault (core dumped)  ./ttyd.x86_64 -d 31 -m 32 bash

Backtrace

== uv_read failed with error -5: i/o error
[2022/09/29 15:05:02:0198] N: process killed with signal 1, pid: 981454
[LWP 981455 exited]
[2022/09/29 15:05:03:2838] N: WS closed from 127.0.0.1, clients: 1
[2022/09/29 15:05:03:2838] N: killing process, pid: 981297
[2022/09/29 15:05:03:2839] N: __lws_lc_untag:  -- [wsisrv|1|adopted] (3) 10.278s
== uv_read failed with error -5: i/o error
[LWP 981298 exited]
[2022/09/29 15:05:03:2852] N: process killed with signal 1, pid: 981297
[2022/09/29 15:05:03:6474] N: __lws_lc_untag:  -- [wsisrv|2|adopted] (2) 10.000s
[2022/09/29 15:05:05:1401] N: __lws_lc_untag:  -- [wsisrv|0|adopted] (1) 12.914s
[2022/09/29 15:05:05:7534] N: WS closed from 127.0.0.1, clients: 0
[2022/09/29 15:05:05:7534] N: killing process, pid: 981701
[2022/09/29 15:05:05:7534] N: __lws_lc_untag:  -- [wsisrv|4|adopted] (0) 4.548s
== uv_read failed with error -5: i/o error
[LWP 981702 exited]
[2022/09/29 15:05:05:7546] N: process killed with signal 1, pid: 981701

Thread 1 "ttyd.x86_64" received signal SIGSEGV, Segmentation fault.
0x000000000043be98 in uv__run_closing_handles (loop=0x7ffff7ff8830) at src/unix/core.c:316
316         q = p->next_closing;
(gdb) bt
#0  0x000000000043be98 in uv__run_closing_handles (loop=0x7ffff7ff8830) at src/unix/core.c:316
#1  0x000000000043c0bd in uv_run (loop=0x7ffff7ff8830, mode=UV_RUN_DEFAULT) at src/unix/core.c:395
#2  0x0000000000417c34 in lws_service ()
#3  0x000000000040142e in main ()

Environment:

  • OS: ttyd running on Ubuntu 20.04
  • Browser: Chrome 105, Safari from MacOS 12.6
@jzw-weride jzw-weride added the bug label Sep 29, 2022
@jzw-weride jzw-weride changed the title Segmentation fault when closing clients by random order Segmentation fault when closing clients by random order @1.7.1 and main Sep 29, 2022
@jzw-weride
Copy link
Contributor Author

It looks like async_cb @ pty.c is called by uv_run from src/unix/core.c by uv__io_poll .

In async_cb, we do:

...
  uv_close((uv_handle_t *) async, NULL);
  process_free(process);
...

Since async is a member of process, and we free process at process_free. As the result, async is no longer valid.

But uv_close requires:

This MUST be called on each handle before memory is released. Moreover, the memory can only be released in close_cb or after it has returned.

A potential fix is:

static void async_free_cb(uv_handle_t *handle) {
  free((uv_async_t *) handle -> data);
}

static void async_cb(uv_async_t *async) {
  pty_process *process = (pty_process *) async->data;
  process->exit_cb(process);

  uv_close((uv_handle_t *) async, async_free_cb);
  process_free(process);
}

@jzw-weride
Copy link
Contributor Author

Fix is here: #997

@jzw-weride
Copy link
Contributor Author

Fix is merged into main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant