diff options
Diffstat (limited to 'vdso/check_vdso.py')
-rw-r--r-- | vdso/check_vdso.py | 204 |
1 files changed, 0 insertions, 204 deletions
diff --git a/vdso/check_vdso.py b/vdso/check_vdso.py deleted file mode 100644 index e41b09709..000000000 --- a/vdso/check_vdso.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2018 The gVisor Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Verify VDSO ELF does not contain any relocations and is directly mmappable. -""" - -import argparse -import logging -import re -import subprocess - -PAGE_SIZE = 4096 - - -def PageRoundDown(addr): - """Rounds down to the nearest page. - - Args: - addr: An address. - - Returns: - The address rounded down to thie nearest page. - """ - return addr & ~(PAGE_SIZE - 1) - - -def Fatal(*args, **kwargs): - """Logs a critical message and exits with code 1. - - Args: - *args: Args to pass to logging.critical. - **kwargs: Keyword args to pass to logging.critical. - """ - logging.critical(*args, **kwargs) - exit(1) - - -def CheckSegments(vdso_path): - """Verifies layout of PT_LOAD segments. - - PT_LOAD segments must be laid out such that the ELF is directly mmappable. - - Specifically, check that: - * PT_LOAD file offsets are equivalent to the memory offset from the first - segment. - * No extra zeroed space (memsz) is required. - * PT_LOAD segments are in order (required for any ELF). - * No two PT_LOAD segments share part of the same page. - - The readelf line format looks like: - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - LOAD 0x000000 0xffffffffff700000 0xffffffffff700000 0x000e68 0x000e68 R E 0x1000 - - Args: - vdso_path: Path to VDSO binary. - """ - output = subprocess.check_output(["readelf", "-lW", vdso_path]).decode() - lines = output.split("\n") - - segments = [] - for line in lines: - if not line.startswith(" LOAD"): - continue - - components = line.split() - - segments.append({ - "offset": int(components[1], 16), - "addr": int(components[2], 16), - "filesz": int(components[4], 16), - "memsz": int(components[5], 16), - }) - - if not segments: - Fatal("No PT_LOAD segments in VDSO") - - first = segments[0] - if first["offset"] != 0: - Fatal("First PT_LOAD segment has non-zero file offset: %s", first) - - for i, segment in enumerate(segments): - memoff = segment["addr"] - first["addr"] - if memoff != segment["offset"]: - Fatal("PT_LOAD segment has different memory and file offsets: %s", - segments) - - if segment["memsz"] != segment["filesz"]: - Fatal("PT_LOAD segment memsz != filesz: %s", segment) - - if i > 0: - last_end = segments[i-1]["addr"] + segments[i-1]["memsz"] - if segment["addr"] < last_end: - Fatal("PT_LOAD segments out of order") - - last_page = PageRoundDown(last_end) - start_page = PageRoundDown(segment["addr"]) - if last_page >= start_page: - Fatal("PT_LOAD segments share a page: %s and %s", segment, - segments[i - 1]) - - -# Matches the section name in readelf -SW output. -_SECTION_NAME_RE = re.compile(r"""^\s+\[\ ?\d+\]\s+ - (?P<name>\.\S+)\s+ - (?P<type>\S+)\s+ - (?P<addr>[0-9a-f]+)\s+ - (?P<off>[0-9a-f]+)\s+ - (?P<size>[0-9a-f]+)""", re.VERBOSE) - - -def CheckData(vdso_path): - """Verifies the VDSO contains no .data or .bss sections. - - The readelf line format looks like: - - There are 15 section headers, starting at offset 0x15f0: - - Section Headers: - [Nr] Name Type Address Off Size ES Flg Lk Inf Al - [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .hash HASH ffffffffff700120 000120 000040 04 A 2 0 8 - [ 2] .dynsym DYNSYM ffffffffff700160 000160 000108 18 A 3 1 8 - ... - [13] .strtab STRTAB 0000000000000000 001448 000123 00 0 0 1 - [14] .shstrtab STRTAB 0000000000000000 00156b 000083 00 0 0 1 - Key to Flags: - W (write), A (alloc), X (execute), M (merge), S (strings), I (info), - L (link order), O (extra OS processing required), G (group), T (TLS), - C (compressed), x (unknown), o (OS specific), E (exclude), - l (large), p (processor specific) - - Args: - vdso_path: Path to VDSO binary. - """ - output = subprocess.check_output(["readelf", "-SW", vdso_path]).decode() - lines = output.split("\n") - - found_text = False - for line in lines: - m = re.search(_SECTION_NAME_RE, line) - if not m: - continue - - if not line.startswith(" ["): - continue - - name = m.group("name") - size = int(m.group("size"), 16) - - if name == ".text" and size != 0: - found_text = True - - # Clang will typically omit these sections entirely; gcc will include them - # but with size 0. - if name.startswith(".data") and size != 0: - Fatal("VDSO contains non-empty .data section:\n%s" % output) - - if name.startswith(".bss") and size != 0: - Fatal("VDSO contains non-empty .bss section:\n%s" % output) - - if not found_text: - Fatal("VDSO contains no/empty .text section? Bad parsing?:\n%s" % output) - - -def CheckRelocs(vdso_path): - """Verifies that the VDSO includes no relocations. - - Args: - vdso_path: Path to VDSO binary. - """ - output = subprocess.check_output(["readelf", "-r", vdso_path]).decode() - if output.strip() != "There are no relocations in this file.": - Fatal("VDSO contains relocations: %s", output) - - -def main(): - parser = argparse.ArgumentParser(description="Verify VDSO ELF.") - parser.add_argument("--vdso", required=True, help="Path to VDSO ELF") - parser.add_argument( - "--check-data", - action="store_true", - help="Check that the ELF contains no .data or .bss sections") - args = parser.parse_args() - - CheckSegments(args.vdso) - CheckRelocs(args.vdso) - - if args.check_data: - CheckData(args.vdso) - - -if __name__ == "__main__": - main() |