Implement /dev/tty for donated host TTYs

Fixes #10925

PiperOrigin-RevId: 681684673
This commit is contained in:
Nicolas Lacasse
2024-10-02 19:40:43 -07:00
committed by gVisor bot
parent 72193f12c9
commit d5a9d523bb
5 changed files with 42 additions and 0 deletions
+7
View File
@@ -272,6 +272,13 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
return nil, 0, nil, err
}
if ttyFile != nil {
// Index does not matter here. This tty is not coming from a
// devpts mount, so it won't collide with any of the ptys
// created there.
initArgs.TTY = kernel.NewTTY(0, ttyFile)
}
// Set cgroups to the new exec task if cgroups are mounted.
cgroupRegistry := proc.Kernel.CgroupRegistry()
initialCgrps := map[kernel.Cgroup]struct{}{}
+9
View File
@@ -31,6 +31,8 @@ import (
// TTYFileDescription implements vfs.FileDescriptionImpl for a host file
// descriptor that wraps a TTY FD.
//
// It implements kernel.TTYOperations.
//
// +stateify savable
type TTYFileDescription struct {
fileDescription
@@ -49,6 +51,13 @@ type TTYFileDescription struct {
termios linux.KernelTermios
}
// Open re-opens the tty fd, for example via open(/dev/tty). See Linux's
// tty_repoen().
func (t *TTYFileDescription) Open(_ context.Context, _ *vfs.Mount, _ *vfs.Dentry, _ vfs.OpenOptions) (*vfs.FileDescription, error) {
t.vfsfd.IncRef()
return &t.vfsfd, nil
}
// InitForegroundProcessGroup sets the foreground process group and session for
// the TTY. This should only be called once, after the foreground process group
// has been created, but before it has started running.
+9
View File
@@ -991,6 +991,9 @@ type CreateProcessArgs struct {
// Origin indicates how the task was first created.
Origin TaskOrigin
// TTY is the optional TTY to associate with this process.
TTY *TTY
}
// NewContext returns a context.Context that represents the task that will be
@@ -1222,6 +1225,12 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
}
t.traceExecEvent(image) // Simulate exec for tracing.
// Set TTY if configured.
if args.TTY != nil {
t.tg.tty = args.TTY
args.TTY.tg = t.tg
}
// Success.
cu.Release()
tgid := k.tasks.Root.IDOfThreadGroup(tg)
+7
View File
@@ -1110,6 +1110,13 @@ func (l *Loader) createContainerProcess(info *containerInfo) (*kernel.ThreadGrou
// ours either way.
info.procArgs.FDTable = fdTable
if ttyFile != nil {
// Index does not matter here. This tty is not coming from a
// devpts mount, so it won't collide with any of the ptys
// created there.
info.procArgs.TTY = kernel.NewTTY(0, ttyFile)
}
if info.execFD != nil {
if info.procArgs.Filename != "" {
return nil, nil, fmt.Errorf("process must either be started from a file or a filename, not both")
+10
View File
@@ -594,6 +594,16 @@ func TestMultiContainerTerminal(t *testing.T) {
if err := testutil.WaitUntilRead(ptyBuf, "foo-/-123", 5*time.Second); err != nil {
t.Fatalf("echo didn't execute: %v", err)
}
// Make sure we can open /dev/tty. We do this
// by asking `head` to to read 0 bytes, which
// causes it to simply open & close the file.
if _, err := tc.master.Write([]byte("head -n 0 /dev/tty; echo $?\n")); err != nil {
t.Fatalf("master.Write(): %v", err)
}
if err := testutil.WaitUntilRead(ptyBuf, "0", 5*time.Second); err != nil {
t.Fatalf("head didn't execute: %v", err)
}
}
})
}