1
1
mirror of https://github.com/henrydcase/pqc.git synced 2024-11-22 15:39:07 +00:00

Merge pull request #30 from PQClean/ds-test-namespace

Implement symbol namespace check using new Python testing framework
This commit is contained in:
Thom Wiggers 2019-02-15 09:57:24 +01:00 committed by GitHub
commit bb38e64258
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 57 additions and 70 deletions

View File

@ -8,7 +8,7 @@ matrix:
os: linux os: linux
compiler: gcc compiler: gcc
env: env:
- MAKETARGET="test-all tidy-all check-format check-metadata check-license-files" - MAKETARGET="test-all tidy-all check-format check-metadata"
addons: addons:
apt: apt:
packages: packages:
@ -50,7 +50,7 @@ matrix:
os: linux os: linux
services: docker services: docker
env: env:
- MAKETARGET="run-functest-all run-testvectors-all run-sanitizer-all run-symbol-namespace-all" - MAKETARGET="run-functest-all run-testvectors-all run-sanitizer-all"
script: script:
- docker run --rm --privileged multiarch/qemu-user-static:register --reset - docker run --rm --privileged multiarch/qemu-user-static:register --reset
- docker run --rm -v `pwd`:`pwd` -w `pwd` "pqclean/debian-unstable-ppc" /bin/bash -c "uname -a && - docker run --rm -v `pwd`:`pwd` -w `pwd` "pqclean/debian-unstable-ppc" /bin/bash -c "uname -a &&

View File

@ -121,8 +121,6 @@ help:
@echo "make run-testvectors SCHEME=scheme Run testvector checks for SCHEME" @echo "make run-testvectors SCHEME=scheme Run testvector checks for SCHEME"
@echo "make run-testvectors-all Run all testvector checks" @echo "make run-testvectors-all Run all testvector checks"
@echo "make run-sanitizer-all Run address sanitizer for all schemes" @echo "make run-sanitizer-all Run address sanitizer for all schemes"
@echo "make run-symbol-namespace SCHEME=scheme Run symbol namespace checks for SCHEME"
@echo "make run-symbol-namespace-all Run all symbol namespace checks"
@echo "make run-valgrind SCHEME=scheme Run valgrind checks for SCHEME" @echo "make run-valgrind SCHEME=scheme Run valgrind checks for SCHEME"
@echo "make run-valgrind-all Run valgrind checks all schemes" @echo "make run-valgrind-all Run valgrind checks all schemes"
@echo "make clean Clean up the bin/ folder" @echo "make clean Clean up the bin/ folder"
@ -155,22 +153,12 @@ run-valgrind-all:
run-testvectors: test/check_tvectors.py | require_scheme run-testvectors: test/check_tvectors.py | require_scheme
python3 test/check_tvectors.py $(SCHEME) || exit 1; \ python3 test/check_tvectors.py $(SCHEME) || exit 1; \
.PHONY: run-symbol-namespace
run-symbol-namespace: test/check_symbol_namespace.py | require_scheme
python3 test/check_symbol_namespace.py $(SCHEME) || exit 1; \
.PHONY: run-testvectors-all .PHONY: run-testvectors-all
run-testvectors-all: test/check_tvectors.py run-testvectors-all: test/check_tvectors.py
@for scheme in $(ALL_SCHEMES); do \ @for scheme in $(ALL_SCHEMES); do \
python3 test/check_tvectors.py $$scheme || exit 1; \ python3 test/check_tvectors.py $$scheme || exit 1; \
done done
.PHONY: run-symbol-namespace-all
run-symbol-namespace-all:
@for scheme in $(ALL_SCHEMES); do \
python3 test/check_symbol_namespace.py $$scheme || exit 1; \
done
.PHONY: run-functest-all .PHONY: run-functest-all
run-functest-all: functest-all run-functest-all: functest-all
@for functest in $$(find bin/ -maxdepth 1 -name 'functest_*' -not -type d) ; do \ @for functest in $$(find bin/ -maxdepth 1 -name 'functest_*' -not -type d) ; do \
@ -187,16 +175,8 @@ run-sanitizer-all: sanitizer-all
done done
@echo Tests completed @echo Tests completed
.PHONY: check-license-files
check-license-files:
@echo Checking that LICENSE files exist
@for scheme in $(ALL_SCHEMES); do \
echo Checking for $$scheme/clean/LICENSE;\
test -f $$scheme/clean/LICENSE || exit 1 ;\
done
.PHONY: test-all .PHONY: test-all
test-all: run-functest-all run-valgrind-all run-sanitizer-all run-testvectors-all run-symbol-namespace-all test-all: run-functest-all run-valgrind-all run-sanitizer-all run-testvectors-all
.PHONY: tidy-all .PHONY: tidy-all
tidy-all: tidy-all:

View File

@ -1,43 +0,0 @@
import subprocess
import sys
"""
For a given SCHEME, this script verifies that all exported symbols are properly
namespaced, i.e., all start with "PQCLEAN_SCHEMENAME_"
"""
if sys.platform != 'linux':
print("This test is not supported on non-Linux platforms")
exit(0)
if len(sys.argv) != 2:
print("Provide a scheme name (e.g. crypto_kem/kyber768) as argv[1]")
exit(1)
SCHEME = sys.argv[1]
SCHEMEFULL = SCHEME.replace('/', '_') # e.g. crypto_kem_kyber768
SCHEMESHORT = SCHEME.split('/')[1].upper()
namespace = "PQCLEAN_{}_".format(SCHEMESHORT).replace('-', '')
# TODO can we do this using object files instead, to preserve file origin?
sharedlib = "bin/shared_{}_clean.so".format(SCHEMEFULL)
subprocess.run(["make", sharedlib, "SCHEME={}".format(SCHEME)])
p = subprocess.run(["nm", "-D", sharedlib], stdout=subprocess.PIPE)
symbols = p.stdout.decode('utf-8').strip().split("\n")
non_namespaced = []
for symbolstr in symbols:
*_, symtype, symbol = symbolstr.split()
if symtype in 'TR':
if not symbol.startswith(namespace):
non_namespaced.append(symbol)
if non_namespaced:
print("! Not all symbols were properly namespaced.", file=sys.stderr)
print("! Missing namespace literal {}".format(namespace), file=sys.stderr)
for symbol in non_namespaced:
print("\t{}".format(symbol), file=sys.stderr)
sys.exit(1)
else:
print("Checking {} succeeded".format(SCHEME))

View File

@ -11,3 +11,4 @@ def run_subprocess(command, working_dir, expected_returncode = 0):
) )
print(result.stdout.decode('utf-8')) print(result.stdout.decode('utf-8'))
assert(result.returncode == expected_returncode) assert(result.returncode == expected_returncode)
return result.stdout.decode('utf-8')

View File

@ -10,6 +10,9 @@ class Scheme:
def path(self, base='..'): def path(self, base='..'):
return os.path.join(base, 'crypto_' + self.type, self.name) return os.path.join(base, 'crypto_' + self.type, self.name)
def namespace_prefix(self):
return 'PQCLEAN_{}_'.format(self.name.upper()).replace('-', '')
@staticmethod @staticmethod
def by_name(scheme_name): def by_name(scheme_name):
for scheme in Scheme.all_schemes(): for scheme in Scheme.all_schemes():

View File

@ -13,6 +13,10 @@ def test_compile_lib():
def check_compile_lib(scheme_name, implementation_name): def check_compile_lib(scheme_name, implementation_name):
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name) implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
helpers.run_subprocess(
['make', 'clean'],
implementation.path()
)
helpers.run_subprocess( helpers.run_subprocess(
['make'], ['make'],
implementation.path() implementation.path()

View File

@ -13,10 +13,6 @@ def test_functest():
def check_functest(scheme_name, implementation_name): def check_functest(scheme_name, implementation_name):
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name) implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
helpers.run_subprocess(
['make', 'clean', 'TYPE=' + implementation.scheme.type, 'SCHEME=' + scheme_name, 'IMPLEMENTATION=' + implementation_name],
os.path.join('..', 'test')
)
helpers.run_subprocess( helpers.run_subprocess(
['make', 'TYPE=' + implementation.scheme.type, 'SCHEME=' + scheme_name, 'IMPLEMENTATION=' + implementation_name], ['make', 'TYPE=' + implementation.scheme.type, 'SCHEME=' + scheme_name, 'IMPLEMENTATION=' + implementation_name],
os.path.join('..', 'test') os.path.join('..', 'test')

View File

@ -0,0 +1,46 @@
"""
Checks that the all exported symbols are properly namespaced, i.e., all start with "PQCLEAN_SCHEMENAME_".
"""
import os
import pqclean
import helpers
import sys
import unittest
def test_symbol_namespace():
if sys.platform not in ['linux', 'darwin']: raise unittest.SkipTest()
for scheme in pqclean.Scheme.all_schemes():
for implementation in scheme.implementations:
yield check_symbol_namespace, scheme.name, implementation.name
def check_symbol_namespace(scheme_name, implementation_name):
implementation = pqclean.Implementation.by_name(scheme_name, implementation_name)
helpers.run_subprocess(
['make'],
implementation.path()
)
out = helpers.run_subprocess(
['nm', '-g', 'lib{}_{}.a'.format(scheme_name, implementation_name)],
implementation.path()
)
lines = out.strip().split("\n")
symbols = []
for line in lines:
if ' T ' in line or ' D ' in line or ' S ' in line:
symbols.append(line)
namespace = implementation.scheme.namespace_prefix()
non_namespaced = []
for symbolstr in symbols:
*_, symtype, symbol = symbolstr.split()
if symtype in 'TR':
if not symbol.startswith(namespace) and not symbol.startswith('_' + namespace):
non_namespaced.append(symbol)
if non_namespaced:
print("Missing namespace literal {}".format(namespace))
for symbol in non_namespaced:
print("\ttype: {}, symbol: {}".format(symtype, symbol))
assert(False)