Replace rngd with a Go version

Only supports the use cases we currently need, currently support
for using Intel hardware rng to initialise and add entropy.

Supports oneshot and service mode. Call as `rngd -1` for one shot
mode.

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
Justin Cormack 2017-07-31 19:53:32 +01:00
parent f436e66a77
commit e0bc13451f
7 changed files with 172 additions and 91 deletions

View File

@ -1,46 +1,15 @@
FROM linuxkit/alpine:9bcf61f605ef0ce36cc94d59b8eac307862de6e1 AS mirror
RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/
RUN apk add --no-cache --initdb -p /out \
tini
RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache
RUN mkdir -p /out/dev /out/proc /out/sys
FROM linuxkit/alpine:c23813875499d85163dc358fc6370c9de650df57 AS mirror
FROM linuxkit/alpine:9bcf61f605ef0ce36cc94d59b8eac307862de6e1 AS build
RUN apk add \
argp-standalone \
automake \
curl \
gcc \
linux-headers \
make \
musl-dev \
patch
RUN apk add --no-cache go gcc musl-dev linux-headers
ENV GOPATH=/go PATH=$PATH:/go/bin
COPY . /
ENV pkgname=rng-tools pkgver=5
RUN curl -fSL "http://downloads.sourceforge.net/project/gkernel/$pkgname/$pkgver/$pkgname-$pkgver.tar.gz" -o "$pkgname-$pkgver.tar.gz"
RUN sha256sum -c sha256sums
RUN zcat $pkgname-$pkgver.tar.gz | tar xf -
RUN cd $pkgname-$pkgver && for p in ../*.patch; do cat $p | patch -p1; done
RUN cd $pkgname-$pkgver && \
export LIBS="-largp" && \
LDFLAGS=-static ./configure \
--prefix=/usr \
--libexecdir=/usr/lib/rng-tools \
--sysconfdir=/etc \
--disable-silent-rules && \
make && \
make DESTDIR=/ install && \
strip /usr/sbin/rngd
COPY cmd/rngd/*.go /go/src/rngd/
RUN REQUIRE_CGO=1 go-compile.sh /go/src/rngd
FROM scratch
ENTRYPOINT []
CMD []
WORKDIR /
COPY --from=mirror /out/ /
COPY --from=build usr/sbin/rngd usr/sbin/rngd
CMD ["/sbin/tini", "/usr/sbin/rngd", "-f"]
COPY --from=mirror /go/bin/rngd /sbin/rngd
CMD ["/sbin/rngd"]
LABEL org.mobyproject.config='{"capabilities": ["CAP_SYS_ADMIN"], "oomScoreAdj": -800, "readonly": true, "net": "new", "ipc": "new"}'

View File

@ -1,4 +1,4 @@
IMAGE=rngd
NETWORK=1
DEPS=$(wildcard cmd/rngd/*.go)
include ../package.mk

66
pkg/rngd/cmd/rngd/main.go Normal file
View File

@ -0,0 +1,66 @@
package main
import (
"log"
"os"
"syscall"
)
func main() {
oneshot := len(os.Args) > 1 && os.Args[1] == "-1"
timeout := -1
if oneshot {
timeout = 0
}
supported := initRand()
if !supported {
log.Fatalf("No random source available")
}
random, err := os.Open("/dev/random")
if err != nil {
log.Fatalf("Cannot open /dev/random: %v", err)
}
defer random.Close()
fd := int(random.Fd())
epfd, err := syscall.EpollCreate1(0)
if err != nil {
log.Fatalf("epoll create error: %v", err)
}
defer syscall.Close(epfd)
var event syscall.EpollEvent
var events [1]syscall.EpollEvent
event.Events = syscall.EPOLLOUT
event.Fd = int32(fd)
if err := syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, fd, &event); err != nil {
log.Fatalf("epoll add error: %v", err)
}
count := 0
for {
// write some entropy
n, err := writeEntropy(random)
if err != nil {
log.Fatalf("write entropy: %v", err)
}
count += n
// sleep until we can write more
nevents, err := syscall.EpollWait(epfd, events[:], timeout)
if err != nil {
log.Fatalf("epoll wait error: %v", err)
}
if nevents == 1 && events[0].Events&syscall.EPOLLOUT == syscall.EPOLLOUT {
continue
}
if oneshot {
log.Printf("Wrote %d bytes of entropy, exiting as oneshot\n", count)
break
}
}
}

View File

@ -0,0 +1,84 @@
package main
// #cgo CFLAGS: -mrdrnd -mrdseed
// #include <immintrin.h>
// #include <x86intrin.h>
// #include <stdint.h>
// #include <cpuid.h>
// #include <linux/random.h>
// #include <sys/ioctl.h>
//
// int hasrdrand() {
// unsigned int eax, ebx, ecx, edx;
// __get_cpuid(1, &eax, &ebx, &ecx, &edx);
//
// return ((ecx & bit_RDRND) == bit_RDRND);
// }
//
// int hasrdseed() {
// unsigned int eax, ebx, ecx, edx;
// __get_cpuid(7, &eax, &ebx, &ecx, &edx);
//
// return ((ebx & bit_RDSEED) == bit_RDSEED);
// }
//
// int rdrand(uint64_t *val) {
// return _rdrand64_step((unsigned long long *)val);
// }
//
// int rdseed(uint64_t *val) {
// return _rdseed64_step((unsigned long long *)val);
// }
//
// int rndaddentropy = RNDADDENTROPY;
//
import "C"
import (
"errors"
"os"
"syscall"
"unsafe"
)
var hasRdrand, hasRdseed bool
type randInfo struct {
entropyCount int
size int
buf uint64
}
func initRand() bool {
hasRdrand = C.hasrdrand() == 1
hasRdseed = C.hasrdseed() == 1
return hasRdrand || hasRdseed
}
func rand() (uint64, error) {
var x C.uint64_t
// prefer rdseed as that is correct seed
if hasRdseed && C.rdseed(&x) == 1 {
return uint64(x), nil
}
// failed rdseed, rdrand better than nothing
if hasRdrand && C.rdrand(&x) == 1 {
return uint64(x), nil
}
return 0, errors.New("No randomness available")
}
func writeEntropy(random *os.File) (int, error) {
r, err := rand()
if err != nil {
// assume can fail occasionally
return 0, nil
}
const entropy = 64 // they are good random numbers, Brent
info := randInfo{entropy, 8, r}
ret, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(random.Fd()), uintptr(C.rndaddentropy), uintptr(unsafe.Pointer(&info)))
if ret == 0 {
return 8, nil
}
return 0, err
}

View File

@ -0,0 +1,13 @@
// +build !amd64
package main
import "errors"
func initRand() bool {
return false
}
func rand() (uint64, error) {
return 0, errors.New("No rng available")
}

View File

@ -1,50 +0,0 @@
--- rng-tools/rdrand_asm.S
+++ rng-tools/rdrand_asm.S
@@ -49,6 +49,7 @@
ret
ENDPROC(x86_rdrand_nlong)
+#define INIT_PIC()
#define SETPTR(var,ptr) leaq var(%rip),ptr
#define PTR0 %rdi
#define PTR1 %rsi
@@ -84,7 +85,16 @@
ret
ENDPROC(x86_rdrand_nlong)
+#if defined(__PIC__)
+#undef __i686 /* gcc builtin define gets in our way */
+#define INIT_PIC() \
+ call __i686.get_pc_thunk.bx ; \
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+#define SETPTR(var,ptr) leal (var)@GOTOFF(%ebx),ptr
+#else
+#define INIT_PIC()
#define SETPTR(var,ptr) movl $(var),ptr
+#endif
#define PTR0 %eax
#define PTR1 %edx
#define PTR2 %ecx
@@ -101,6 +111,7 @@
movl 8(%ebp), %eax
movl 12(%ebp), %edx
#endif
+ INIT_PIC()
SETPTR(aes_round_keys, PTR2)
@@ -166,6 +177,17 @@
#endif
ret
ENDPROC(x86_aes_mangle)
+
+#if defined(__i386__) && defined(__PIC__)
+ .section .gnu.linkonce.t.__i686.get_pc_thunk.bx,"ax",@progbits
+.globl __i686.get_pc_thunk.bx
+ .hidden __i686.get_pc_thunk.bx
+ .type __i686.get_pc_thunk.bx,@function
+__i686.get_pc_thunk.bx:
+ movl (%esp), %ebx
+ ret
+#endif
+

View File

@ -1 +0,0 @@
60a102b6603bbcce2da341470cad42eeaa9564a16b4490e7867026ca11a3078e rng-tools-5.tar.gz