Skip to content

FileStream.Unix: prevent open to cause setting the controlling terminal.#129166

Open
tmds wants to merge 1 commit into
dotnet:mainfrom
tmds:o-noctty
Open

FileStream.Unix: prevent open to cause setting the controlling terminal.#129166
tmds wants to merge 1 commit into
dotnet:mainfrom
tmds:o-noctty

Conversation

@tmds

@tmds tmds commented Jun 9, 2026

Copy link
Copy Markdown
Member

This passes the O_NOCTTY flag to prevent terminal devices from becoming the controlling terminal of the process.
Without this flag, opening a terminal device (like a serial port) on a process with no controlling terminal would make it the controlling terminal. When the serial port then disconnects, the .NET process can get an unexpected SIGHUP which causes it to terminate.

Fixes #129156.

@adamsitnik ptal.

This passes the O_NOCTTY flag to prevent terminal devices from
becoming the controlling terminal of the process.
Without this flag, opening a terminal device (like a serial port)
on a process with no controlling terminal would make it the
controlling terminal. When the serial port then disconnects,
the .NET process can get an unexpected SIGHUP which causes
it to terminate.
@github-actions github-actions Bot added the area-PAL-coreclr only for closed issues label Jun 9, 2026
@adamsitnik adamsitnik requested a review from Copilot June 9, 2026 14:27
@adamsitnik adamsitnik added area-System.IO and removed area-PAL-coreclr only for closed issues labels Jun 9, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-io
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the Unix SystemNative_Open shim in System.Native to always include O_NOCTTY, preventing terminal/TTY device nodes opened via File/FileStream (and other Interop.Sys.Open call sites) from implicitly becoming the process controlling terminal.

Changes:

  • Adds O_NOCTTY to the open(2) flags used by SystemNative_Open on Unix.
  • Documents the intent inline with a short comment.
Comments suppressed due to low confidence (1)

src/native/libs/System.Native/pal_io.c:356

  • On platforms without O_CLOEXEC support, we always call fcntl(result, F_SETFD, FD_CLOEXEC) when PAL_O_CLOEXEC was requested, even if open() failed (result < 0). That can overwrite errno from the failing open() (e.g., ENOENT -> EBADF) and cause managed code to observe the wrong error. It also doesn't retry fcntl on EINTR or handle a rare fcntl failure by closing the fd.
    while ((result = open(path, flags, (mode_t)mode)) < 0 && errno == EINTR);
#if !HAVE_O_CLOEXEC
    if (old_flags & PAL_O_CLOEXEC)
    {
        fcntl(result, F_SETFD, FD_CLOEXEC);
    }

Comment thread src/native/libs/System.Native/pal_io.c

@adamsitnik adamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tmds It LGTM, but would you be able to provide a regression test? With ProcessStartInfo.StartDetached you can start a process that calls setsid after fork:

// Start the child in a new session when startDetached is set, making it independent
// of the parent's process group and terminal.
if (startDetached && setsid() == -1)

Thanks!

@tmds

tmds commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

It LGTM, but would you be able to provide a regression test? With ProcessStartInfo.StartDetached you can start a process that calls setsid after fork:

I haven't included a test because it would need some interop to create a pty the child could open. I'm not sure the complexity of the test justifies how likely this is to regress.

@adamsitnik adamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It LGTM, but would you be able to provide a regression test? With ProcessStartInfo.StartDetached you can start a process that calls setsid after fork:

I haven't included a test because it would need some interop to create a pty the child could open. I'm not sure the complexity of the test justifies how likely this is to regress.

Sounds reasonable to me. Let's revisit it once we implement #128565

@adamsitnik adamsitnik enabled auto-merge (squash) June 9, 2026 15:21
@adamsitnik adamsitnik added this to the 11.0.0 milestone Jun 9, 2026
@jkotas

jkotas commented Jun 9, 2026

Copy link
Copy Markdown
Member

What are the chances that some app depends on this behavior and be broken by this change?

@tmds

tmds commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

What are the chances that some app depends on this behavior and be broken by this change?

Very low. It would be weird for a process that has no controlling terminal to try and set one.

@tmds

tmds commented Jun 9, 2026

Copy link
Copy Markdown
Member Author

Very low. It would be weird for a process that has no controlling terminal to try and set one.

The main use-case where you want to set the controlling terminal is pseudo terminals (#128565). Something like https://github.com/mitchdenny/hex1b does it through interop. That library is calling forkpty.

As a side-effect of open, it is more likely to be a bug than it is used as a feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use O_NOCTTY flag in .NET APIs that open files.

4 participants