Skip to content

Commit

Permalink
refs #23: Improve jail for git/shell kernels.
Browse files Browse the repository at this point in the history
 * Now shell's job control (e.g., Ctrl+Z) works correctly.

   - It uses PTRACE_SEIZE instead of PTRACE_ATTACH/PTRACE_TRACEME
     to handle group-stop scenarios properly.
     (introduce Linux kernel 3.4 or later)

   - Improved jail and intra-jail synchronization on startup.

 * Optimized the tracer loop of jail so that it uses only one
   goroutine to monitor child signals.
   (No more recreation for every signal!)

 * Set TERM environment variable and let jail keep it.

 * Know problem:

   - To allow self-stopping in intra-jail, I had to allow "kill"
     syscall blindly.  Killing pid 1 is prevented by Docker but
     killing the jail is allowed.  Fortunately, the other parts of
     Sorna API service handles this situation well, notifying server
     termination to the user without leaking coroutines.

   - If we could remove already-installed seccomp filters in runtime
     then we can solve the above problem.
  • Loading branch information
achimnol committed Feb 14, 2017
1 parent ac85b89 commit fbeb647
Show file tree
Hide file tree
Showing 9 changed files with 418 additions and 196 deletions.
4 changes: 2 additions & 2 deletions bin/intra-jail
Git LFS file not shown
4 changes: 2 additions & 2 deletions bin/intra-jail-check
Git LFS file not shown
4 changes: 2 additions & 2 deletions bin/jail
Git LFS file not shown
4 changes: 2 additions & 2 deletions bin/jail-check
Git LFS file not shown
1 change: 1 addition & 0 deletions git/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ RUN apt-get install -y nodejs nodejs-legacy npm

# Configure the shell to use Unicode characeters
ENV LANG en_US.UTF-8
ENV TERM xterm
RUN sed -i 's/# *\(set convert-meta off\)/\1/' /etc/inputrc; \
locale-gen en_US.UTF-8; \
echo 'set hlsearch incsearch sts=4 sw=4 et' >> /etc/vim/vimrc.local; \
Expand Down
56 changes: 44 additions & 12 deletions intra-jail/main.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package main

import (
"github.com/fatih/color"
seccomp "github.com/seccomp/libseccomp-golang"
"log"
"os"
Expand All @@ -9,37 +10,68 @@ import (
)

func main() {
syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PTRACER, uintptr(os.Getppid()), 0)

// Inform the parent that I'm ready to continue.
// This must be called before setting up seccomp syscall filters,
// as the filter disables use of ptrace.
syscall.Kill(os.Getpid(), syscall.SIGSTOP)
l := log.New(os.Stderr, "", 0)

syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PTRACER, uintptr(os.Getppid()), 0)

arch, _ := seccomp.GetNativeArch()
filter, _ := seccomp.NewFilter(seccomp.ActErrno.SetReturnCode(int16(syscall.EPERM)))
for _, syscallName := range policy.TracedSyscalls {
syscallId, _ := seccomp.GetSyscallFromNameByArch(syscallName, arch)
filter.AddRuleExact(syscallId, seccomp.ActTrace)
}
for _, syscallName := range policy.AllowedSyscalls {
syscallId, _ := seccomp.GetSyscallFromNameByArch(syscallName, arch)
filter.AddRuleExact(syscallId, seccomp.ActAllow)
}
for _, syscallName := range policy.TracedSyscalls {
syscallId, _ := seccomp.GetSyscallFromNameByArch(syscallName, arch)
filter.AddRuleExact(syscallId, seccomp.ActTrace)
}
for syscallName, cond := range policy.ConditionallyAllowedSyscalls {
syscallId, _ := seccomp.GetSyscallFromNameByArch(syscallName, arch)
filter.AddRuleConditional(syscallId, seccomp.ActAllow, []seccomp.ScmpCondition{cond})
}
filter.SetNoNewPrivsBit(true)

// Load seccomp filters into the kernel.
l := log.New(os.Stderr, "", 0)
err := filter.Load()
if err != nil {
l.Fatal("ScmpFilter.Load: ", err)
color.Set(color.FgRed)
l.Printf("ScmpFilter.Load (1): ", err)
color.Unset()
os.Exit(1)
}

// Inform the parent that I'm ready to continue.
// Any code before this line code must use only non-traced system calls in
// the filter because the tracer has not set up itself yet.
// (traced syscalls will cause ENOSYS "function not implemented" error)
syscall.Kill(os.Getpid(), syscall.SIGSTOP)

// Now we have the working tracer parent.
// Make kill() syscall to be traced as well for more sophisticated filtering.
killSyscalls := []string{"kill", "killpg", "tkill", "tgkill"}
for _, syscallName := range killSyscalls {
scId, _ := seccomp.GetSyscallFromNameByArch(syscallName, arch)
filter.AddRuleExact(scId, seccomp.ActTrace)
}
err = filter.Load()
if err != nil {
color.Set(color.FgRed)
l.Printf("ScmpFilter.Load (2): ", err)
color.Unset()
os.Exit(1)
}

// NOTE: signal.Reset() here causes race conditions with the tracer.
// (syscall tracing doesn't work deterministically with it.)

// Replace myself with the language runtime.
err = syscall.Exec(os.Args[1], os.Args[1:], os.Environ())
l.Fatalf("Exec: %s\n", err)

// NOTE: "function not implemented" errors here may be due to above codes.
color.Set(color.FgRed)
l.Printf("Exec: %s\n", err)
color.Unset()
os.Exit(1)
}

// vim: ts=4 sts=4 sw=4 noet
Loading

0 comments on commit fbeb647

Please sign in to comment.