Repository: moby/moby (language: go)

Issue:
v25 regression: Rootless docker - plugin discovery uses wrong path
### Description

We encounter exactly the same problem as earlier described in https://github.com/moby/moby/issues/43111

This issue was fixed in v24.0.0, we are now using v25.0.3

### Reproduce

1. run the commands `docker system prune -a -f --volumes` and `docker system df` 
2. An error is returned: `Error response from daemon: list: error listing plugins: legacy plugin: error reading dir entries: open /etc/docker/plugins: permission denied`

### Expected behavior

The commands should be executed without error

### docker version

```bash
Client: Docker Engine - Community
 Version:           25.0.3
 API version:       1.44
 Go version:        go1.21.6
 Git commit:        4debf41
 Built:             Tue Feb  6 21:14:26 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          25.0.3
  API version:      1.44 (minimum version 1.24)
  Go version:       go1.21.6
  Git commit:       f417435
  Built:            Tue Feb  6 21:14:26 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.28
  GitCommit:        ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
```


### docker info

```bash
Client: Docker Engine - Community
 Version:    25.0.3
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.12.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.24.5
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 3
  Running: 3
  Paused: 0
  Stopped: 0
 Images: 5
 Server Version: 25.0.3
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc version: v1.1.12-0-g51d5e94
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 5.10.0-28-amd64
 Operating System: Debian GNU/Linux 11 (bullseye)
 OSType: linux
 Architecture: x86_64
 CPUs: 12
 Total Memory: 23.46GiB
 Name: tridev002
 ID: KVHD:CZGB:YY5C:SF3K:6OM6:62UH:HZ6V:XF7J:WMBL:KOPK:BEUN:T35H
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Registry Mirrors:
  https://docker.triopsys.net/
 Live Restore Enabled: false
```


### Additional Info

As a workaround group and other are given read and execute permissions for /etc/docker and /etc/docker/plugins


Discussion / hints:
Seems like a dup of #47248?
> Seems like a dup of #47248?

Apparently not, and I can't repro

Can be reproduced with `sudo mkdir -m 0700 /etc/docker/plugins && docker volume ls` 

Fix patch:
diff --git a/pkg/plugins/discovery.go b/pkg/plugins/discovery.go
index 37316ed4829af..503ac574a9091 100644
--- a/pkg/plugins/discovery.go
+++ b/pkg/plugins/discovery.go
@@ -10,6 +10,8 @@ import (
 	"strings"
 	"sync"
 
+	"github.com/containerd/containerd/pkg/userns"
+	"github.com/containerd/log"
 	"github.com/pkg/errors"
 )
 
@@ -56,10 +58,16 @@ func (l *LocalRegistry) Scan() ([]string, error) {
 
 	for _, p := range l.specsPaths {
 		dirEntries, err = os.ReadDir(p)
-		if err != nil && !os.IsNotExist(err) {
+		if err != nil {
+			if os.IsNotExist(err) {
+				continue
+			}
+			if os.IsPermission(err) && userns.RunningInUserNS() {
+				log.L.Debug(err.Error())
+				continue
+			}
 			return nil, errors.Wrap(err, "error reading dir entries")
 		}
-
 		for _, entry := range dirEntries {
 			if entry.IsDir() {
 				infos, err := os.ReadDir(filepath.Join(p, entry.Name()))


Test patch: