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

PtyMaster::drop should panic on EBADF #677

Merged
merged 1 commit into from
Jul 16, 2017
Merged

Conversation

asomers
Copy link
Member

@asomers asomers commented Jul 15, 2017

Fixes #659

@Susurrus
Copy link
Contributor

LGTM. This bug was never in a released version of nix, so we're fine with no CHANGELOG entry.

Is it worth adding any doccomments somewhere that elaborate on this case so people understand what could happen? I'm not certain there is, but I wanted to make sure you thought about it.

@asomers
Copy link
Member Author

asomers commented Jul 15, 2017

I have no idea why i686-unknown-linux-musl keeps failing. It passed 10,000 times in a row on my system. QEMU is not to blame; i686 doesn't use it. @Susurrus any ideas?

@Susurrus
Copy link
Contributor

Please squash these into a single commit. And then it's r+ by me.

Also, document the double-close risk with unistd::close

Fixes nix-rust#659
@asomers
Copy link
Member Author

asomers commented Jul 16, 2017

bors r+ susurrus

bors bot added a commit that referenced this pull request Jul 16, 2017
677: PtyMaster::drop should panic on EBADF r=asomers

Fixes #659
@bors
Copy link
Contributor

bors bot commented Jul 16, 2017

@bors bors bot merged commit 5fb4ceb into nix-rust:master Jul 16, 2017
bors bot added a commit that referenced this pull request Dec 8, 2022
1921: feat: I/O safety for 'sys/termios' & 'pty' r=asomers a=SteveLauC

#### What this PR does:
1. Adds I/O safety for modules `sys/termios` and `pty`

------


#### Known Problems:

1. [Double free issue on `PtyMaster`](#659)
                                            
   I have changed the `RawFd` in `PtyMaster` to `OwnedFd` in this PR, with this
   change, the double-free issue still exists, see this test code snippet 
   (From [this comment](#659 (comment)))

   ```rust
   use std::io::prelude::*;
   use std::os::unix::io::AsRawFd;
   
   fn main() {
       let mut f = {
           let m = nix::pty::posix_openpt(nix::fcntl::OFlag::O_RDWR).unwrap(); // get fd 3
           nix::unistd::close(m.as_raw_fd()).unwrap(); // close fd 3
           std::fs::File::create("foo").unwrap()       // get fd 3 again
       }; // m goes out of scope, `drop(OwnedFd)`, fd 3 closed
       f.write("whatever".as_bytes()).unwrap(); // EBADF
   }
   ```

   I have tested this code with `nix 0.26.1`, and I am still getting `EBADF`, which means the current impl does not prevent this problem either.

   ```shell
   $ cat Cargo.toml | grep nix
   nix = "0.26.1"

   $ cargo r -q
   thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 9, kind: Uncategorized, message: "Bad file descriptor" }', src/main.rs:10:36
   ```

   If we still wanna the drop of `PtyMaster` panic when the internal `fd` is invalid 
   as we did in #677, then we have to revert the changes to use `RawFd` and manually impl `Drop`.

2. Some trait implementations for some types are removed

   * `struct OpenptyResult`:
     1. PartialEq 
     2. Eq
     3. Hash
     4. Clone

   * `struct ForkptyResult`:
     1. Clone

   * `struct PtyMaster`:
     1. PartialEq
     2. Eq
     3. Hash

   In the previous implementation, these trait impls are `#[derive()]`ed, due to
   the type change to `OwnedFd`, we can no longer derive them. Should we manually
   implement them?

   I kinda think we should at least impl `PartialEq` and `Eq` for `OpenptyResult`
   and `PtyMaster`.

-----
#### Some Clarifications that may help code review

1. For the basic `fd`-related syscall like `read(2)`, `write(2)` and `fcntl(2)`
   , I am still using the old `RawFd` interfaces, as they will be covered in
   other PRs.

2. Two helper functions

   1. `write_all()` in `test/sys/test_termios.rs`:

      ```rust
      /// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
      fn write_all(f: RawFd, buf: &[u8]) {
      /// Helper function analogous to `std::io::Write::write_all`, but for `Fd`s
      fn write_all<Fd: AsFd>(f: &Fd, buf: &[u8]) {
          let mut len = 0;
          while len < buf.len() {
              len += write(f, &buf[len..]).unwrap();
              len += write(f.as_fd().as_raw_fd(), &buf[len..]).unwrap();
          }
      }
      ```

   2. `read_exact()` in `test/test.rs`:

      ```rust
      /// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
      fn read_exact(f: RawFd, buf: &mut [u8]) {
      /// Helper function analogous to `std::io::Read::read_exact`, but for `Fd`s
      fn read_exact<Fd: AsFd>(f: &Fd, buf: &mut [u8]) {
          let mut len = 0;
          while len < buf.len() {
              // get_mut would be better than split_at_mut, but it requires nightly
              let (_, remaining) = buf.split_at_mut(len);
              len += read(f, remaining).unwrap();
              len += read(f.as_fd().as_raw_fd(), remaining).unwrap();
          }
      }
      ```

    I have added I/O safety for them, but it actually does not matter whether
    they use `Fd: AsFd` or `RawFd`. So feel free to ask me to discard these changes
    if you guys don't like it.


Co-authored-by: Steve Lau <stevelauc@outlook.com>
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

Successfully merging this pull request may close these issues.

None yet

2 participants