@@ -3,8 +3,11 @@ package runner
33import (
44 "context"
55 "errors"
6+ "fmt"
7+ "os"
68 "os/exec"
79 "path/filepath"
10+ "strings"
811
912 "github.com/buildbarn/bb-remote-execution/pkg/proto/runner"
1013 "github.com/buildbarn/bb-storage/pkg/filesystem"
@@ -17,6 +20,21 @@ import (
1720 "google.golang.org/protobuf/types/known/emptypb"
1821)
1922
23+ // Mount information for the special filesystems
24+ // to mount in the input root when using 'chroot'.
25+ var (
26+ procMountpointComponent = path .MustNewComponent ("proc" )
27+ sysMountpointComponent = path .MustNewComponent ("sys" )
28+ mounts = []struct {
29+ mountpoint path.Component
30+ fstype string
31+ source string
32+ } {
33+ {procMountpointComponent , "proc" , "/proc" },
34+ {sysMountpointComponent , "sysfs" , "/sys" },
35+ }
36+ )
37+
2038// logFileResolver is an implementation of path.ComponentWalker that is
2139// used by localRunner.Run() to traverse to the directory of stdout and
2240// stderr log files, so that they may be opened.
@@ -136,6 +154,42 @@ func (r *localRunner) Run(ctx context.Context, request *runner.RunRequest) (*run
136154 }
137155 cmd .Stdout = stdout
138156
157+ // Mount special filesystems.
158+ requiresSpecialFilesystems := cmd .SysProcAttr != nil && cmd .SysProcAttr .Chroot != ""
159+ var MountRootDirectory filesystem.Directory
160+
161+ if requiresSpecialFilesystems {
162+ var dir filesystem.Directory
163+ dir = r .buildDirectory
164+ // TODO(nils): How to best open the input root `Directory`
165+ // It must be a `localDirectory`, but outer directories can be `lazyDirectory`.
166+ for _ , segment := range strings .Split (request .InputRootDirectory , "/" ) {
167+ component := path .MustNewComponent (segment )
168+ dircloser , err := dir .EnterDirectory (component )
169+ // We want to keep the input root open so we can use its file descriptor.
170+ if segment != "root" {
171+ defer dircloser .Close ()
172+ }
173+
174+ dir = dircloser .(filesystem.Directory )
175+ if err != nil {
176+ return nil , fmt .Errorf ("Could not enter directory component '%s' in '%#v'" , segment , inputRootDirectory )
177+ }
178+ }
179+ MountRootDirectory = dir
180+
181+ for _ , mount := range mounts {
182+ err := MountRootDirectory .Mkdir (mount .mountpoint , 0o555 )
183+ if err != nil && ! os .IsExist (err ) {
184+ return nil , util .StatusWrapf (err , "Failed to create mount point: '%#v' in the input root" , mount .mountpoint )
185+ }
186+
187+ if err := MountRootDirectory .Mount (mount .mountpoint , mount .source , mount .fstype ); err != nil {
188+ return nil , util .StatusWrapf (err , "Failed to mount '%#v' in the input root" , mount )
189+ }
190+ }
191+ }
192+
139193 stderr , err := r .openLog (request .StderrPath )
140194 if err != nil {
141195 stdout .Close ()
@@ -166,6 +220,14 @@ func (r *localRunner) Run(ctx context.Context, request *runner.RunRequest) (*run
166220 }
167221 }
168222
223+ if requiresSpecialFilesystems {
224+ for _ , mount := range mounts {
225+ if err := MountRootDirectory .Unmount (mount .mountpoint ); err != nil {
226+ return nil , util .StatusWrapf (err , "Failed to unmount '%#v' in the input root" , mount )
227+ }
228+ }
229+ }
230+
169231 // Attach rusage information to the response.
170232 posixResourceUsage , err := anypb .New (getPOSIXResourceUsage (cmd ))
171233 if err != nil {
0 commit comments