diff options
author | Michael Pratt <mpratt@google.com> | 2018-07-03 11:27:29 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-07-03 11:28:53 -0700 |
commit | 062a6f6ec5f4bf2ce46790a22d8e7278d51e6836 (patch) | |
tree | 308e57b306ec0d0714567c26a6b36a5778c7d60d | |
parent | 4500155ffc5edfc2d417297d3367f5656dbea5a7 (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.go | 26 | ||||
-rw-r--r-- | pkg/sentry/loader/interpreter.go | 5 | ||||
-rw-r--r-- | pkg/sentry/loader/loader.go | 5 |
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 |