google / google/gvisor

gofer: hard-link aliases of inotify-watched files leak dentries+inodes, bypassing --dcache

Open
#14,619 2 comments 0 reactions 1 assignee Claimed by @milantracy View on GitHub
type: bug
Dominant language
Go
Stars
19.3k
Forks
2k
Avg merge
3d 5h
Merged PRs (30d)
264

Description

### Description

Aliases share the inode's watch set. A zero-ref alias with a live watch is never entered in the dentry cache but stays alive in parent.children. On final inotify_rm_watch, OnZeroWatches fires only on one target - siblings are never revisited, so they're neither cached nor destroyed. The leaked dentry+inode holds the file's host FD open in the sentry - sentry FDs grow per alias.

### Steps to reproduce

1. Watch a file (inotify_add_watch).
2. Create a hard link to it, drop the alias to zero refs.
3. Remove the watch (inotify_rm_watch).

Repro: https://gist.github.com/ildar-safarov/70fd110f0a93d5204adec11b9ea5de21
Run: `RUNSC=/path/to/runsc sudo -E ./repro-gofer-inotify-hardlink.py`

Expected output:
```
ctl (no watch): no leaks (0 gofer.dentry, 0 gofer.inode) fds: gofer=21 sentry=137
bug (watch): 6004 leaked objects (3002 gofer.dentry, 3002 gofer.inode) fds: gofer=21 sentry=6037
logs kept at: /tmp/gofer-hl-inotify.6egj9jwa
```

### runsc version

```shell
runsc version 602040cbcc58
spec: 1.2.1
```

### docker version (if using docker)

```shell

```

### uname

Linux [REDACTED] 6.8.0-137-generic #137-Ubuntu SMP PREEMPT_DYNAMIC Fri Jul 17 20:28:23 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux

### kubectl (if using Kubernetes)

```shell

```

### repo state (if built from source)

release-20260831.0-12-g602040cbc

### runsc debug logs (if available)

```shell

```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.