From fa7217f74de31f949e386efea1713df195a91900 Mon Sep 17 00:00:00 2001
From: Damien Neil <dneil@google.com>
Date: Thu, 27 Mar 2025 16:22:38 -0700
Subject: [PATCH] [release-branch.go1.24] os: avoid panic in Root when symlink
 references the root

We would panic when opening a symlink ending in ..,
where the symlink references the root itself.

For #73081
Fixes #73082

Change-Id: I7dc3f041ca79df7942feec58c197fde6881ecae5
Reviewed-on: https://go-review.googlesource.com/c/go/+/661416
Reviewed-by: Alan Donovan <adonovan@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
(cherry picked from commit cfc784a152ebbc4fc0b8bf13c02e0f6eb9c980bd)
Reviewed-on: https://go-review.googlesource.com/c/go/+/662315
---
 src/os/root_openat.go |  3 +++
 src/os/root_test.go   | 27 +++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/src/os/root_openat.go b/src/os/root_openat.go
index a03208b4c17..6fc02a1a071 100644
--- a/src/os/root_openat.go
+++ b/src/os/root_openat.go
@@ -146,6 +146,9 @@ func doInRoot[T any](r *Root, name string, f func(parent sysfdType, name string)
 				return ret, errPathEscapes
 			}
 			parts = slices.Delete(parts, i-count, end)
+			if len(parts) == 0 {
+				parts = []string{"."}
+			}
 			i = 0
 			if dirfd != rootfd {
 				syscall.Close(dirfd)
diff --git a/src/os/root_test.go b/src/os/root_test.go
index cbb985b2cee..6f6f6cc8267 100644
--- a/src/os/root_test.go
+++ b/src/os/root_test.go
@@ -1176,6 +1176,33 @@ func TestRootRaceRenameDir(t *testing.T) {
 	}
 }
 
+func TestRootSymlinkToRoot(t *testing.T) {
+	dir := makefs(t, []string{
+		"d/d => ..",
+	})
+	root, err := os.OpenRoot(dir)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer root.Close()
+	if err := root.Mkdir("d/d/new", 0777); err != nil {
+		t.Fatal(err)
+	}
+	f, err := root.Open("d/d")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	names, err := f.Readdirnames(-1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	slices.Sort(names)
+	if got, want := names, []string{"d", "new"}; !slices.Equal(got, want) {
+		t.Errorf("root contains: %q, want %q", got, want)
+	}
+}
+
 func TestOpenInRoot(t *testing.T) {
 	dir := makefs(t, []string{
 		"file",
-- 
GitLab