make system random work in VM (#17059)

* make system random work in VM
This commit is contained in:
flywind
2021-02-17 04:52:46 -06:00
committed by GitHub
parent f32ffb6ed8
commit 4f118721be
5 changed files with 90 additions and 19 deletions

View File

@@ -28,6 +28,10 @@ proc toLit*[T](a: T): PNode =
elif T is tuple:
result = newTree(nkTupleConstr)
for ai in fields(a): result.add toLit(ai)
elif T is seq:
result = newNode(nkBracket)
for ai in a:
result.add toLit(ai)
elif T is object:
result = newTree(nkObjConstr)
result.add(newNode(nkEmpty))

View File

@@ -56,3 +56,10 @@ proc getNode*(a: VmArgs; i: Natural): PNode =
doAssert i < a.rc-1
doAssert a.slots[i+a.rb+1].kind == rkNode
result = a.slots[i+a.rb+1].node
proc getNodeAddr*(a: VmArgs; i: Natural): PNode =
doAssert i < a.rc-1
doAssert a.slots[i+a.rb+1].kind == rkNodeAddr
let nodeAddr = a.slots[i+a.rb+1].nodeAddr
doAssert nodeAddr != nil
result = nodeAddr[]

View File

@@ -9,24 +9,28 @@
# Unfortunately this cannot be a module yet:
#import vmdeps, vm
from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
floor, ceil, `mod`
when declared(math.copySign):
from math import copySign
from std/math import copySign
when declared(math.signbit):
from math import signbit
from std/math import signbit
from std/os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir,
getAppFilename, raiseOSError, osLastError
from std/md5 import getMD5
from std/times import cpuTime
from std/hashes import hash
from std/osproc import nil
from std/sysrand import urandom
from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename
from md5 import getMD5
from sighashes import symBodyDigest
from times import cpuTime
from hashes import hash
from osproc import nil
# There are some useful procs in vmconv.
import vmconv
template mathop(op) {.dirty.} =
@@ -304,3 +308,35 @@ proc registerAdditionalOps*(c: PCtx) =
let fn = getNode(a, 0)
setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or
(fn.kind == nkSym and fn.sym.kind == skFunc))
if vmopsDanger in c.config.features:
proc urandomImpl(a: VmArgs) =
doAssert a.numArgs == 1
let kind = a.slots[a.rb+1].kind
case kind
of rkInt:
setResult(a, urandom(a.getInt(0)).toLit)
of rkNode, rkNodeAddr:
let n =
if kind == rkNode:
a.getNode(0)
else:
a.getNodeAddr(0)
let length = n.len
## TODO refactor using vmconv.fromLit
var res = newSeq[uint8](length)
for i in 0 ..< length:
res[i] = byte(n[i].intVal)
let isSuccess = urandom(res)
for i in 0 ..< length:
n[i].intVal = BiggestInt(res[i])
setResult(a, isSuccess)
else:
doAssert false, $kind
registerCallback c, "stdlib.sysrand.urandom", urandomImpl

View File

@@ -158,7 +158,8 @@ elif defined(windows):
result = randomBytes(addr dest[0], size)
elif defined(linux):
let SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
# TODO using let, pending bootstrap >= 1.4.0
var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
const syscallHeader = """#include <unistd.h>
#include <sys/syscall.h>"""
@@ -209,7 +210,7 @@ elif defined(freebsd):
# errno is set to indicate the error.
proc getRandomImpl(p: pointer, size: int): int {.inline.} =
result = getrandom(p, csize_t(batchSize), 0)
result = getrandom(p, csize_t(size), 0)
elif defined(ios):
{.passL: "-framework Security".}
@@ -284,7 +285,7 @@ proc urandomInternalImpl(dest: var openArray[byte]): int {.inline.} =
proc urandom*(dest: var openArray[byte]): bool =
## Fills `dest` with random bytes suitable for cryptographic use.
## If succeed, returns `true`.
## If the call succeeds, returns `true`.
##
## If `dest` is empty, `urandom` immediately returns success,
## without calling underlying operating system api.
@@ -305,4 +306,4 @@ proc urandom*(size: Natural): seq[byte] {.inline.} =
when defined(js): discard urandomInternalImpl(result)
else:
if not urandom(result):
raiseOsError(osLastError())
raiseOSError(osLastError())

View File

@@ -1,13 +1,36 @@
discard """
targets: "c cpp js"
matrix: "--experimental:vmopsDanger"
"""
import std/sysrand
doAssert urandom(0).len == 0
doAssert urandom(10).len == 10
doAssert urandom(20).len == 20
doAssert urandom(120).len == 120
doAssert urandom(113).len == 113
doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice
template main() =
block:
var x = array[5, byte].default
doAssert urandom(x)
block:
var x = newSeq[byte](5)
doAssert urandom(x)
block:
var x = @[byte(0), 0, 0, 0, 0]
doAssert urandom(x)
block:
var x = @[byte(1), 2, 3, 4, 5]
doAssert urandom(x)
block:
doAssert urandom(0).len == 0
doAssert urandom(10).len == 10
doAssert urandom(20).len == 20
doAssert urandom(120).len == 120
doAssert urandom(113).len == 113
doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice
static: main()
main()