Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack corruption on keypair generation #40

Closed
mratsim opened this issue Mar 11, 2020 · 2 comments
Closed

Stack corruption on keypair generation #40

mratsim opened this issue Mar 11, 2020 · 2 comments

Comments

@mratsim
Copy link
Contributor

mratsim commented Mar 11, 2020

The stack can be corrupted on key-pair generation.

For some reason this does not happen when generated in a loop, for example

import blscurve, nimcrypto

proc main() =

  for i in 0 ..< 100:
    echo "iteration ", i, ":"
    var ikm: array[32, byte]

    let written = randomBytes(ikm)
    doAssert written >= 32, "Key generation failure"

    var secKey: SecretKey
    var pubKey: PublicKey

    let ok = keygen(ikm, pubkey, seckey)

    doAssert ok
    echo "  seckey: ", seckey.toHex()
    echo "  pubkey: ", pubkey.toHex()

main()

But it happens when generated in global arrays (even on the heap) like in PR status-im/nimbus-eth2#780 unless it has to do with object variants?

import
  # Specs
  ../../beacon_chain/spec/[datatypes, crypto]

# this is being indexed inside "mock_deposits.nim" by a value up to `validatorCount`
# which is `num_validators` which is `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT`
proc genMockPrivKeys(privkeys: var array[MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, ValidatorPrivKey]) =
  for i in 0 ..< privkeys.len:
    let pair = newKeyPair()
    privkeys[i] = pair.priv

proc genMockPubKeys(
       pubkeys: var array[MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, ValidatorPubKey],
       privkeys: array[MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, ValidatorPrivKey]
     ) =
  for i in 0 ..< privkeys.len:
    pubkeys[i] = pubkey(privkeys[i])

# TODO: Ref array necessary to use a proc to avoid stack smashing in ECP_BLS381_mul (see gdb)
var MockPrivKeys*: ref array[MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, ValidatorPrivKey]
new MockPrivKeys
genMockPrivKeys(MockPrivKeys[])

var MockPubKeys*: ref array[MIN_GENESIS_ACTIVE_VALIDATOR_COUNT, ValidatorPubKey]
new MockPubKeys
genMockPubKeys(MockPubKeys[], MockPrivKeys[])

type MockKey = ValidatorPrivKey or ValidatorPubKey

template `[]`*[N: static int](a: array[N, MockKey], idx: ValidatorIndex): MockKey =
  a[idx.int]

when isMainModule:
  from blscurve import toHex

  echo "========================================"
  echo "Mock keys"
  for i in 0 ..< MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
    echo "  validator ", i
    echo "    seckey: ", MockPrivKeys[i].toHex()
    echo "    pubkey: ", MockPubKeys[i]

In Clang

This seems to manifest as a secret key that is bigger than the curve order:
image

In GDB we crash soon after

image

@mratsim
Copy link
Contributor Author

mratsim commented Mar 11, 2020

AddressSanitizer report on the openarray branch: 49bed1a

nim c --cc:clang --passC:-fsanitize=address --passL:"-fsanitize=address" --verbosity:0 --warnings:off --hints:off -r --outdir:build tests/mocking/mock_validator_keys.nim

You may need to add -lclang_rt.asan_dynamic-x86_64 to passL on WIndows

Note that seckey should be lesser than the CurveOrder so there is at least one error earlier than the stacktrace

keyGen:
  CURVE_Order: 0000000000000000000000000000000073eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
  seckey (mod): 7e65031cc69d8847cc1dab551b7b3b273167c64ccb50432062f3f06d59a8048f4d62360c7914c49a79b16f090b3f0a88
=================================================================
==185309==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff8be89487 at pc 0x55d55600c801 bp 0x7fff8be889b0 sp 0x7fff8be889a8
WRITE of size 1 at 0x7fff8be89487 thread T0
    #0 0x55d55600c800 in ECP_BLS381_mul /home/beta/Programming/Status/nim-beacon-chain/vendor/nim-blscurve/blscurve/csources/64/ecp_BLS381.c:1105:13
    #1 0x55d5560b1dab in mul__8dasrHsBDivosc1xoLwN9aQcommon /home/beta/Programming/Status/nim-beacon-chain/vendor/nim-blscurve/blscurve/common.nim:297:2
    #2 0x55d5560b1dab in privToPub__SbUVL7n9atErGXu7gDCy72Q /home/beta/Programming/Status/nim-beacon-chain/vendor/nim-blscurve/blscurve/bls_signature_scheme.nim:97:2
    #3 0x55d5560b3455 in keyGen__k9aA4fW208vT3m9bROeHOvQQ /home/beta/Programming/Status/nim-beacon-chain/vendor/nim-blscurve/blscurve/bls_signature_scheme.nim:540:17
    #4 0x55d5560b4b8f in newKeyPair__WaRCyvULs0D775n9ckxybgA /home/beta/Programming/Status/nim-beacon-chain/beacon_chain/spec/crypto.nim:206:29
    #5 0x55d5560b8cde in genMockPrivKeys__eJmkvjU6oWGYzAhJKIXKTw /home/beta/Programming/Status/nim-beacon-chain/tests/mocking/mock_validator_keys.nim:19:12
    #6 0x55d5560b8cde in NimMainModule /home/beta/Programming/Status/nim-beacon-chain/tests/mocking/mock_validator_keys.nim:32:2
    #7 0x55d5560ba90a in NimMain /home/beta/.nimble/pkgs/serialization-0.1.0/serialization/errors.nim:56:2
    #8 0x55d5560ba90a in main /home/beta/.nimble/pkgs/serialization-0.1.0/serialization/errors.nim:63:2
    #9 0x7f469be4a022 in __libc_start_main (/usr/lib/libc.so.6+0x27022)
    #10 0x55d555f1618d in _start (/home/beta/Programming/Status/nim-beacon-chain/build/mock_validator_keys+0x2c18d)

Address 0x7fff8be89487 is located in stack of thread T0 at offset 2759 in frame
    #0 0x55d55600c12f in ECP_BLS381_mul /home/beta/Programming/Status/nim-beacon-chain/vendor/nim-blscurve/blscurve/csources/64/ecp_BLS381.c:1022

  This frame has 7 object(s):
    [32, 224) 'NQ.i' (line 985)
    [288, 344) 'mt' (line 1059)
    [384, 440) 't' (line 1059)
    [480, 672) 'Q' (line 1060)
    [736, 2272) 'W' (line 1060)
    [2400, 2592) 'C' (line 1060)
    [2656, 2759) 'w' (line 1061) <== Memory access at offset 2759 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/beta/Programming/Status/nim-beacon-chain/vendor/nim-blscurve/blscurve/csources/64/ecp_BLS381.c:1105:13 in ECP_BLS381_mul
Shadow bytes around the buggy address:
  0x1000717c9240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000717c9250: 00 00 00 00 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2 f2
  0x1000717c9260: f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000717c9270: 00 00 00 00 00 00 00 00 00 00 00 00 f2 f2 f2 f2
  0x1000717c9280: f2 f2 f2 f2 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1000717c9290:[07]f3 f3 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00
  0x1000717c92a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1000717c92b0: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 f8 f8 f8 f8
  0x1000717c92c0: f8 f2 f2 f2 f2 f2 00 00 00 00 00 f2 f2 f2 f2 f2
  0x1000717c92d0: 00 00 00 00 00 f2 f2 f2 f2 f2 f8 f8 f8 f8 f8 f8
  0x1000717c92e0: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==185309==ABORTING

The incriminated w on line 1061:

#else
/* fixed size windows */
int i,nb,s,ns;
BIG_384_58 mt,t;
ECP_BLS381 Q,W[8],C;
sign8 w[1+(NLEN_384_58*BASEBITS_384_58+3)/4];

@mratsim
Copy link
Contributor Author

mratsim commented Mar 11, 2020

For some reason Milagro cannot take the modulo of this

import blscurve/[milagro, common]

proc main() =

  var okm: BIG_384
  doAssert okm.fromHex"7e65031cc69d8847cc1dab551b7b3b273167c64ccb50432062f3f06d59a8048f4d62360c7914c49a79b16f090b3f0a88"

  debugEcho "CurveOrder: ", CURVE_Order.toHex()

  var seckey = okm
  BIG_384_mod(okm, CURVE_Order)

  echo "seckey: ", seckey

main()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant