sentry: use cryptographic PRNG for security-sensitive randomization#12695
sentry: use cryptographic PRNG for security-sensitive randomization#12695KevinZhao wants to merge 5 commits intogoogle:masterfrom
Conversation
| // 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) | ||
| } |
There was a problem hiding this comment.
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.
| } | ||
|
|
||
| c.cid = fmt.Sprintf("runsc-%06d", rand.Int31n(1000000)) | ||
| c.cid = fmt.Sprintf("runsc-%06d", rand.Int63n(1000000)) |
There was a problem hiding this comment.
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)
| // 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 { |
There was a problem hiding this comment.
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] |
There was a problem hiding this comment.
Apply modulo before casting
|
Thanks for the detailed review @EtiennePerot. Updated per your feedback:
Net diff is now 5 files, 7 insertions, 7 deletions. |
|
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? |
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.
d6428ea to
1e29f18
Compare
…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)
1e29f18 to
22c2e00
Compare
|
Please squash your commits. Also this PR does not build because the BUILD files have not been updated with the new import. |
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 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
|
I fixed this up and merged it in 3058187. Closing this. |
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
Replace
math/randwithgvisor.dev/gvisor/pkg/rand(backed bycrypto/randor
getrandom(2)) in 5 security-sensitive code paths that currently use thenon-cryptographic
math/rand:mm/syscalls.gosystrap/stub_unsafe.gosystrap/usertrap/usertrap_amd64.gonetlink/port/port.goinet/abstract_socket_namespace.gomath/randis not cryptographically secure — its output is deterministic giventhe internal state, which can be recovered from observed outputs (e.g., by
observing one's own stack address via
/proc/self/mapsand deducing futurerandomization outputs for other processes in the same sandbox).
gvisor.dev/gvisor/pkg/randalready provides matching API (Uint32,Uint64,Int63n) backed bygetrandom(2)/crypto/rand.Reader.Related: CVE-2024-10026 and CVE-2024-10603 fixed the same class of weakness
(
math/randfor network identifiers) in the TCP/IP stack. These 5 files werenot addressed by those fixes.