@@ -18,10 +18,12 @@ package sandbox
18
18
import (
19
19
"context"
20
20
"fmt"
21
+ "io"
21
22
"math"
22
23
"os"
23
24
"os/exec"
24
25
"strconv"
26
+ "strings"
25
27
"syscall"
26
28
"time"
27
29
@@ -142,7 +144,19 @@ func New(conf *boot.Config, args *Args) (*Sandbox, error) {
142
144
// Wait until the sandbox has booted.
143
145
b := make ([]byte , 1 )
144
146
if l , err := clientSyncFile .Read (b ); err != nil || l != 1 {
145
- return nil , fmt .Errorf ("waiting for sandbox to start: %v" , err )
147
+ err := fmt .Errorf ("waiting for sandbox to start: %v" , err )
148
+ // If the sandbox failed to start, it may be because the binary
149
+ // permissions were incorrect. Check the bits and return a more helpful
150
+ // error message.
151
+ //
152
+ // NOTE: The error message is checked because error types are lost over
153
+ // rpc calls.
154
+ if strings .Contains (err .Error (), io .EOF .Error ()) {
155
+ if permsErr := checkBinaryPermissions (conf ); permsErr != nil {
156
+ return nil , fmt .Errorf ("%v: %v" , err , permsErr )
157
+ }
158
+ }
159
+ return nil , err
146
160
}
147
161
148
162
c .Release ()
@@ -706,7 +720,19 @@ func (s *Sandbox) createSandboxProcess(conf *boot.Config, args *Args, startSyncF
706
720
log .Debugf ("Starting sandbox: %s %v" , binPath , cmd .Args )
707
721
log .Debugf ("SysProcAttr: %+v" , cmd .SysProcAttr )
708
722
if err := specutils .StartInNS (cmd , nss ); err != nil {
709
- return fmt .Errorf ("Sandbox: %v" , err )
723
+ err := fmt .Errorf ("starting sandbox: %v" , err )
724
+ // If the sandbox failed to start, it may be because the binary
725
+ // permissions were incorrect. Check the bits and return a more helpful
726
+ // error message.
727
+ //
728
+ // NOTE: The error message is checked because error types are lost over
729
+ // rpc calls.
730
+ if strings .Contains (err .Error (), syscall .EACCES .Error ()) {
731
+ if permsErr := checkBinaryPermissions (conf ); permsErr != nil {
732
+ return fmt .Errorf ("%v: %v" , err , permsErr )
733
+ }
734
+ }
735
+ return err
710
736
}
711
737
s .child = true
712
738
s .Pid = cmd .Process .Pid
@@ -1169,3 +1195,31 @@ func deviceFileForPlatform(name string) (*os.File, error) {
1169
1195
}
1170
1196
return f , nil
1171
1197
}
1198
+
1199
+ // checkBinaryPermissions verifies that the required binary bits are set on
1200
+ // the runsc executable.
1201
+ func checkBinaryPermissions (conf * boot.Config ) error {
1202
+ // All platforms need the other exe bit
1203
+ neededBits := os .FileMode (0001 )
1204
+ if conf .Platform == platforms .Ptrace {
1205
+ // Ptrace needs the other read bit
1206
+ neededBits |= os .FileMode (0004 )
1207
+ }
1208
+
1209
+ exePath , err := os .Executable ()
1210
+ if err != nil {
1211
+ return fmt .Errorf ("getting exe path: %v" , err )
1212
+ }
1213
+
1214
+ // Check the permissions of the runsc binary and print an error if it
1215
+ // doesn't match expectations.
1216
+ info , err := os .Stat (exePath )
1217
+ if err != nil {
1218
+ return fmt .Errorf ("stat file: %v" , err )
1219
+ }
1220
+
1221
+ if info .Mode ().Perm ()& neededBits != neededBits {
1222
+ return fmt .Errorf (specutils .FaqErrorMsg ("runsc-perms" , fmt .Sprintf ("%s does not have the correct permissions" , exePath )))
1223
+ }
1224
+ return nil
1225
+ }
0 commit comments