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

Segfault on Lwt_unix.tcsetattr with bad parameters #798

Closed
GreenArchon opened this issue Aug 25, 2020 · 2 comments
Closed

Segfault on Lwt_unix.tcsetattr with bad parameters #798

GreenArchon opened this issue Aug 25, 2020 · 2 comments

Comments

@GreenArchon
Copy link
Contributor

GreenArchon commented Aug 25, 2020

Hello,

The following code

let run_lwt () =
  let%lwt fd = Lwt_unix.openfile "test1" [O_RDWR;O_NONBLOCK] 0o644 in
  let%lwt ta = Lwt_unix.tcgetattr fd in
  let ta' = { ta with c_obaud = 115201; c_ibaud = 115201 } in
  let%lwt () =
    Lwt.try_bind
      (fun () -> Lwt_unix.tcsetattr fd TCSANOW ta')
      Lwt.return
      (fun exn -> Lwt_io.printf "LWT Got %s\n%!" (Printexc.to_string exn))
  in
  Lwt_io.printf "Done LWT\n%!"

, accompanied by the prior creation of a pseudo terminal in the background in the same directory, eg. with

socat -d -d pty,raw,echo=0,link=test1 pty,raw,echo=0,link=test2

segfaults, with the following output:

Fatal error: exception Unix.Unix_error(Unix.EINVAL, "tcsetattr", "")
Raised by primitive operation at file "src/unix/lwt_engine.ml", line 403, characters 26-60
Called from file "src/unix/lwt_engine.ml", line 344, characters 8-19
Called from file "src/unix/lwt_main.ml", line 37, characters 6-49
Called from file "src/unix/lwt_main.ml", line 114, characters 8-13
Re-raised at file "src/unix/lwt_main.ml", line 120, characters 4-13
Called from file "test_crash.ml", line 25, characters 2-28
[1]    13202 segmentation fault (core dumped)  OCAMLRUNPARAM=b _build/install/default/bin/test_crash

Note the 115201 baudrate is not a standard baudrate (115200 is, and setting it does not crash), so there's a reason for the failure - but I would expect it to call the exception handler and continue its merry way, not a hard crash.

The equivalent standard OCaml code:

let run_normal () =
  let fd = Unix.openfile "test1" [O_RDWR;O_NONBLOCK] 0o644 in
  let ta = Unix.tcgetattr fd in
  let ta' = { ta with c_obaud = 115201; c_ibaud = 115201 } in
  (try
    Unix.tcsetattr fd TCSANOW ta'
  with exn -> Printf.printf "UNIX: Got %s\n%!" (Printexc.to_string exn));
  Printf.printf "Done Unix\n%!"

does not crash (but an exception is raised and handled by the print statement).

Am I missing something in the above code or is there a bug in the error handling of the underlying C stubs?

This was tested and reproduced on (OCaml 4.10, LWT 5.3.0), (OCaml 4.05, LWT 5.2.0), (OCaml 4.05, LWT 5.2.0 on 32-bit ARM), (Ocaml 4.05, LWT 3.2.1).

Thank you!

@GreenArchon
Copy link
Contributor Author

Looking at the stub's code, it looks like decode_terminal_status function, called from worker_tcsetattr, throws unix_error()s on errors. I'm not familiar with LWT's internals, but this seems to clash with/bypass the job->result, job->error_code and result_tcsetattr() process.

GreenArchon added a commit to GHGSat/lwt that referenced this issue Aug 31, 2020
raphael-proust added a commit that referenced this issue Sep 1, 2020
Lwt_unix.tcsetattr: Fix segfault on bad arguments (#798)
@raphael-proust
Copy link
Collaborator

The fix has been merged into master

GreenArchon added a commit to GHGSat/lwt that referenced this issue Dec 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants