]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rand: use the new getrandom syscall on FreeBSD
authorDavid Carlier <devnexen@gmail.com>
Tue, 21 Aug 2018 07:54:04 +0000 (07:54 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 22 Aug 2018 01:49:02 +0000 (01:49 +0000)
Since the 12.x branch, the getrandom syscall had been introduced
with similar interface as Linux's and consistent syscall id
across architectures.

Change-Id: I63d6b45dbe9e29f07f1b5b6c2ec8be4fa624b9ee
GitHub-Last-Rev: 6fb76e6522ef5ccb96d02445ffa39796dae89016
GitHub-Pull-Request: golang/go#25976
Reviewed-on: https://go-review.googlesource.com/120055
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/crypto/rand/rand.go
src/crypto/rand/rand_batched.go [new file with mode: 0644]
src/crypto/rand/rand_batched_test.go [moved from src/crypto/rand/rand_linux_test.go with 97% similarity]
src/crypto/rand/rand_freebsd.go [new file with mode: 0644]
src/crypto/rand/rand_linux.go
src/internal/syscall/unix/getrandom_freebsd.go [new file with mode: 0644]
src/internal/syscall/unix/getrandom_linux_generic.go

index b8df8a371170519e6899efc8ff224127ffb8b239..952d20aa16d7cdaac98df45ab0f95c1012aaf917 100644 (file)
@@ -11,7 +11,7 @@ import "io"
 // Reader is a global, shared instance of a cryptographically
 // secure random number generator.
 //
-// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise.
+// On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise.
 // On OpenBSD, Reader uses getentropy(2).
 // On other Unix-like systems, Reader reads from /dev/urandom.
 // On Windows systems, Reader uses the CryptGenRandom API.
diff --git a/src/crypto/rand/rand_batched.go b/src/crypto/rand/rand_batched.go
new file mode 100644 (file)
index 0000000..60267fd
--- /dev/null
@@ -0,0 +1,42 @@
+// 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.
+
+// +build linux freebsd
+
+package rand
+
+import (
+       "internal/syscall/unix"
+)
+
+// maxGetRandomRead is platform dependent.
+func init() {
+       altGetRandom = batched(getRandomBatch, maxGetRandomRead)
+}
+
+// batched returns a function that calls f to populate a []byte by chunking it
+// into subslices of, at most, readMax bytes.
+func batched(f func([]byte) bool, readMax int) func([]byte) bool {
+       return func(buf []byte) bool {
+               for len(buf) > readMax {
+                       if !f(buf[:readMax]) {
+                               return false
+                       }
+                       buf = buf[readMax:]
+               }
+               return len(buf) == 0 || f(buf)
+       }
+}
+
+// If the kernel is too old to support the getrandom syscall(),
+// unix.GetRandom will immediately return ENOSYS and we will then fall back to
+// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
+// result so we only suffer the syscall overhead once in this case.
+// If the kernel supports the getrandom() syscall, unix.GetRandom will block
+// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
+// In this case, unix.GetRandom will not return an error.
+func getRandomBatch(p []byte) (ok bool) {
+       n, err := unix.GetRandom(p, 0)
+       return n == len(p) && err == nil
+}
similarity index 97%
rename from src/crypto/rand/rand_linux_test.go
rename to src/crypto/rand/rand_batched_test.go
index 77b7b6ebd7a7b2e6eb434d94367724360f9274c3..837db83f770844ef92d4b644fed2a491feed267f 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build linux freebsd
+
 package rand
 
 import (
diff --git a/src/crypto/rand/rand_freebsd.go b/src/crypto/rand/rand_freebsd.go
new file mode 100644 (file)
index 0000000..b4d6653
--- /dev/null
@@ -0,0 +1,9 @@
+// Copyright 2018 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
+
+// maxGetRandomRead is the maximum number of bytes to ask for in one call to the
+// getrandom() syscall. In FreeBSD at most 256 bytes will be returned per call.
+const maxGetRandomRead = (1 << 8)
index dbd038cc582413e3c80618eaaf229e1631e30734..26b93c54d286b94aaae92c64d5008a40c18cec31 100644 (file)
@@ -4,14 +4,6 @@
 
 package rand
 
-import (
-       "internal/syscall/unix"
-)
-
-func init() {
-       altGetRandom = batched(getRandomLinux, maxGetRandomRead)
-}
-
 // maxGetRandomRead is the maximum number of bytes to ask for in one call to the
 // getrandom() syscall. In linux at most 2^25-1 bytes will be returned per call.
 // From the manpage
@@ -20,29 +12,3 @@ func init() {
 //        is returned by a single call to getrandom() on systems where int
 //        has a size of 32 bits.
 const maxGetRandomRead = (1 << 25) - 1
-
-// batched returns a function that calls f to populate a []byte by chunking it
-// into subslices of, at most, readMax bytes.
-func batched(f func([]byte) bool, readMax int) func([]byte) bool {
-       return func(buf []byte) bool {
-               for len(buf) > readMax {
-                       if !f(buf[:readMax]) {
-                               return false
-                       }
-                       buf = buf[readMax:]
-               }
-               return len(buf) == 0 || f(buf)
-       }
-}
-
-// If the kernel is too old (before 3.17) to support the getrandom syscall(),
-// unix.GetRandom will immediately return ENOSYS and we will then fall back to
-// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
-// result so we only suffer the syscall overhead once in this case.
-// If the kernel supports the getrandom() syscall, unix.GetRandom will block
-// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
-// In this case, unix.GetRandom will not return an error.
-func getRandomLinux(p []byte) (ok bool) {
-       n, err := unix.GetRandom(p, 0)
-       return n == len(p) && err == nil
-}
diff --git a/src/internal/syscall/unix/getrandom_freebsd.go b/src/internal/syscall/unix/getrandom_freebsd.go
new file mode 100644 (file)
index 0000000..fc241f2
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright 2018 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 unix
+
+import (
+       "sync/atomic"
+       "syscall"
+       "unsafe"
+)
+
+var randomUnsupported int32 // atomic
+
+// FreeBSD getrandom system call number.
+const randomTrap uintptr = 563
+
+// 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 is only set for portability purpose, no-op on FreeBSD.
+       GRND_RANDOM GetRandomFlag = 0x0002
+)
+
+// GetRandom calls the FreeBSD getrandom system call.
+func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
+       if randomTrap == 0 {
+               return 0, syscall.ENOSYS
+       }
+       if len(p) == 0 {
+               return 0, nil
+       }
+       if atomic.LoadInt32(&randomUnsupported) != 0 {
+               return 0, syscall.ENOSYS
+       }
+       r1, _, errno := syscall.Syscall(randomTrap,
+               uintptr(unsafe.Pointer(&p[0])),
+               uintptr(len(p)),
+               uintptr(flags))
+       if errno != 0 {
+               if errno == syscall.ENOSYS {
+                       atomic.StoreInt32(&randomUnsupported, 1)
+               }
+               return 0, errno
+       }
+       return int(r1), nil
+}
index 8425800b6da8417cb53763f32219e701888703f6..f8490ce97857c7ff450c0c4b585ab5ce0242170f 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build arm64
+// +build linux,arm64
 
 package unix