1#!/usr/bin/env python3
2"""Report numeric CEF runtime version fields plus library hash.
3
4Opens only the explicitly selected trusted libcef.so using the standard
5library ctypes module and calls the header-verified cef_version_info(int)
6entries from /usr/include/cef/include/cef_version_info.h:
7
8 0 - CEF_VERSION_MAJOR
9 1 - CEF_VERSION_MINOR
10 2 - CEF_VERSION_PATCH
11 3 - CEF_COMMIT_NUMBER
12 4 - CHROME_VERSION_MAJOR
13 5 - CHROME_VERSION_MINOR
14 6 - CHROME_VERSION_BUILD
15 7 - CHROME_VERSION_PATCH
16
17Outputs JSON to stdout with numeric fields and the library SHA-256. Never
18outputs filesystem paths. This probe is not an ABI bypass: the candidate must
19still pass its normal loader ABI/version validation.
20"""
21
22import argparse
23import ctypes
24import hashlib
25import json
26import os
27import sys
28
29
30ENTRIES = (
31 ("cef_version_major", 0),
32 ("cef_version_minor", 1),
33 ("cef_version_patch", 2),
34 ("cef_commit_number", 3),
35 ("chrome_version_major", 4),
36 ("chrome_version_minor", 5),
37 ("chrome_version_build", 6),
38 ("chrome_version_patch", 7),
39)
40
41
42def fail(message):
43 print("cef-runtime-probe: {}".format(message), file=sys.stderr)
44 raise SystemExit(2)
45
46
47def main():
48 parser = argparse.ArgumentParser(description="Probe selected libcef.so version fields.")
49 parser.add_argument("--cef-dir", required=True, help="Selected CEF runtime directory.")
50 args = parser.parse_args()
51
52 cef_dir = args.cef_dir
53 if not cef_dir or not os.path.isabs(cef_dir):
54 fail("cef dir must be an absolute path")
55 lib_name = os.path.join(cef_dir, "libcef.so")
56 try:
57 is_file = os.path.isfile(lib_name) and not os.path.islink(lib_name)
58 except OSError:
59 fail("could not stat runtime library")
60 if not is_file:
61 fail("runtime library not found")
62
63 try:
64 with open(lib_name, "rb") as candidate:
65 # Chunked streaming hash: hashlib.file_digest needs 3.11+,
66 # this stays compatible with older 3.x interpreters.
67 digest = hashlib.sha256()
68 for chunk in iter(lambda: candidate.read(65536), b""):
69 digest.update(chunk)
70 library_sha256 = digest.hexdigest()
71 except OSError:
72 fail("could not hash runtime library")
73
74 try:
75 lib = ctypes.CDLL(lib_name)
76 except OSError:
77 fail("could not open runtime library")
78 try:
79 version_info = lib.cef_version_info
80 except AttributeError:
81 fail("cef_version_info symbol is unavailable")
82 version_info.argtypes = (ctypes.c_int,)
83 version_info.restype = ctypes.c_int
84
85 result = {}
86 for field, entry in ENTRIES:
87 try:
88 value = version_info(entry)
89 except (ctypes.ArgumentError, OSError, ValueError):
90 fail("version query failed")
91 if not isinstance(value, int) or value < 0:
92 fail("version query failed")
93 result[field] = value
94 result["libcef_sha256"] = library_sha256
95 json.dump(result, sys.stdout, indent=2, sort_keys=True)
96 sys.stdout.write("\n")
97
98
99if __name__ == "__main__":
100 main()