1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
|
"""
Calculate symbol_versions for a policy in policy.json by collection
defined version (.gnu.version_d) from libraries in lib_whitelist.
This should be run inside a manylinux Docker container.
"""
import argparse
import json
import os
import platform
from elftools.elf.elffile import ELFFile
if platform.architecture()[0] == "64bit":
LIBRARY_PATHS = ["/lib64", "/usr/lib64"]
else:
LIBRARY_PATHS = ["/lib", "/usr/lib"]
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("policy", help="The policy name")
parser.add_argument("policyjson", help="The policy.json file.")
def load_policies(path):
with open(path) as f:
return json.load(f)
def choose_policy(name, policies):
try:
return next(policy for policy in policies if policy["name"] == name)
except StopIteration:
raise RuntimeError(f"Unknown policy {name}")
def find_library(library):
for p in LIBRARY_PATHS:
path = os.path.join(p, library)
if os.path.exists(path):
return path
else:
raise RuntimeError(f"Unknown library {library}")
def versionify(version_string):
try:
result = [int(n) for n in version_string.split(".")]
assert len(result) <= 3
except ValueError:
result = [999999, 999999, 999999, version_string]
return result
def calculate_symbol_versions(libraries, symbol_versions, arch):
calculated_symbol_versions = {k: set() for k in symbol_versions}
prefixes = ["/lib", "/usr/lib"]
if arch == "64bit":
prefixes = [p + "64" for p in prefixes]
for library in libraries:
library_path = find_library(library)
with open(library_path, "rb") as f:
e = ELFFile(f)
section = e.get_section_by_name(".gnu.version_d")
if section:
for _, verdef_iter in section.iter_versions():
for vernaux in verdef_iter:
for symbol_name in symbol_versions:
try:
name, version = vernaux.name.split("_", 1)
except ValueError:
pass
if (
name in calculated_symbol_versions
and version != "PRIVATE"
):
calculated_symbol_versions[name].add(version)
return {k: sorted(v, key=versionify) for k, v in calculated_symbol_versions.items()}
def main():
args = parser.parse_args()
policies = load_policies(args.policyjson)
policy = choose_policy(args.policy, policies)
arch, _ = platform.architecture()
print(
json.dumps(
calculate_symbol_versions(
policy["lib_whitelist"],
policy["symbol_versions"],
arch,
)
)
)
main()
|