[go] os: avoid escape from Root via ReadDir or Readdir

0 views
Skip to first unread message

Gopher Robot (Gerrit)

unread,
Feb 26, 2026, 7:02:59 PM (2 days ago) Feb 26
to Damien Neil, goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, Go LUCI, Nicholas Husin, Nicholas Husin, golang-co...@googlegroups.com

Gopher Robot submitted the change with unreviewed changes

Unreviewed changes

2 is the latest approved patch-set.
The change was submitted with unreviewed changes in the following files:

```
The name of the file: src/os/root_test.go
Insertions: 1, Deletions: 1.

@@ -2046,7 +2046,7 @@
}
checkFileInfo(t, fileinfos[0])
})
- // File.Readdirnames, returningm []string
+ // File.Readdirnames, returning []string
test("Readdirnames", func(t *testing.T, subdir *os.File) {
names, err := subdir.Readdirnames(-1)
if err != nil {
```
```
The name of the file: src/os/dir_darwin.go
Insertions: 0, Deletions: 1.

@@ -89,7 +89,6 @@
names = append(names, string(name))
} else if mode == readdirDirEntry {
de, err := newUnixDirent(f, string(name), dtToType(dirent.Type))
- println(f.name, de.Name(), err)
if IsNotExist(err) {
// File disappeared between readdir and stat.
// Treat as if it didn't exist.
```

Change information

Commit message:
os: avoid escape from Root via ReadDir or Readdir

When reading the contents of a directory using
File.ReadDir or File.Readdir, the os.FileInfo was
populated on Unix platforms using lstat.
This lstat call is vulnerable to a TOCTOU race
and could escape the root.

For example:
- Open the directory "dir" within a Root.
This directory contains a file named "file".
- Use File.ReadDir to list the contents of "dir",
receiving a os.DirEntry for "dir/file".
- Replace "dir" with a symlink to "/etc".
- Use DirEntry.Info to retrieve the FileInfo for "dir/file".
This FileInfo contains information on "/etc/file" instead.

This escape permits identifying the presence or absence of
files outside a Root, as well as retreiving stat metadata
(size, mode, modification time, etc.) for files outside a Root.

This escape does not permit reading or writing to files
outside a Root.

Fixes #77827
Fixes CVE-2026-27139
Change-Id: I40004f830c588e516aff8ee593d630d36a6a6964
Reviewed-by: Nicholas Husin <hu...@google.com>
Reviewed-by: Nicholas Husin <n...@golang.org>
Auto-Submit: Damien Neil <dn...@google.com>
Files:
  • A src/internal/poll/fstatat_unix.go
  • M src/os/dir_darwin.go
  • M src/os/dir_unix.go
  • M src/os/export_test.go
  • M src/os/file.go
  • M src/os/file_unix.go
  • M src/os/os_test.go
  • M src/os/os_unix_test.go
  • M src/os/root_test.go
  • M src/os/root_unix.go
  • M src/os/stat.go
  • A src/os/statat.go
  • A src/os/statat_other.go
  • A src/os/statat_unix.go
Change size: M
Delta: 14 files changed, 219 insertions(+), 22 deletions(-)
Branch: refs/heads/master
Submit Requirements:
  • requirement satisfiedCode-Review: +2 by Nicholas Husin, +1 by Nicholas Husin
  • requirement satisfiedTryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
Open in Gerrit
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: merged
Gerrit-Project: go
Gerrit-Branch: master
Gerrit-Change-Id: I40004f830c588e516aff8ee593d630d36a6a6964
Gerrit-Change-Number: 749480
Gerrit-PatchSet: 4
Gerrit-Owner: Damien Neil <dn...@google.com>
Gerrit-Reviewer: Damien Neil <dn...@google.com>
Gerrit-Reviewer: Gopher Robot <go...@golang.org>
Gerrit-Reviewer: Nicholas Husin <hu...@google.com>
Gerrit-Reviewer: Nicholas Husin <n...@golang.org>
open
diffy
satisfied_requirement

Cherry Mui (Gerrit)

unread,
Feb 27, 2026, 4:46:32 PM (yesterday) Feb 27
to Damien Neil, goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, Nicholas Husin, Nicholas Husin, Go LUCI, Gopher Robot, golang-co...@googlegroups.com

Cherry Mui submitted the change

Change information

Commit message:
[release-branch.go1.25] os: avoid escape from Root via ReadDir or Readdir


When reading the contents of a directory using
File.ReadDir or File.Readdir, the os.FileInfo was
populated on Unix platforms using lstat.
This lstat call is vulnerable to a TOCTOU race
and could escape the root.

For example:
- Open the directory "dir" within a Root.
This directory contains a file named "file".
- Use File.ReadDir to list the contents of "dir",
receiving a os.DirEntry for "dir/file".
- Replace "dir" with a symlink to "/etc".
- Use DirEntry.Info to retrieve the FileInfo for "dir/file".
This FileInfo contains information on "/etc/file" instead.

This escape permits identifying the presence or absence of
files outside a Root, as well as retreiving stat metadata
(size, mode, modification time, etc.) for files outside a Root.

This escape does not permit reading or writing to files
outside a Root.

For #77827
Fixes #77833

Fixes CVE-2026-27139

Change-Id: I40004f830c588e516aff8ee593d630d36a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/749480
LUCI-TryBot-Result: Go LUCI <golang...@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicholas Husin <hu...@google.com>
Reviewed-by: Nicholas Husin <n...@golang.org>
Auto-Submit: Damien Neil <dn...@google.com>
(cherry picked from commit 657ed934e85dc575aad51356c4b437961e7c1313)
Reviewed-on: https://go-review.googlesource.com/c/go/+/749920
Files:
  • A src/internal/poll/fstatat_unix.go
  • M src/os/dir_darwin.go
  • M src/os/dir_unix.go
  • M src/os/export_test.go
  • M src/os/file.go
  • M src/os/file_unix.go
  • M src/os/os_test.go
  • M src/os/os_unix_test.go
  • M src/os/root_test.go
  • M src/os/root_unix.go
  • M src/os/stat.go
  • A src/os/statat.go
  • A src/os/statat_other.go
  • A src/os/statat_unix.go
Change size: M
Delta: 14 files changed, 219 insertions(+), 22 deletions(-)
Branch: refs/heads/release-branch.go1.25
Submit Requirements:
  • requirement satisfiedCode-Review: +1 by Nicholas Husin, +2 by Nicholas Husin
  • requirement satisfiedTryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: merged
Gerrit-Project: go
Gerrit-Branch: release-branch.go1.25
Gerrit-Change-Id: I40004f830c588e516aff8ee593d630d36a6a6964
Gerrit-Change-Number: 749920
Gerrit-PatchSet: 2
Gerrit-Owner: Damien Neil <dn...@google.com>
Gerrit-Reviewer: Cherry Mui <cher...@google.com>
Gerrit-Reviewer: Damien Neil <dn...@google.com>
Gerrit-Reviewer: Nicholas Husin <hu...@google.com>
Gerrit-Reviewer: Nicholas Husin <n...@golang.org>
Gerrit-CC: Gopher Robot <go...@golang.org>
open
diffy
satisfied_requirement

Cherry Mui (Gerrit)

unread,
Feb 27, 2026, 4:48:29 PM (yesterday) Feb 27
to Damien Neil, goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, Nicholas Husin, Nicholas Husin, Go LUCI, Dmitri Shuralyov, Gopher Robot, golang-co...@googlegroups.com

Cherry Mui submitted the change

Change information

Commit message:
[release-branch.go1.26] os: avoid escape from Root via ReadDir or Readdir


When reading the contents of a directory using
File.ReadDir or File.Readdir, the os.FileInfo was
populated on Unix platforms using lstat.
This lstat call is vulnerable to a TOCTOU race
and could escape the root.

For example:
- Open the directory "dir" within a Root.
This directory contains a file named "file".
- Use File.ReadDir to list the contents of "dir",
receiving a os.DirEntry for "dir/file".
- Replace "dir" with a symlink to "/etc".
- Use DirEntry.Info to retrieve the FileInfo for "dir/file".
This FileInfo contains information on "/etc/file" instead.

This escape permits identifying the presence or absence of
files outside a Root, as well as retreiving stat metadata
(size, mode, modification time, etc.) for files outside a Root.

This escape does not permit reading or writing to files
outside a Root.

For #77827
Fixes #77834

Fixes CVE-2026-27139

Change-Id: I40004f830c588e516aff8ee593d630d36a6a6964
Reviewed-on: https://go-review.googlesource.com/c/go/+/749480
LUCI-TryBot-Result: Go LUCI <golang...@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicholas Husin <hu...@google.com>
Reviewed-by: Nicholas Husin <n...@golang.org>
Auto-Submit: Damien Neil <dn...@google.com>
(cherry picked from commit 657ed934e85dc575aad51356c4b437961e7c1313)
Files:
  • A src/internal/poll/fstatat_unix.go
  • M src/os/dir_darwin.go
  • M src/os/dir_unix.go
  • M src/os/export_test.go
  • M src/os/file.go
  • M src/os/file_unix.go
  • M src/os/os_test.go
  • M src/os/os_unix_test.go
  • M src/os/root_test.go
  • M src/os/root_unix.go
  • M src/os/stat.go
  • A src/os/statat.go
  • A src/os/statat_other.go
  • A src/os/statat_unix.go
Change size: M
Delta: 14 files changed, 219 insertions(+), 22 deletions(-)
Branch: refs/heads/release-branch.go1.26
Submit Requirements:
  • requirement satisfiedCode-Review: +2 by Nicholas Husin, +1 by Nicholas Husin
  • requirement satisfiedTryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: merged
Gerrit-Project: go
Gerrit-Branch: release-branch.go1.26
Gerrit-Change-Id: I40004f830c588e516aff8ee593d630d36a6a6964
Gerrit-Change-Number: 749822
Gerrit-PatchSet: 2
Gerrit-Owner: Damien Neil <dn...@google.com>
Gerrit-Reviewer: Cherry Mui <cher...@google.com>
Gerrit-Reviewer: Dmitri Shuralyov <dmit...@golang.org>
open
diffy
satisfied_requirement
Reply all
Reply to author
Forward
0 new messages