From 5e66757b835f155f7e50931f54c9f6af8af86f75 Mon Sep 17 00:00:00 2001 From: Yuval Pavel Zholkover Date: Sat, 13 Oct 2018 13:57:27 +0300 Subject: [PATCH] internal/fastwalk: don't cross Dirent.Reclen boundry while looking for NULL in parseDirEnt Crossing Dirent.Reclen boundry was manifested in golang/go#28131 as garbaled filenames, when Dirent.Name was not NULL terminated on FreeBSD due to a bug (parseDirEnt would find a NULL in the following Dirent's Fileno/Reclen fields). Only search for NULL on linux, when the Namlen field is available use it directly instead. Updates golang/go#28131 Change-Id: I64090576c8bad2bd246d1561432bf73d5caee2a9 Reviewed-on: https://go-review.googlesource.com/c/141801 Reviewed-by: Brad Fitzpatrick --- .../fastwalk/fastwalk_dirent_namlen_bsd.go | 13 ++++++++++ .../fastwalk/fastwalk_dirent_namlen_linux.go | 24 +++++++++++++++++++ internal/fastwalk/fastwalk_unix.go | 6 +---- 3 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 internal/fastwalk/fastwalk_dirent_namlen_bsd.go create mode 100644 internal/fastwalk/fastwalk_dirent_namlen_linux.go diff --git a/internal/fastwalk/fastwalk_dirent_namlen_bsd.go b/internal/fastwalk/fastwalk_dirent_namlen_bsd.go new file mode 100644 index 0000000000..a3b26a7bae --- /dev/null +++ b/internal/fastwalk/fastwalk_dirent_namlen_bsd.go @@ -0,0 +1,13 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin freebsd openbsd netbsd + +package fastwalk + +import "syscall" + +func direntNamlen(dirent *syscall.Dirent) uint64 { + return uint64(dirent.Namlen) +} diff --git a/internal/fastwalk/fastwalk_dirent_namlen_linux.go b/internal/fastwalk/fastwalk_dirent_namlen_linux.go new file mode 100644 index 0000000000..61896ffe7e --- /dev/null +++ b/internal/fastwalk/fastwalk_dirent_namlen_linux.go @@ -0,0 +1,24 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux +// +build !appengine + +package fastwalk + +import ( + "bytes" + "syscall" + "unsafe" +) + +func direntNamlen(dirent *syscall.Dirent) uint64 { + const fixedHdr = uint16(unsafe.Offsetof(syscall.Dirent{}.Name)) + nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) + nameLen := bytes.IndexByte(nameBuf[:dirent.Reclen-fixedHdr], 0) + if nameLen < 0 { + panic("failed to find terminating 0 byte in dirent") + } + return uint64(nameLen) +} diff --git a/internal/fastwalk/fastwalk_unix.go b/internal/fastwalk/fastwalk_unix.go index e541c57506..3369b1a0b2 100644 --- a/internal/fastwalk/fastwalk_unix.go +++ b/internal/fastwalk/fastwalk_unix.go @@ -8,7 +8,6 @@ package fastwalk import ( - "bytes" "fmt" "os" "syscall" @@ -114,10 +113,7 @@ func parseDirEnt(buf []byte) (consumed int, name string, typ os.FileMode) { } nameBuf := (*[unsafe.Sizeof(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0])) - nameLen := bytes.IndexByte(nameBuf[:], 0) - if nameLen < 0 { - panic("failed to find terminating 0 byte in dirent") - } + nameLen := direntNamlen(dirent) // Special cases for common things: if nameLen == 1 && nameBuf[0] == '.' {