Skip to content

sentry: use cryptographic PRNG for security-sensitive randomization#12695

Closed
KevinZhao wants to merge 5 commits intogoogle:masterfrom
KevinZhao:fix/weak-prng-security-sensitive
Closed

sentry: use cryptographic PRNG for security-sensitive randomization#12695
KevinZhao wants to merge 5 commits intogoogle:masterfrom
KevinZhao:fix/weak-prng-security-sensitive

Conversation

@KevinZhao
Copy link
Copy Markdown
Contributor

Replace math/rand with gvisor.dev/gvisor/pkg/rand (backed by crypto/rand
or getrandom(2)) in 5 security-sensitive code paths that currently use the
non-cryptographic math/rand:

File Usage Risk
mm/syscalls.go Stack ASLR Stack address prediction aids ROP
systrap/stub_unsafe.go Stub code layout Sentry code location prediction
systrap/usertrap/usertrap_amd64.go Trap table layout Syscall dispatch hijacking
netlink/port/port.go Port allocation Port collision/hijacking
inet/abstract_socket_namespace.go Socket autobind Socket name prediction

math/rand is not cryptographically secure — its output is deterministic given
the internal state, which can be recovered from observed outputs (e.g., by
observing one's own stack address via /proc/self/maps and deducing future
randomization outputs for other processes in the same sandbox).

gvisor.dev/gvisor/pkg/rand already provides matching API (Uint32, Uint64,
Int63n) backed by getrandom(2) / crypto/rand.Reader.

Related: CVE-2024-10026 and CVE-2024-10603 fixed the same class of weakness
(math/rand for network identifiers) in the TCP/IP stack. These 5 files were
not addressed by those fixes.

Copy link
Copy Markdown
Collaborator

@EtiennePerot EtiennePerot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread pkg/sentry/kernel/syslog.go Outdated
Comment on lines +92 to +97
// cryptoFloat64 returns a cryptographically random float64 in [0, 1).
cryptoFloat64 := func() float64 {
var b [8]byte
crand.Read(b[:])
return float64(binary.NativeEndian.Uint64(b[:])>>11) / (1 << 53)
}
Copy link
Copy Markdown
Collaborator

@EtiennePerot EtiennePerot Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just randomly-generated syslog messages for fun. They do not need cryptographic randomness.

Please revert these changes here and in other places that do not need randomness to state as such, to ensure future agent-based PRs do not get tempted again to change this in the future.

Comment thread runsc/cmd/do.go Outdated
}

c.cid = fmt.Sprintf("runsc-%06d", rand.Int31n(1000000))
c.cid = fmt.Sprintf("runsc-%06d", rand.Int63n(1000000))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runsc do is just for a debug command, so cryptographic randomness is not needed here. (Also, 1000000 fits in 31 bits, so this is consuming 2x the entropy that it actually needs to consume)

Comment thread runsc/metricserver/metricserver.go Outdated
Comment on lines +625 to +634
// Fisher-Yates shuffle using cryptographic PRNG.
perm := make([]int, len(loadedSandboxes))
for i := range perm {
perm[i] = i
}
for i := len(perm) - 1; i > 0; i-- {
j := int(crand.Int63n(int64(i + 1)))
perm[i], perm[j] = perm[j], perm[i]
}
for _, sandboxIndex := range perm {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a best-effort way to avoid slow sandboxes across metric fetches. It does not need cryptographic randomness, especially if that comes at the complexity cost of an inline Fisher-Yates implementation.

panic("failed to map stub code")
}
r := regions[rand.Int()%n]
r := regions[int(rand.Uint64())%n]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apply modulo before casting

@KevinZhao
Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review @EtiennePerot. Updated per your feedback:

  • Reverted syslog.go, do.go, metricserver.go, and lisafs/sample_message.go — none of these need cryptographic randomness
  • Fixed modulo-before-cast in stub_unsafe.go (rand.Uint64()%uint64(n) instead of int() cast first)
  • Kept only 5 genuinely security-sensitive files: mm/syscalls.go (ASLR), stub_unsafe.go (stub ASLR), usertrap_amd64.go (trap table), netlink/port.go (port allocation), abstract_socket_namespace.go (autobind — matches kernel get_random_u32() behavior)

Net diff is now 5 files, 7 insertions, 7 deletions.

@KevinZhao
Copy link
Copy Markdown
Contributor Author

Hi @EtiennePerot — I've addressed all the review feedback (reverted non-security files, fixed modulo-before-cast). The diff is now just 5 files with security-sensitive math/rand usage. Could you take another look when you have a moment?

copybara-service Bot pushed a commit that referenced this pull request Mar 30, 2026
Replace `math/rand` with `gvisor.dev/gvisor/pkg/rand` (backed by `crypto/rand`
or `getrandom(2)`) in 5 security-sensitive code paths that currently use the
non-cryptographic `math/rand`:

| File | Usage | Risk |
|------|-------|------|
| `mm/syscalls.go` | Stack ASLR | Stack address prediction aids ROP |
| `systrap/stub_unsafe.go` | Stub code layout | Sentry code location prediction |
| `systrap/usertrap/usertrap_amd64.go` | Trap table layout | Syscall dispatch hijacking |
| `netlink/port/port.go` | Port allocation | Port collision/hijacking |
| `inet/abstract_socket_namespace.go` | Socket autobind | Socket name prediction |

`math/rand` is not cryptographically secure — its output is deterministic given
the internal state, which can be recovered from observed outputs (e.g., by
observing one's own stack address via `/proc/self/maps` and deducing future
randomization outputs for other processes in the same sandbox).

`gvisor.dev/gvisor/pkg/rand` already provides matching API (`Uint32`, `Uint64`,
`Int63n`) backed by `getrandom(2)` / `crypto/rand.Reader`.

**Related**: CVE-2024-10026 and CVE-2024-10603 fixed the same class of weakness
(`math/rand` for network identifiers) in the TCP/IP stack. These 5 files were
not addressed by those fixes.

FUTURE_COPYBARA_INTEGRATE_REVIEW=#12695 from KevinZhao:fix/weak-prng-security-sensitive d6428ea
PiperOrigin-RevId: 891955457
Replace math/rand with gvisor.dev/gvisor/pkg/rand (backed by
crypto/rand or getrandom(2)) in security-sensitive code paths:

- mm/syscalls.go: Stack ASLR randomization. math/rand makes stack
  addresses more predictable than Linux's ASLR, aiding exploitation.
- systrap/stub_unsafe.go: Sentry stub code layout randomization.
  Predictable stub locations enable ROP/JOP attacks against the sentry.
- systrap/usertrap/usertrap_amd64.go: Trap table address randomization.
  Predictable trap table aids syscall dispatch hijacking.
- netlink/port/port.go: Netlink port allocation start offset.
- inet/abstract_socket_namespace.go: Unix abstract socket autobind.

math/rand is not cryptographically secure — its output is deterministic
given the internal state, which can be recovered from observed outputs.
gVisor's secure rand package uses getrandom(2)/crypto.rand.Reader.

Related: CVE-2024-10026 and CVE-2024-10603 fixed the same class of
weakness (math/rand for network identifiers) in the TCP/IP stack.
Move gvisor.dev/gvisor/pkg/rand from stdlib group to gvisor package
group, and fix alphabetical ordering within the group.
Replace math/rand with gvisor.dev/gvisor/pkg/rand (backed by
crypto/rand or getrandom(2)) in four additional locations:

- runsc/cmd/do.go: Container ID generation. Predictable IDs from
  math/rand could allow other processes to guess and race container
  names.
- runsc/metricserver/metricserver.go: Sandbox iteration order shuffle.
  Replace rand.Perm with Fisher-Yates using cryptographic PRNG.
- pkg/sentry/kernel/syslog.go: Dmesg message selection and timing.
  Eliminates math/rand from the sentry address space entirely.
- pkg/lisafs/sample_message.go: Test message randomization. Ensures
  no math/rand import remains in the lisafs package.

This is a follow-up to the previous commit that replaced math/rand in
security-sensitive paths (ASLR, stub layout, trap table, netlink port,
socket autobind). Together they eliminate math/rand from all production
code paths in gVisor.
…t order

Revert crypto PRNG changes in syslog.go (fun messages), do.go (debug
command), and metricserver.go (best-effort shuffle) as these do not
need cryptographic randomness.

Fix stub_unsafe.go: apply modulo before int cast to avoid potential
negative index from uint64-to-int conversion.
@KevinZhao KevinZhao force-pushed the fix/weak-prng-security-sensitive branch from d6428ea to 1e29f18 Compare March 31, 2026 14:38
…t order

- Revert syslog.go, do.go, metricserver.go (not security-sensitive)
- Revert lisafs/sample_message.go (test utility, not security-sensitive)
- Fix modulo-before-cast in stub_unsafe.go per reviewer feedback
- Keep only 5 files with genuine security-sensitive randomization:
  mm/syscalls.go (ASLR), systrap/stub_unsafe.go (stub ASLR),
  usertrap_amd64.go (trap table), netlink/port.go (port alloc),
  abstract_socket_namespace.go (autobind)
@KevinZhao KevinZhao force-pushed the fix/weak-prng-security-sensitive branch from 1e29f18 to 22c2e00 Compare March 31, 2026 14:54
@ayushr2
Copy link
Copy Markdown
Collaborator

ayushr2 commented Mar 31, 2026

Please squash your commits. Also this PR does not build because the BUILD files have not been updated with the new import.

copybara-service Bot pushed a commit that referenced this pull request Apr 1, 2026
Replace `math/rand` with `gvisor.dev/gvisor/pkg/rand` (backed by `crypto/rand`
or `getrandom(2)`) in 5 security-sensitive code paths that currently use the
non-cryptographic `math/rand`:

| File | Usage | Risk |
|------|-------|------|
| `mm/syscalls.go` | Stack ASLR | Stack address prediction aids ROP |
| `systrap/stub_unsafe.go` | Stub code layout | Sentry code location prediction |
| `systrap/usertrap/usertrap_amd64.go` | Trap table layout | Syscall dispatch hijacking |
| `netlink/port/port.go` | Port allocation | Port collision/hijacking |
| `inet/abstract_socket_namespace.go` | Socket autobind | Socket name prediction |

`math/rand` is not cryptographically secure — its output is deterministic given
the internal state, which can be recovered from observed outputs (e.g., by
observing one's own stack address via `/proc/self/maps` and deducing future
randomization outputs for other processes in the same sandbox).

`gvisor.dev/gvisor/pkg/rand` already provides matching API (`Uint32`, `Uint64`,
`Int63n`) backed by `getrandom(2)` / `crypto/rand.Reader`.

**Related**: CVE-2024-10026 and CVE-2024-10603 fixed the same class of weakness
(`math/rand` for network identifiers) in the TCP/IP stack. These 5 files were
not addressed by those fixes.

FUTURE_COPYBARA_INTEGRATE_REVIEW=#12695 from KevinZhao:fix/weak-prng-security-sensitive d6428ea
PiperOrigin-RevId: 891955457
copybara-service Bot pushed a commit that referenced this pull request Apr 1, 2026
Replace `math/rand` with `gvisor.dev/gvisor/pkg/rand` (backed by `crypto/rand`
or `getrandom(2)`) in 5 security-sensitive code paths that currently use the
non-cryptographic `math/rand`:

| File | Usage | Risk |
|------|-------|------|
| `mm/syscalls.go` | Stack ASLR | Stack address prediction aids ROP |
| `systrap/stub_unsafe.go` | Stub code layout | Sentry code location prediction |
| `systrap/usertrap/usertrap_amd64.go` | Trap table layout | Syscall dispatch hijacking |
| `netlink/port/port.go` | Port allocation | Port collision/hijacking |
| `inet/abstract_socket_namespace.go` | Socket autobind | Socket name prediction |

`math/rand` is not cryptographically secure — its output is deterministic given
the internal state, which can be recovered from observed outputs (e.g., by
observing one's own stack address via `/proc/self/maps` and deducing future
randomization outputs for other processes in the same sandbox).

`gvisor.dev/gvisor/pkg/rand` already provides matching API (`Uint32`, `Uint64`,
`Int63n`) backed by `getrandom(2)` / `crypto/rand.Reader`.

**Related**: CVE-2024-10026 and CVE-2024-10603 fixed the same class of weakness
(`math/rand` for network identifiers) in the TCP/IP stack. These 5 files were
not addressed by those fixes.

COPYBARA_INTEGRATE_REVIEW=#12695 from KevinZhao:fix/weak-prng-security-sensitive d6428ea
PiperOrigin-RevId: 892755849
@ayushr2
Copy link
Copy Markdown
Collaborator

ayushr2 commented Apr 1, 2026

I fixed this up and merged it in 3058187. Closing this.

@ayushr2 ayushr2 closed this Apr 1, 2026
maci0 pushed a commit to maci0/gvisor that referenced this pull request Apr 23, 2026
Replace `math/rand` with `gvisor.dev/gvisor/pkg/rand` (backed by `crypto/rand`
or `getrandom(2)`) in 5 security-sensitive code paths that currently use the
non-cryptographic `math/rand`:

| File | Usage | Risk |
|------|-------|------|
| `mm/syscalls.go` | Stack ASLR | Stack address prediction aids ROP |
| `systrap/stub_unsafe.go` | Stub code layout | Sentry code location prediction |
| `systrap/usertrap/usertrap_amd64.go` | Trap table layout | Syscall dispatch hijacking |
| `netlink/port/port.go` | Port allocation | Port collision/hijacking |
| `inet/abstract_socket_namespace.go` | Socket autobind | Socket name prediction |

`math/rand` is not cryptographically secure — its output is deterministic given
the internal state, which can be recovered from observed outputs (e.g., by
observing one's own stack address via `/proc/self/maps` and deducing future
randomization outputs for other processes in the same sandbox).

`gvisor.dev/gvisor/pkg/rand` already provides matching API (`Uint32`, `Uint64`,
`Int63n`) backed by `getrandom(2)` / `crypto/rand.Reader`.

**Related**: CVE-2024-10026 and CVE-2024-10603 fixed the same class of weakness
(`math/rand` for network identifiers) in the TCP/IP stack. These 5 files were
not addressed by those fixes.

COPYBARA_INTEGRATE_REVIEW=google#12695 from KevinZhao:fix/weak-prng-security-sensitive d6428ea
PiperOrigin-RevId: 892755849
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants