summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2018-07-03 11:27:29 -0700
committerShentubot <shentubot@google.com>2018-07-03 11:28:53 -0700
commit062a6f6ec5f4bf2ce46790a22d8e7278d51e6836 (patch)
tree308e57b306ec0d0714567c26a6b36a5778c7d60d
parent4500155ffc5edfc2d417297d3367f5656dbea5a7 (diff)
Handle NUL-only paths in exec
The path in execve(2), interpreter script, and ELF interpreter may all be no more than a NUL-byte. Handle each of those cases. PiperOrigin-RevId: 203155745 Change-Id: I1c8b1b387924b23b2cf942341dfc76c9003da959
-rw-r--r--pkg/sentry/loader/elf.go26
-rw-r--r--pkg/sentry/loader/interpreter.go5
-rw-r--r--pkg/sentry/loader/loader.go5
3 files changed, 34 insertions, 2 deletions
diff --git a/pkg/sentry/loader/elf.go b/pkg/sentry/loader/elf.go
index d2f18cd4f..0462a1788 100644
--- a/pkg/sentry/loader/elf.go
+++ b/pkg/sentry/loader/elf.go
@@ -405,6 +405,10 @@ func loadParsedELF(ctx context.Context, m *mm.MemoryManager, f *fs.File, info el
}
case elf.PT_INTERP:
+ if phdr.Filesz < 2 {
+ ctx.Infof("PT_INTERP path too small: %v", phdr.Filesz)
+ return loadedELF{}, syserror.ENOEXEC
+ }
if phdr.Filesz > syscall.PathMax {
ctx.Infof("PT_INTERP path too big: %v", phdr.Filesz)
return loadedELF{}, syserror.ENOEXEC
@@ -423,8 +427,26 @@ func loadParsedELF(ctx context.Context, m *mm.MemoryManager, f *fs.File, info el
return loadedELF{}, syserror.ENOEXEC
}
- // Strip NUL-terminator from string.
- interpreter = string(path[:len(path)-1])
+ // Strip NUL-terminator and everything beyond from
+ // string. Note that there may be a NUL-terminator
+ // before len(path)-1.
+ interpreter = string(path[:bytes.IndexByte(path, '\x00')])
+ if interpreter == "" {
+ // Linux actually attempts to open_exec("\0").
+ // open_exec -> do_open_execat fails to check
+ // that name != '\0' before calling
+ // do_filp_open, which thus opens the working
+ // directory. do_open_execat returns EACCES
+ // because the directory is not a regular file.
+ //
+ // We bypass that nonsense and simply
+ // short-circuit with EACCES. Those this does
+ // mean that there may be some edge cases where
+ // the open path would return a different
+ // error.
+ ctx.Infof("PT_INTERP path is empty: %v", path)
+ return loadedELF{}, syserror.EACCES
+ }
}
}
diff --git a/pkg/sentry/loader/interpreter.go b/pkg/sentry/loader/interpreter.go
index b8ecbe92f..7249b8f30 100644
--- a/pkg/sentry/loader/interpreter.go
+++ b/pkg/sentry/loader/interpreter.go
@@ -82,6 +82,11 @@ func parseInterpreterScript(ctx context.Context, filename string, f *fs.File, ar
}
}
+ if string(interp) == "" {
+ ctx.Infof("Interpreter script contains no interpreter: %v", line)
+ return "", []string{}, syserror.ENOEXEC
+ }
+
// Build the new argument list:
//
// 1. The interpreter.
diff --git a/pkg/sentry/loader/loader.go b/pkg/sentry/loader/loader.go
index 3cda0fe6f..1b2e9f183 100644
--- a/pkg/sentry/loader/loader.go
+++ b/pkg/sentry/loader/loader.go
@@ -55,6 +55,11 @@ func readFull(ctx context.Context, f *fs.File, dst usermem.IOSequence, offset in
//
// name must be a readable, executable, regular file.
func openPath(ctx context.Context, mm *fs.MountNamespace, root, wd *fs.Dirent, maxTraversals uint, name string) (*fs.Dirent, *fs.File, error) {
+ if name == "" {
+ ctx.Infof("cannot open empty name")
+ return nil, nil, syserror.ENOENT
+ }
+
d, err := mm.FindInode(ctx, root, wd, name, maxTraversals)
if err != nil {
return nil, nil, err