Skip to content

Commit 2c950f1

Browse files
ethical-buddygeyslan
authored andcommitted
fix(container): stop masking procfs access errors
Map only ErrNotExist to ErrContainerFSUnreachable in the GetHostAbsPath fallback path, so dead-process races are quietly handled while real access errors (e.g. ErrPermission from missing CAP_SYS_PTRACE or Yama ptrace_scope restrictions) propagate to callers and surface at error level. Also wrap errors with %w in getProcessFSRoot to preserve the error chain for callers using errors.Is.
1 parent a1f33a9 commit 2c950f1

2 files changed

Lines changed: 50 additions & 3 deletions

File tree

pkg/datastores/container/path_resolver.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ func (cPathRes *ContainerPathResolver) GetHostAbsPath(mountNSAbsolutePath string
8282

8383
procFSRoot, err := cPathRes.getProcessFSRoot(uint(pid))
8484
if err != nil {
85-
return "", errfmt.Errorf("could not access process %d FS: %v", pid, err)
85+
if errors.Is(err, fs.ErrNotExist) {
86+
return "", ErrContainerFSUnreachable
87+
}
88+
89+
return "", errfmt.Errorf("could not access process %d FS: %w", pid, err)
8690
}
8791

8892
// register this process in the mount namespace
@@ -105,7 +109,7 @@ func (cPathRes *ContainerPathResolver) getProcessFSRoot(pid uint) (string, error
105109
entries, err := fs.ReadDir(cPathRes.fs, strings.TrimPrefix(procRootPath, "/"))
106110
if err != nil {
107111
// This process is either not alive or we don't have permissions to access.
108-
return "", errfmt.Errorf("failed accessing process FS root %s: %v", procRootPath, err)
112+
return "", errfmt.WrapError(fmt.Errorf("failed accessing process FS root %s: %w", procRootPath, err))
109113
}
110114
if len(entries) == 0 {
111115
return "", errfmt.Errorf("process FS root (%s) is empty", procRootPath)
@@ -307,6 +311,6 @@ func (cPathRes *ContainerPathResolver) isFileAccessible(path string) bool {
307311
}
308312

309313
var (
310-
ErrContainerFSUnreachable = errors.New("container file system is unreachable in mount namespace because there are not living children")
314+
ErrContainerFSUnreachable = errors.New("container file system is unreachable in mount namespace")
311315
ErrNonAbsolutePath = errors.New("file path is not absolute in its container mount point")
312316
)

pkg/datastores/container/path_resolver_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package container
22

33
import (
4+
"errors"
45
"fmt"
6+
"io/fs"
57
"testing"
68
"testing/fstest"
79

@@ -337,3 +339,44 @@ func TestPathResolver_isFileAccessible(t *testing.T) {
337339
// Test with a directory (should be accessible but not readable as a file)
338340
assert.True(t, pres.isFileAccessible("/proc"))
339341
}
342+
343+
// errorFS is a fake fs.FS that returns a fixed error for all ReadDir calls.
344+
type errorFS struct {
345+
err error
346+
}
347+
348+
func (e errorFS) Open(name string) (fs.File, error) {
349+
return nil, &fs.PathError{Op: "open", Path: name, Err: e.err}
350+
}
351+
352+
func (e errorFS) ReadDir(name string) ([]fs.DirEntry, error) {
353+
return nil, &fs.PathError{Op: "readdir", Path: name, Err: e.err}
354+
}
355+
356+
func TestPathResolver_getProcessFSRoot_PermissionDenied(t *testing.T) {
357+
t.Parallel()
358+
359+
bucket := bucketcache.BucketCache{}
360+
bucket.Init(20)
361+
pres := InitContainerPathResolver(&bucket)
362+
pres.fs = errorFS{err: fs.ErrPermission}
363+
364+
_, err := pres.getProcessFSRoot(1234)
365+
require.Error(t, err)
366+
assert.ErrorIs(t, err, fs.ErrPermission)
367+
assert.False(t, errors.Is(err, fs.ErrNotExist))
368+
}
369+
370+
func TestPathResolver_getProcessFSRoot_NotExist(t *testing.T) {
371+
t.Parallel()
372+
373+
bucket := bucketcache.BucketCache{}
374+
bucket.Init(20)
375+
pres := InitContainerPathResolver(&bucket)
376+
pres.fs = errorFS{err: fs.ErrNotExist}
377+
378+
_, err := pres.getProcessFSRoot(1234)
379+
require.Error(t, err)
380+
assert.ErrorIs(t, err, fs.ErrNotExist)
381+
assert.True(t, errors.Is(err, fs.ErrNotExist))
382+
}

0 commit comments

Comments
 (0)