@@ -3,20 +3,39 @@ package runner
33import (
44 "context"
55 "errors"
6+ "fmt"
67 "os/exec"
78 "path/filepath"
9+ "strings"
10+ "sync"
811
912 "github.com/buildbarn/bb-remote-execution/pkg/proto/runner"
1013 "github.com/buildbarn/bb-storage/pkg/filesystem"
1114 "github.com/buildbarn/bb-storage/pkg/filesystem/path"
1215 "github.com/buildbarn/bb-storage/pkg/util"
16+ "golang.org/x/sys/unix"
1317
1418 "google.golang.org/grpc/codes"
1519 "google.golang.org/grpc/status"
1620 "google.golang.org/protobuf/types/known/anypb"
1721 "google.golang.org/protobuf/types/known/emptypb"
1822)
1923
24+ // Mount information for the special filesystems
25+ // to mount in the input root when using 'chroot'.
26+ var (
27+ procMountpointComponent = path .MustNewComponent ("proc" )
28+ sysMountpointComponent = path .MustNewComponent ("sys" )
29+ mounts = []struct {
30+ mountpoint path.Component
31+ fstype string
32+ source string
33+ }{
34+ {procMountpointComponent , "proc" , "/proc" },
35+ {sysMountpointComponent , "sysfs" , "/sys" },
36+ }
37+ )
38+
2039// logFileResolver is an implementation of path.ComponentWalker that is
2140// used by localRunner.Run() to traverse to the directory of stdout and
2241// stderr log files, so that they may be opened.
@@ -65,6 +84,7 @@ type localRunner struct {
6584 buildDirectory filesystem.Directory
6685 buildDirectoryPath * path.Builder
6786 commandCreator CommandCreator
87+ chdirLock * sync.Mutex
6888 setTmpdirEnvironmentVariable bool
6989}
7090
@@ -95,6 +115,7 @@ func NewLocalRunner(buildDirectory filesystem.Directory, buildDirectoryPath *pat
95115 buildDirectory : buildDirectory ,
96116 buildDirectoryPath : buildDirectoryPath ,
97117 commandCreator : commandCreator ,
118+ chdirLock : & sync.Mutex {},
98119 setTmpdirEnvironmentVariable : setTmpdirEnvironmentVariable ,
99120 }
100121}
@@ -136,6 +157,44 @@ func (r *localRunner) Run(ctx context.Context, request *runner.RunRequest) (*run
136157 }
137158 cmd .Stdout = stdout
138159
160+ // Mount special filesystems.
161+ requiresSpecialFilesystems := cmd .SysProcAttr != nil && cmd .SysProcAttr .Chroot != ""
162+ var MountRootDirectory filesystem.Directory
163+
164+ if requiresSpecialFilesystems {
165+ var dir filesystem.Directory
166+ dir = r .buildDirectory
167+ // TODO(nils): How to best open the input root `Directory`
168+ // It must be a `localDirectory`, but outer directories can be `lazyDirectory`.
169+ for _ , segment := range strings .Split (request .InputRootDirectory , "/" ) {
170+ component := path .MustNewComponent (segment )
171+ dircloser , err := dir .EnterDirectory (component )
172+ // We want to keep the input root open so we can use its file descriptor.
173+ if segment != "root" {
174+ defer dircloser .Close ()
175+ }
176+
177+ dir = dircloser .(filesystem.Directory )
178+ if err != nil {
179+ return nil , fmt .Errorf ("Could not enter directory component '%s' in '%#v'" , segment , inputRootDirectory )
180+ }
181+ }
182+ MountRootDirectory = dir
183+
184+ for _ , mount := range mounts {
185+ err := MountRootDirectory .Mkdir (mount .mountpoint , 0o555 )
186+ if err != nil {
187+ if err != unix .EEXIST {
188+ return nil , util .StatusWrapf (err , "Failed to create mount point: '%#v' in the input root" , mount .mountpoint )
189+ }
190+ }
191+
192+ if err := MountRootDirectory .Mount (mount .mountpoint , mount .source , mount .fstype , 0 ); err != nil {
193+ return nil , util .StatusWrapf (err , "Failed to mount '%#v' in the input root" , mount )
194+ }
195+ }
196+ }
197+
139198 stderr , err := r .openLog (request .StderrPath )
140199 if err != nil {
141200 stdout .Close ()
@@ -166,6 +225,14 @@ func (r *localRunner) Run(ctx context.Context, request *runner.RunRequest) (*run
166225 }
167226 }
168227
228+ if requiresSpecialFilesystems {
229+ for _ , mount := range mounts {
230+ if err := MountRootDirectory .Unmount (r .chdirLock , mount .mountpoint ); err != nil {
231+ return nil , util .StatusWrapf (err , "Failed to unmount '%#v' in the input root" , mount )
232+ }
233+ }
234+ }
235+
169236 // Attach rusage information to the response.
170237 posixResourceUsage , err := anypb .New (getPOSIXResourceUsage (cmd ))
171238 if err != nil {
0 commit comments