Skip to content

Commit 56054fc

Browse files
Ian Lewisgvisor-bot
Ian Lewis
authored andcommitted
Add friendlier messages for frequently encountered errors.
Issue #2270 Issue #1765 PiperOrigin-RevId: 305385436
1 parent 5802051 commit 56054fc

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

runsc/boot/fs.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -824,7 +824,20 @@ func (c *containerMounter) mountSubmount(ctx context.Context, conf *Config, mns
824824

825825
inode, err := filesystem.Mount(ctx, mountDevice(m), mf, strings.Join(opts, ","), nil)
826826
if err != nil {
827-
return fmt.Errorf("creating mount with source %q: %v", m.Source, err)
827+
err := fmt.Errorf("creating mount with source %q: %v", m.Source, err)
828+
// Check to see if this is a common error due to a Linux bug.
829+
// This error is generated here in order to cause it to be
830+
// printed to the user using Docker via 'runsc create' etc. rather
831+
// than simply printed to the logs for the 'runsc boot' command.
832+
//
833+
// We check the error message string rather than type because the
834+
// actual error types (syscall.EIO, syscall.EPIPE) are lost by file system
835+
// implementation (e.g. p9).
836+
// TODO(gvisor.dev/issue/1765): Remove message when bug is resolved.
837+
if strings.Contains(err.Error(), syscall.EIO.Error()) || strings.Contains(err.Error(), syscall.EPIPE.Error()) {
838+
return fmt.Errorf("%v: %s", err, specutils.FaqErrorMsg("memlock", "you may be encountering a Linux kernel bug"))
839+
}
840+
return err
828841
}
829842

830843
// If there are submounts, we need to overlay the mount on top of a ramfs

runsc/sandbox/sandbox.go

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ package sandbox
1818
import (
1919
"context"
2020
"fmt"
21+
"io"
2122
"math"
2223
"os"
2324
"os/exec"
2425
"strconv"
26+
"strings"
2527
"syscall"
2628
"time"
2729

@@ -142,7 +144,19 @@ func New(conf *boot.Config, args *Args) (*Sandbox, error) {
142144
// Wait until the sandbox has booted.
143145
b := make([]byte, 1)
144146
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
146160
}
147161

148162
c.Release()
@@ -706,7 +720,19 @@ func (s *Sandbox) createSandboxProcess(conf *boot.Config, args *Args, startSyncF
706720
log.Debugf("Starting sandbox: %s %v", binPath, cmd.Args)
707721
log.Debugf("SysProcAttr: %+v", cmd.SysProcAttr)
708722
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
710736
}
711737
s.child = true
712738
s.Pid = cmd.Process.Pid
@@ -1169,3 +1195,31 @@ func deviceFileForPlatform(name string) (*os.File, error) {
11691195
}
11701196
return f, nil
11711197
}
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+
}

runsc/specutils/specutils.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,8 @@ func EnvVar(env []string, name string) (string, bool) {
528528
}
529529
return "", false
530530
}
531+
532+
// FaqErrorMsg returns an error message pointing to the FAQ.
533+
func FaqErrorMsg(anchor, msg string) string {
534+
return fmt.Sprintf("%s; see https://gvisor.dev/faq#%s for more details", msg, anchor)
535+
}

0 commit comments

Comments
 (0)