Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
crypto/rand: use getrandom system call on Linux
Adds internal/syscall package. Fixes #8520 LGTM=r, agl R=agl, rsc, r CC=golang-codereviews, iant https://golang.org/cl/123260044
- Loading branch information
Showing
4 changed files
with
105 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright 2014 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package rand | ||
|
||
import ( | ||
"internal/syscall" | ||
"sync" | ||
) | ||
|
||
func init() { | ||
altGetRandom = getRandomLinux | ||
} | ||
|
||
var ( | ||
once sync.Once | ||
useSyscall bool | ||
) | ||
|
||
func pickStrategy() { | ||
// Test whether we should use the system call or /dev/urandom. | ||
// We'll fall back to urandom if: | ||
// - the kernel is too old (before 3.17) | ||
// - the machine has no entropy available (early boot + no hardware | ||
// entropy source?) and we want to avoid blocking later. | ||
var buf [1]byte | ||
n, err := syscall.GetRandom(buf[:], syscall.GRND_NONBLOCK) | ||
useSyscall = n == 1 && err == nil | ||
} | ||
|
||
func getRandomLinux(p []byte) (ok bool) { | ||
once.Do(pickStrategy) | ||
if !useSyscall { | ||
return false | ||
} | ||
n, err := syscall.GetRandom(p, 0) | ||
return n == len(p) && err == nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright 2014 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package syscall | ||
|
||
import ( | ||
"runtime" | ||
"sync/atomic" | ||
stdsyscall "syscall" | ||
"unsafe" | ||
) | ||
|
||
var randomTrap = map[string]uintptr{ | ||
"amd64": 318, | ||
"386": 355, | ||
}[runtime.GOARCH] | ||
|
||
var randomUnsupported int32 // atomic | ||
|
||
// GetRandomFlag is a flag supported by the getrandom system call. | ||
type GetRandomFlag uintptr | ||
|
||
const ( | ||
// GRND_NONBLOCK means return EAGAIN rather than blocking. | ||
GRND_NONBLOCK GetRandomFlag = 0x0001 | ||
|
||
// GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. | ||
GRND_RANDOM GetRandomFlag = 0x0002 | ||
) | ||
|
||
// GetRandom calls the Linux getrandom system call. | ||
// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895 | ||
func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { | ||
if randomTrap == 0 { | ||
return 0, stdsyscall.ENOSYS | ||
} | ||
if len(p) == 0 { | ||
return 0, nil | ||
} | ||
if atomic.LoadInt32(&randomUnsupported) != 0 { | ||
return 0, stdsyscall.ENOSYS | ||
} | ||
r1, _, errno := stdsyscall.Syscall(randomTrap, | ||
uintptr(unsafe.Pointer(&p[0])), | ||
uintptr(len(p)), | ||
uintptr(flags)) | ||
if errno != 0 { | ||
if errno == stdsyscall.ENOSYS { | ||
atomic.StoreInt32(&randomUnsupported, 1) | ||
} | ||
return 0, errno | ||
} | ||
return int(r1), nil | ||
} |