summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/kernel
diff options
context:
space:
mode:
authorNicolas Lacasse <nlacasse@google.com>2019-02-14 15:46:25 -0800
committerShentubot <shentubot@google.com>2019-02-14 15:47:31 -0800
commit0a41ea72c1f70916bdbb68d9fdfa6c438e28b5b2 (patch)
treece2fdd6bb92036481ea2a44fb091b355b9bfae77 /pkg/sentry/kernel
parentd60ce17a21a28ab32607b195ae42692442322ff8 (diff)
Don't allow writing or reading to TTY unless process group is in foreground.
If a background process tries to read from a TTY, linux sends it a SIGTTIN unless the signal is blocked or ignored, or the process group is an orphan, in which case the syscall returns EIO. See drivers/tty/n_tty.c:n_tty_read()=>job_control(). If a background process tries to write a TTY, set the termios, or set the foreground process group, linux then sends a SIGTTOU. If the signal is ignored or blocked, linux allows the write. If the process group is an orphan, the syscall returns EIO. See drivers/tty/tty_io.c:tty_check_change(). PiperOrigin-RevId: 234044367 Change-Id: I009461352ac4f3f11c5d42c43ac36bb0caa580f9
Diffstat (limited to 'pkg/sentry/kernel')
-rw-r--r--pkg/sentry/kernel/kernel.go44
-rw-r--r--pkg/sentry/kernel/sessions.go29
-rw-r--r--pkg/sentry/kernel/signal_handlers.go8
3 files changed, 51 insertions, 30 deletions
diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go
index e7e5ff777..c6afae2e6 100644
--- a/pkg/sentry/kernel/kernel.go
+++ b/pkg/sentry/kernel/kernel.go
@@ -615,8 +615,11 @@ func (ctx *createProcessContext) Value(key interface{}) interface{} {
// CreateProcess creates a new task in a new thread group with the given
// options. The new task has no parent and is in the root PID namespace.
//
-// If k.Start() has already been called, the created task will begin running
-// immediately. Otherwise, it will be started when k.Start() is called.
+// If k.Start() has already been called, then the created process must be
+// started by calling kernel.StartProcess(tg).
+//
+// If k.Start() has not yet been called, then the created task will begin
+// running when k.Start() is called.
//
// CreateProcess has no analogue in Linux; it is used to create the initial
// application task, as well as processes started by the control server.
@@ -688,22 +691,25 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
AbstractSocketNamespace: args.AbstractSocketNamespace,
ContainerID: args.ContainerID,
}
- t, err := k.tasks.NewTask(config)
- if err != nil {
+ if _, err := k.tasks.NewTask(config); err != nil {
return nil, 0, err
}
// Success.
tgid := k.tasks.Root.IDOfThreadGroup(tg)
- if k.started {
- tid := k.tasks.Root.IDOfTask(t)
- t.Start(tid)
- } else if k.globalInit == nil {
+ if k.globalInit == nil {
k.globalInit = tg
}
return tg, tgid, nil
}
+// StartProcess starts running a process that was created with CreateProcess.
+func (k *Kernel) StartProcess(tg *ThreadGroup) {
+ t := tg.Leader()
+ tid := k.tasks.Root.IDOfTask(t)
+ t.Start(tid)
+}
+
// Start starts execution of all tasks in k.
//
// Preconditions: Start may be called exactly once.
@@ -866,28 +872,6 @@ func (k *Kernel) SendContainerSignal(cid string, info *arch.SignalInfo) error {
return lastErr
}
-// SendProcessGroupSignal sends a signal to all processes inside the process
-// group. It is analagous to kernel/signal.c:kill_pgrp.
-func (k *Kernel) SendProcessGroupSignal(pg *ProcessGroup, info *arch.SignalInfo) error {
- k.extMu.Lock()
- defer k.extMu.Unlock()
- k.tasks.mu.RLock()
- defer k.tasks.mu.RUnlock()
-
- var lastErr error
- for t := range k.tasks.Root.tids {
- if t == t.tg.leader && t.tg.ProcessGroup() == pg {
- t.tg.signalHandlers.mu.Lock()
- defer t.tg.signalHandlers.mu.Unlock()
- infoCopy := *info
- if err := t.sendSignalLocked(&infoCopy, true /*group*/); err != nil {
- lastErr = err
- }
- }
- }
- return lastErr
-}
-
// FeatureSet returns the FeatureSet.
func (k *Kernel) FeatureSet() *cpuid.FeatureSet {
return k.featureSet
diff --git a/pkg/sentry/kernel/sessions.go b/pkg/sentry/kernel/sessions.go
index 78a5b4063..6fd65f2b0 100644
--- a/pkg/sentry/kernel/sessions.go
+++ b/pkg/sentry/kernel/sessions.go
@@ -17,6 +17,7 @@ package kernel
import (
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/refs"
+ "gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/syserror"
)
@@ -119,6 +120,13 @@ func (pg *ProcessGroup) Originator() *ThreadGroup {
return pg.originator
}
+// IsOrphan returns true if this process group is an orphan.
+func (pg *ProcessGroup) IsOrphan() bool {
+ pg.originator.TaskSet().mu.RLock()
+ defer pg.originator.TaskSet().mu.RUnlock()
+ return pg.ancestors == 0
+}
+
// incRefWithParent grabs a reference.
//
// This function is called when this ProcessGroup is being associated with some
@@ -224,6 +232,27 @@ func (pg *ProcessGroup) Session() *Session {
return pg.session
}
+// SendSignal sends a signal to all processes inside the process group. It is
+// analagous to kernel/signal.c:kill_pgrp.
+func (pg *ProcessGroup) SendSignal(info *arch.SignalInfo) error {
+ tasks := pg.originator.TaskSet()
+ tasks.mu.RLock()
+ defer tasks.mu.RUnlock()
+
+ var lastErr error
+ for t := range tasks.Root.tids {
+ if t == t.tg.leader && t.tg.ProcessGroup() == pg {
+ t.tg.signalHandlers.mu.Lock()
+ defer t.tg.signalHandlers.mu.Unlock()
+ infoCopy := *info
+ if err := t.sendSignalLocked(&infoCopy, true /*group*/); err != nil {
+ lastErr = err
+ }
+ }
+ }
+ return lastErr
+}
+
// CreateSession creates a new Session, with the ThreadGroup as the leader.
//
// EPERM may be returned if either the given ThreadGroup is already a Session
diff --git a/pkg/sentry/kernel/signal_handlers.go b/pkg/sentry/kernel/signal_handlers.go
index 3f1ac9898..60cbe85b8 100644
--- a/pkg/sentry/kernel/signal_handlers.go
+++ b/pkg/sentry/kernel/signal_handlers.go
@@ -69,6 +69,14 @@ func (sh *SignalHandlers) CopyForExec() *SignalHandlers {
return sh2
}
+// IsIgnored returns true if the signal is ignored.
+func (sh *SignalHandlers) IsIgnored(sig linux.Signal) bool {
+ sh.mu.Lock()
+ defer sh.mu.Unlock()
+ sa, ok := sh.actions[sig]
+ return ok && sa.Handler == arch.SignalActIgnore
+}
+
// dequeueActionLocked returns the SignalAct that should be used to handle sig.
//
// Preconditions: sh.mu must be locked.