Merge "Fix freopen() where the path is null."
diff --git a/libc/Android.bp b/libc/Android.bp
index 1bced2e..6ba60ca 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1579,6 +1579,7 @@
"bionic/NetdClient.cpp",
"arch-common/bionic/crtend_so.S",
],
+ bazel_module: { bp2build_available: true },
}
filegroup {
@@ -1589,6 +1590,7 @@
"bionic/malloc_common.cpp",
"bionic/malloc_limit.cpp",
],
+ bazel_module: { bp2build_available: true },
}
filegroup {
@@ -1597,6 +1599,7 @@
"arch-arm/bionic/exidx_dynamic.c",
"arch-arm/bionic/atexit_legacy.c",
],
+ bazel_module: { bp2build_available: true },
}
// ========================================================
@@ -1754,6 +1757,7 @@
srcs: ["libc.map.txt"],
tool_files: [":bionic-generate-version-script"],
cmd: "$(location :bionic-generate-version-script) arm $(in) $(out)",
+ bazel_module: { bp2build_available: true },
}
genrule {
@@ -1762,6 +1766,7 @@
srcs: ["libc.map.txt"],
tool_files: [":bionic-generate-version-script"],
cmd: "$(location :bionic-generate-version-script) arm64 $(in) $(out)",
+ bazel_module: { bp2build_available: true },
}
genrule {
@@ -1770,6 +1775,7 @@
srcs: ["libc.map.txt"],
tool_files: [":bionic-generate-version-script"],
cmd: "$(location :bionic-generate-version-script) x86 $(in) $(out)",
+ bazel_module: { bp2build_available: true },
}
genrule {
@@ -1778,6 +1784,7 @@
srcs: ["libc.map.txt"],
tool_files: [":bionic-generate-version-script"],
cmd: "$(location :bionic-generate-version-script) x86_64 $(in) $(out)",
+ bazel_module: { bp2build_available: true },
}
// Headers that only other parts of the platform can include.
@@ -2356,53 +2363,11 @@
],
}
-// Generate the C++ policy sources for app and system seccomp-bpf filters.
-python_binary_host {
- name: "genseccomp",
- main: "tools/genseccomp.py",
-
- srcs: [
- "tools/genseccomp.py",
- "tools/gensyscalls.py",
- ],
-
- data: [
- "kernel/uapi/**/*.h",
- ],
-
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
+filegroup {
+ name: "all_kernel_uapi_headers",
+ srcs: ["kernel/uapi/**/*.h"],
}
-python_binary_host {
- name: "genfunctosyscallnrs",
- main: "tools/genfunctosyscallnrs.py",
-
- srcs: [
- "tools/genseccomp.py",
- "tools/genfunctosyscallnrs.py",
- "tools/gensyscalls.py",
- ],
-
- data: [
- "kernel/uapi/**/*.h",
- ],
-
- version: {
- py2: {
- enabled: true,
- },
- py3: {
- enabled: false,
- },
- },
-}
cc_genrule {
name: "func_to_syscall_nrs",
diff --git a/libc/arch-arm/generic/bionic/strlen.c b/libc/arch-arm/generic/bionic/strlen.c
index 43d9e51..a6fde8b 100644
--- a/libc/arch-arm/generic/bionic/strlen.c
+++ b/libc/arch-arm/generic/bionic/strlen.c
@@ -116,8 +116,8 @@
"beq 2f \n"
"add %[l], %[l], #1 \n"
"tst %[v], #0xFF0000 \n"
- "it ne \n"
- "addne %[l], %[l], #1 \n"
+ "beq 2f \n"
+ "add %[l], %[l], #1 \n"
"2: \n"
: [l]"=&r"(l), [v]"=&r"(v), [t]"=&r"(t), [s]"=&r"(u.b)
: "%[l]"(l), "%[s]"(u.b), [mask]"r"(0x80808080UL)
diff --git a/libc/tools/Android.bp b/libc/tools/Android.bp
index 13179a0..bf515ca 100644
--- a/libc/tools/Android.bp
+++ b/libc/tools/Android.bp
@@ -2,3 +2,33 @@
name: "bionic-gensyscalls",
srcs: ["gensyscalls.py"]
}
+
+// Generate the C++ policy sources for app and system seccomp-bpf filters.
+python_binary_host {
+ name: "genseccomp",
+ main: "genseccomp.py",
+
+ srcs: [
+ "genseccomp.py",
+ "gensyscalls.py",
+ ],
+
+ data: [
+ ":all_kernel_uapi_headers",
+ ],
+}
+
+python_binary_host {
+ name: "genfunctosyscallnrs",
+ main: "genfunctosyscallnrs.py",
+
+ srcs: [
+ "genseccomp.py",
+ "genfunctosyscallnrs.py",
+ "gensyscalls.py",
+ ],
+
+ data: [
+ ":all_kernel_uapi_headers",
+ ],
+}
diff --git a/libc/tools/generate-NOTICE.py b/libc/tools/generate_notice.py
similarity index 60%
rename from libc/tools/generate-NOTICE.py
rename to libc/tools/generate_notice.py
index b6deb9c..e0e6b32 100755
--- a/libc/tools/generate-NOTICE.py
+++ b/libc/tools/generate_notice.py
@@ -1,28 +1,29 @@
#!/usr/bin/env python
-# Run with directory arguments from any directory, with no special setup required.
+# Run with directory arguments from any directory, with no special setup
+# required.
-import ftplib
-import hashlib
import os
+from pathlib import Path
import re
-import shutil
-import string
-import subprocess
import sys
-import tarfile
-import tempfile
+from typing import Sequence
VERBOSE = False
+copyrights = set()
+
+
def warn(s):
sys.stderr.write("warning: %s\n" % s)
+
def warn_verbose(s):
if VERBOSE:
warn(s)
-def is_interesting(path):
- path = path.lower()
+
+def is_interesting(path_str: str) -> bool:
+ path = Path(path_str.lower())
uninteresting_extensions = [
".bp",
".map",
@@ -33,12 +34,13 @@
".swp",
".txt",
]
- if os.path.splitext(path)[1] in uninteresting_extensions:
+ if path.suffix in uninteresting_extensions:
return False
- if path.endswith("/notice") or path.endswith("/readme") or path.endswith("/pylintrc"):
+ if path.name in {"notice", "readme", "pylintrc"}:
return False
return True
+
def is_auto_generated(content):
if "Generated by gensyscalls.py" in content or "generated by genserv.py" in content:
return True
@@ -46,14 +48,40 @@
return True
return False
-copyrights = set()
-def extract_copyright_at(lines, i):
- hash = lines[i].startswith("#")
+def is_copyright_end(line: str, first_line_was_hash: bool) -> bool:
+ endings = [
+ " $FreeBSD: ",
+ "$Citrus$",
+ "$FreeBSD$",
+ "*/",
+ "From: @(#)",
+ # OpenBSD likes to say where stuff originally came from:
+ "Original version ID:",
+ "\t$Citrus: ",
+ "\t$NetBSD: ",
+ "\t$OpenBSD: ",
+ "\t@(#)",
+ "\tcitrus Id: ",
+ "\tfrom: @(#)",
+ "from OpenBSD:",
+ ]
+ if first_line_was_hash and not line:
+ return True
+
+ for ending in endings:
+ if ending in line:
+ return True
+
+ return False
+
+
+def extract_copyright_at(lines: Sequence[str], i: int) -> int:
+ first_line_was_hash = lines[i].startswith("#")
# Do we need to back up to find the start of the copyright header?
start = i
- if not hash:
+ if not first_line_was_hash:
while start > 0:
if "/*" in lines[start - 1]:
break
@@ -62,20 +90,7 @@
# Read comment lines until we hit something that terminates a
# copyright header.
while i < len(lines):
- if "*/" in lines[i]:
- break
- if hash and len(lines[i]) == 0:
- break
- if "\t@(#)" in lines[i] or "\tfrom: @(#)" in lines[i] or "From: @(#)" in lines[i] or "from OpenBSD:" in lines[i]:
- break
- if "\tcitrus Id: " in lines[i]:
- break
- if "\t$Citrus: " in lines[i] or "\t$OpenBSD: " in lines[i] or " $FreeBSD: " in lines[i] or "\t$NetBSD: " in lines[i]:
- break
- if "$FreeBSD$" in lines[i] or "$Citrus$" in lines[i]:
- break
- # OpenBSD likes to say where stuff originally came from:
- if "Original version ID:" in lines[i]:
+ if is_copyright_end(lines[i], first_line_was_hash):
break
i += 1
@@ -83,7 +98,10 @@
# Trim trailing cruft.
while end > 0:
- if lines[end - 1] != " *" and lines[end - 1] != " * ====================================================":
+ line = lines[end - 1]
+ if line not in {
+ " *", " * ===================================================="
+ }:
break
end -= 1
@@ -92,7 +110,7 @@
for line in lines[start:end]:
line = line.replace("\t", " ")
line = line.replace("/* ", "")
- line = re.sub("^ \* ", "", line)
+ line = re.sub(r"^ \* ", "", line)
line = line.replace("** ", "")
line = line.replace("# ", "")
if "SPDX-License-Identifier:" in line:
@@ -102,7 +120,7 @@
line = line.replace("--Copyright--", "")
line = line.rstrip()
# These come last and take care of "blank" comment lines.
- if line == "#" or line == " *" or line == "**" or line == "-":
+ if line in {"#", " *", "**", "-"}:
line = ""
clean_lines.append(line)
@@ -112,19 +130,18 @@
while clean_lines[len(clean_lines) - 1] == "":
clean_lines = clean_lines[0:(len(clean_lines) - 1)]
- copyright = "\n".join(clean_lines)
- copyrights.add(copyright)
+ copyrights.add("\n".join(clean_lines))
return i
-def do_file(path):
- with open(path, "r") as the_file:
- try:
- content = open(path, "r").read().decode("utf-8")
- except UnicodeDecodeError:
- warn("bad UTF-8 in %s" % path)
- content = open(path, "r").read().decode("iso-8859-1")
+def do_file(path: str) -> None:
+ raw = Path(path).read_bytes()
+ try:
+ content = raw.decode("utf-8")
+ except UnicodeDecodeError:
+ warn("bad UTF-8 in %s" % path)
+ content = raw.decode("iso-8859-1")
lines = content.split("\n")
@@ -140,10 +157,12 @@
if "public domain" in content.lower():
warn_verbose("ignoring public domain file %s" % path)
return
- warn('no copyright notice found in "%s" (%d lines)' % (path, len(lines)))
+ warn('no copyright notice found in "%s" (%d lines)' %
+ (path, len(lines)))
return
- # Manually iterate because extract_copyright_at tells us how many lines to skip.
+ # Manually iterate because extract_copyright_at tells us how many lines to
+ # skip.
i = 0
while i < len(lines):
if "Copyright" in lines[i] and not "@(#) Copyright" in lines[i]:
@@ -152,7 +171,7 @@
i += 1
-def do_dir(path):
+def do_dir(arg):
for directory, sub_directories, filenames in os.walk(arg):
if ".git" in sub_directories:
sub_directories.remove(".git")
@@ -164,20 +183,23 @@
do_file(path)
-args = sys.argv[1:]
-if len(args) == 0:
- args = [ "." ]
+def main() -> None:
+ args = sys.argv[1:]
+ if len(args) == 0:
+ args = ["."]
-for arg in args:
- if os.path.isdir(arg):
- do_dir(arg)
- else:
- do_file(arg)
+ for arg in args:
+ if os.path.isdir(arg):
+ do_dir(arg)
+ else:
+ do_file(arg)
-for copyright in sorted(copyrights):
- print copyright.encode("utf-8")
- print
- print "-------------------------------------------------------------------"
- print
+ for notice in sorted(copyrights):
+ print(notice)
+ print()
+ print("-" * 67)
+ print()
-sys.exit(0)
+
+if __name__ == "__main__":
+ main()
diff --git a/libc/tools/genfunctosyscallnrs.py b/libc/tools/genfunctosyscallnrs.py
index ecfc8ab..26642f9 100755
--- a/libc/tools/genfunctosyscallnrs.py
+++ b/libc/tools/genfunctosyscallnrs.py
@@ -1,60 +1,71 @@
#!/usr/bin/env python
import argparse
-import collections
import logging
import os
import re
-import subprocess
-import textwrap
from gensyscalls import SupportedArchitectures, SysCallsTxtParser
from genseccomp import parse_syscall_NRs
-def load_syscall_names_from_file(file_path, architecture):
- parser = SysCallsTxtParser()
- parser.parse_open_file(open(file_path))
- arch_map = {}
- for syscall in parser.syscalls:
- if syscall.get(architecture):
- arch_map[syscall["func"]] = syscall["name"];
- return arch_map
+def load_syscall_names_from_file(file_path, architecture):
+ parser = SysCallsTxtParser()
+ parser.parse_open_file(open(file_path))
+ arch_map = {}
+ for syscall in parser.syscalls:
+ if syscall.get(architecture):
+ arch_map[syscall["func"]] = syscall["name"]
+
+ return arch_map
+
def gen_syscall_nrs(out_file, base_syscall_file, syscall_NRs):
- for arch in SupportedArchitectures:
- base_names = load_syscall_names_from_file(base_syscall_file, arch)
+ for arch in SupportedArchitectures:
+ base_names = load_syscall_names_from_file(base_syscall_file, arch)
- for func,syscall in base_names.iteritems():
- out_file.write("#define __" + arch + "_" + func + " " + str(syscall_NRs[arch][syscall]) + ";\n")
+ for func, syscall in base_names.items():
+ out_file.write("#define __" + arch + "_" + func + " " +
+ str(syscall_NRs[arch][syscall]) + ";\n")
+
def main():
- parser = argparse.ArgumentParser(
- description="Generates a mapping of bionic functions to system call numbers per architecture.")
- parser.add_argument("--verbose", "-v", help="Enables verbose logging.")
- parser.add_argument("--out-dir",
- help="The output directory for the output files")
- parser.add_argument("base_file", metavar="base-file", type=str,
- help="The path of the base syscall list (SYSCALLS.TXT).")
- parser.add_argument("files", metavar="FILE", type=str, nargs="+",
- help=("A syscall name-number mapping file for an architecture.\n"))
- args = parser.parse_args()
+ parser = argparse.ArgumentParser(
+ description=
+ "Generates a mapping of bionic functions to system call numbers per architecture."
+ )
+ parser.add_argument("--verbose", "-v", help="Enables verbose logging.")
+ parser.add_argument("--out-dir",
+ help="The output directory for the output files")
+ parser.add_argument(
+ "base_file",
+ metavar="base-file",
+ type=str,
+ help="The path of the base syscall list (SYSCALLS.TXT).")
+ parser.add_argument(
+ "files",
+ metavar="FILE",
+ type=str,
+ nargs="+",
+ help=("A syscall name-number mapping file for an architecture.\n"))
+ args = parser.parse_args()
- if args.verbose:
- logging.basicConfig(level=logging.DEBUG)
- else:
- logging.basicConfig(level=logging.INFO)
+ if args.verbose:
+ logging.basicConfig(level=logging.DEBUG)
+ else:
+ logging.basicConfig(level=logging.INFO)
- syscall_files = []
- syscall_NRs = {}
- for filename in args.files:
- m = re.search(r"libseccomp_gen_syscall_nrs_([^/]+)", filename)
- syscall_NRs[m.group(1)] = parse_syscall_NRs(filename)
+ syscall_NRs = {}
+ for filename in args.files:
+ m = re.search(r"libseccomp_gen_syscall_nrs_([^/]+)", filename)
+ syscall_NRs[m.group(1)] = parse_syscall_NRs(filename)
- output_path = os.path.join(args.out_dir, "func_to_syscall_nrs.h")
- with open(output_path, "w") as output_file:
- gen_syscall_nrs(out_file=output_file,
- syscall_NRs=syscall_NRs, base_syscall_file=args.base_file)
+ output_path = os.path.join(args.out_dir, "func_to_syscall_nrs.h")
+ with open(output_path, "w") as output_file:
+ gen_syscall_nrs(out_file=output_file,
+ syscall_NRs=syscall_NRs,
+ base_syscall_file=args.base_file)
+
if __name__ == "__main__":
- main()
+ main()
diff --git a/libc/tools/genseccomp.py b/libc/tools/genseccomp.py
index 89eeb44..a78f6c1 100755
--- a/libc/tools/genseccomp.py
+++ b/libc/tools/genseccomp.py
@@ -1,11 +1,10 @@
#!/usr/bin/env python
import argparse
-import collections
import logging
+import operator
import os
import re
-import subprocess
import textwrap
from gensyscalls import SupportedArchitectures, SysCallsTxtParser
@@ -16,7 +15,7 @@
BPF_ALLOW = "BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW)"
-class SyscallRange(object):
+class SyscallRange:
def __init__(self, name, value):
self.names = [name]
self.begin = value
@@ -35,23 +34,23 @@
def load_syscall_names_from_file(file_path, architecture):
parser = SysCallsTxtParser()
parser.parse_open_file(open(file_path))
- return set([x["name"] for x in parser.syscalls if x.get(architecture)])
+ return {x["name"] for x in parser.syscalls if x.get(architecture)}
def load_syscall_priorities_from_file(file_path):
format_re = re.compile(r'^\s*([A-Za-z_][A-Za-z0-9_]+)\s*$')
priorities = []
- with open(file_path) as f:
- for line in f:
- m = format_re.match(line)
- if not m:
+ with open(file_path) as priority_file:
+ for line in priority_file:
+ match = format_re.match(line)
+ if match is None:
continue
try:
- name = m.group(1)
+ name = match.group(1)
priorities.append(name)
- except:
- logging.debug('Failed to parse %s from %s', (line, file_path))
- pass
+ except IndexError:
+ # TODO: This should be impossible becauase it wouldn't have matched?
+ logging.exception('Failed to parse %s from %s', line, file_path)
return priorities
@@ -93,7 +92,7 @@
with open(names_path) as f:
for line in f:
m = constant_re.match(line)
- if not m:
+ if m is None:
continue
try:
name = m.group(1)
@@ -102,12 +101,21 @@
m.group(2)))
constants[name] = value
- except:
+ except: # pylint: disable=bare-except
+ # TODO: This seems wrong.
+ # Key error doesn't seem like the error the original author was trying
+ # to catch. It looks like the intent was to catch IndexError from
+ # match.group() for non-matching lines, but that's impossible because
+ # the match object is checked and continued if not matched. What
+ # actually happens is that KeyError is thrown by constants[x.group(0)]
+ # on at least the first run because the dict is empty.
+ #
+ # It's also matching syntax errors because not all C integer literals
+ # are valid Python integer literals, e.g. 10L.
logging.debug('Failed to parse %s', line)
- pass
syscalls = {}
- for name, value in constants.iteritems():
+ for name, value in constants.items():
if not name.startswith("__NR_") and not name.startswith("__ARM_NR"):
continue
if name.startswith("__NR_"):
@@ -120,7 +128,7 @@
def convert_NRs_to_ranges(syscalls):
# Sort the values so we convert to ranges and binary chop
- syscalls = sorted(syscalls, lambda x, y: cmp(x[1], y[1]))
+ syscalls = sorted(syscalls, key=operator.itemgetter(1))
# Turn into a list of ranges. Keep the names for the comments
ranges = []
@@ -148,12 +156,12 @@
# We will replace {fail} and {allow} with appropriate range jumps later
return [BPF_JGE.format(ranges[0].end, "{fail}", "{allow}") +
", //" + "|".join(ranges[0].names)]
- else:
- half = (len(ranges) + 1) / 2
- first = convert_to_intermediate_bpf(ranges[:half])
- second = convert_to_intermediate_bpf(ranges[half:])
- jump = [BPF_JGE.format(ranges[half].begin, len(first), 0) + ","]
- return jump + first + second
+
+ half = (len(ranges) + 1) // 2
+ first = convert_to_intermediate_bpf(ranges[:half])
+ second = convert_to_intermediate_bpf(ranges[half:])
+ jump = [BPF_JGE.format(ranges[half].begin, len(first), 0) + ","]
+ return jump + first + second
# Converts the prioritized syscalls to a bpf list that is prepended to the
@@ -162,7 +170,7 @@
# immediately
def convert_priority_to_intermediate_bpf(priority_syscalls):
result = []
- for i, syscall in enumerate(priority_syscalls):
+ for syscall in priority_syscalls:
result.append(BPF_JEQ.format(syscall[1], "{allow}", 0) +
", //" + syscall[0])
return result
@@ -227,7 +235,8 @@
return convert_bpf_to_output(bpf, architecture, name_modifier)
-def gen_policy(name_modifier, out_dir, base_syscall_file, syscall_files, syscall_NRs, priority_file):
+def gen_policy(name_modifier, out_dir, base_syscall_file, syscall_files,
+ syscall_NRs, priority_file):
for arch in SupportedArchitectures:
base_names = load_syscall_names_from_file(base_syscall_file, arch)
allowlist_names = set()
@@ -251,7 +260,6 @@
output = construct_bpf(allowed_syscalls, arch, name_modifier, priorities)
# And output policy
- existing = ""
filename_modifier = "_" + name_modifier if name_modifier else ""
output_path = os.path.join(out_dir,
"{}{}_policy.cpp".format(arch, filename_modifier))
@@ -274,8 +282,8 @@
help=("The path of the input files. In order to "
"simplify the build rules, it can take any of the "
"following files: \n"
- "* /blocklist.*\.txt$/ syscall blocklist.\n"
- "* /allowlist.*\.txt$/ syscall allowlist.\n"
+ "* /blocklist.*\\.txt$/ syscall blocklist.\n"
+ "* /allowlist.*\\.txt$/ syscall allowlist.\n"
"* /priority.txt$/ priorities for bpf rules.\n"
"* otherwise, syscall name-number mapping.\n"))
args = parser.parse_args()
diff --git a/libc/tools/gensyscalls.py b/libc/tools/gensyscalls.py
index 0e0e25f..d8d4302 100755
--- a/libc/tools/gensyscalls.py
+++ b/libc/tools/gensyscalls.py
@@ -5,7 +5,6 @@
# makefiles used to build all the stubs.
import atexit
-import commands
import filecmp
import glob
import re
@@ -315,7 +314,7 @@
self.lineno = 0
def E(self, msg):
- print "%d: %s" % (self.lineno, msg)
+ print("%d: %s" % (self.lineno, msg))
def parse_line(self, line):
""" parse a syscall spec line.
@@ -340,7 +339,7 @@
return
syscall_func = return_type[-1]
- return_type = string.join(return_type[:-1],' ')
+ return_type = ' '.join(return_type[:-1])
socketcall_id = -1
pos_colon = syscall_func.find(':')
@@ -372,13 +371,13 @@
alias_delim = syscall_name.find('|')
if alias_delim > 0:
syscall_name = syscall_name[:alias_delim]
- syscall_aliases = string.split(alias_list, ',')
+ syscall_aliases = alias_list.split(',')
else:
syscall_aliases = []
if pos_rparen > pos_lparen+1:
syscall_params = line[pos_lparen+1:pos_rparen].split(',')
- params = string.join(syscall_params,',')
+ params = ','.join(syscall_params)
else:
syscall_params = []
params = "void"
@@ -398,7 +397,7 @@
for arch in SupportedArchitectures:
t[arch] = True
else:
- for arch in string.split(arch_list, ','):
+ for arch in arch_list.split(','):
if arch == "lp32":
for arch in SupportedArchitectures:
if "64" not in arch:
@@ -464,7 +463,7 @@
if __name__ == "__main__":
if len(sys.argv) < 2:
- print "Usage: gensyscalls.py ARCH SOURCE_FILE"
+ print("Usage: gensyscalls.py ARCH SOURCE_FILE")
sys.exit(1)
arch = sys.argv[1]
diff --git a/libc/tools/mypy.ini b/libc/tools/mypy.ini
new file mode 100644
index 0000000..0269354
--- /dev/null
+++ b/libc/tools/mypy.ini
@@ -0,0 +1,3 @@
+[mypy]
+# TODO: Enable.
+# disallow_untyped_defs = True
diff --git a/libc/tools/pylintrc b/libc/tools/pylintrc
new file mode 100644
index 0000000..df319e3
--- /dev/null
+++ b/libc/tools/pylintrc
@@ -0,0 +1,8 @@
+[MESSAGES CONTROL]
+disable=
+ eval-used,
+ design,
+ fixme,
+ invalid-name,
+ logging-fstring-interpolation,
+ missing-docstring
diff --git a/libc/tools/test_genseccomp.py b/libc/tools/test_genseccomp.py
index 812218e..8bd3517 100755
--- a/libc/tools/test_genseccomp.py
+++ b/libc/tools/test_genseccomp.py
@@ -1,176 +1,65 @@
#!/usr/bin/env python
# Unit tests for genseccomp.py
-import cStringIO
import textwrap
import unittest
import genseccomp
class TestGenseccomp(unittest.TestCase):
- def setUp(self):
- genseccomp.set_dir()
-
- def get_config(self, arch):
- for i in genseccomp.POLICY_CONFIGS:
- if i[0] == arch:
- return i
- self.fail("No such architecture")
-
- def get_headers(self, arch):
- return self.get_config(arch)[1]
-
- def get_switches(self, arch):
- return self.get_config(arch)[2]
-
- def test_get_names(self):
- bionic = cStringIO.StringIO(textwrap.dedent("""\
-int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,x86
-int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
- """))
-
- allowlist = cStringIO.StringIO(textwrap.dedent("""\
-ssize_t read(int, void*, size_t) all
- """))
-
- empty = cStringIO.StringIO(textwrap.dedent("""\
- """))
-
- names = genseccomp.get_names([bionic, allowlist, empty], "arm")
- bionic.seek(0)
- allowlist.seek(0)
- empty.seek(0)
- names64 = genseccomp.get_names([bionic, allowlist, empty], "arm64")
- bionic.seek(0)
- allowlist.seek(0)
- empty.seek(0)
-
- self.assertIn("fchown", names64)
- self.assertNotIn("fchown", names)
- self.assertIn("_llseek", names)
- self.assertNotIn("_llseek", names64)
- self.assertIn("read", names)
- self.assertIn("read", names64)
-
- # Blocklist item must be in bionic
- blocklist = cStringIO.StringIO(textwrap.dedent("""\
-int fchown2:fchown2(int, uid_t, gid_t) arm64,x86_64
- """))
- with self.assertRaises(RuntimeError):
- genseccomp.get_names([bionic, allowlist, blocklist], "arm")
- bionic.seek(0)
- allowlist.seek(0)
- blocklist.seek(0)
-
- # Test blocklist item is removed
- blocklist = cStringIO.StringIO(textwrap.dedent("""\
-int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
- """))
- names = genseccomp.get_names([bionic, allowlist, blocklist], "arm64")
- bionic.seek(0)
- allowlist.seek(0)
- blocklist.seek(0)
- self.assertIn("read", names)
- self.assertNotIn("fchown", names)
-
- # Blocklist item must not be in allowlist
- allowlist = cStringIO.StringIO(textwrap.dedent("""\
-int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
- """))
- with self.assertRaises(RuntimeError):
- genseccomp.get_names([empty, allowlist, blocklist], "arm")
- empty.seek(0)
- allowlist.seek(0)
- blocklist.seek(0)
-
- # No dups in bionic and allowlist
- allowlist = cStringIO.StringIO(textwrap.dedent("""\
-int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,x86
- """))
- with self.assertRaises(RuntimeError):
- genseccomp.get_names([bionic, allowlist, empty], "arm")
- bionic.seek(0)
- allowlist.seek(0)
- empty.seek(0)
-
- def test_convert_names_to_NRs(self):
- self.assertEquals(genseccomp.convert_names_to_NRs(["open"],
- self.get_headers("arm"),
- self.get_switches("arm")),
- [("open", 5)])
-
- self.assertEquals(genseccomp.convert_names_to_NRs(["__ARM_NR_set_tls"],
- self.get_headers("arm"),
- self.get_switches("arm")),
- [('__ARM_NR_set_tls', 983045)])
-
- self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
- self.get_headers("arm64"),
- self.get_switches("arm64")),
- [("openat", 56)])
-
- self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
- self.get_headers("x86"),
- self.get_switches("x86")),
- [("openat", 295)])
-
- self.assertEquals(genseccomp.convert_names_to_NRs(["openat"],
- self.get_headers("x86_64"),
- self.get_switches("x86_64")),
- [("openat", 257)])
-
-
def test_convert_NRs_to_ranges(self):
ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
- self.assertEquals(len(ranges), 1)
- self.assertEquals(ranges[0].begin, 1)
- self.assertEquals(ranges[0].end, 3)
- self.assertItemsEqual(ranges[0].names, ["a", "b"])
+ self.assertEqual(len(ranges), 1)
+ self.assertEqual(ranges[0].begin, 1)
+ self.assertEqual(ranges[0].end, 3)
+ self.assertEqual(set(ranges[0].names), {"a", "b"})
ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
- self.assertEquals(len(ranges), 2)
- self.assertEquals(ranges[0].begin, 1)
- self.assertEquals(ranges[0].end, 2)
- self.assertItemsEqual(ranges[0].names, ["a"])
- self.assertEquals(ranges[1].begin, 3)
- self.assertEquals(ranges[1].end, 4)
- self.assertItemsEqual(ranges[1].names, ["b"])
+ self.assertEqual(len(ranges), 2)
+ self.assertEqual(ranges[0].begin, 1)
+ self.assertEqual(ranges[0].end, 2)
+ self.assertEqual(set(ranges[0].names), {"a"})
+ self.assertEqual(ranges[1].begin, 3)
+ self.assertEqual(ranges[1].end, 4)
+ self.assertEqual(set(ranges[1].names), {"b"})
def test_convert_to_intermediate_bpf(self):
ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
bpf = genseccomp.convert_to_intermediate_bpf(ranges)
- self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, {fail}, {allow}), //a|b'])
+ self.assertEqual(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, {fail}, {allow}), //a|b'])
ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
bpf = genseccomp.convert_to_intermediate_bpf(ranges)
- self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
+ self.assertEqual(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, {fail}, {allow}), //a',
'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, {fail}, {allow}), //b'])
def test_convert_ranges_to_bpf(self):
ranges = genseccomp.convert_NRs_to_ranges([("b", 2), ("a", 1)])
- bpf = genseccomp.convert_ranges_to_bpf(ranges)
- self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 2),',
+ bpf = genseccomp.convert_ranges_to_bpf(ranges, priority_syscalls=[])
+ self.assertEqual(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 2),',
'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0), //a|b',
'BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),'])
ranges = genseccomp.convert_NRs_to_ranges([("b", 3), ("a", 1)])
- bpf = genseccomp.convert_ranges_to_bpf(ranges)
- self.assertEquals(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 4),',
+ bpf = genseccomp.convert_ranges_to_bpf(ranges, priority_syscalls=[])
+ self.assertEqual(bpf, ['BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 1, 0, 4),',
'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 1, 0),',
'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 2, 2, 1), //a',
'BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 1, 0), //b',
'BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),'])
def test_convert_bpf_to_output(self):
- output = genseccomp.convert_bpf_to_output(["line1", "line2"], "arm")
+ output = genseccomp.convert_bpf_to_output(["line1", "line2"],
+ "arm",
+ name_modifier="")
expected_output = textwrap.dedent("""\
- // Autogenerated file - edit at your peril!!
+ // File autogenerated by genseccomp.py - edit at your peril!!
#include <linux/filter.h>
#include <errno.h>
- #include "seccomp_bpfs.h"
+ #include "seccomp/seccomp_bpfs.h"
const sock_filter arm_filter[] = {
line1
line2
@@ -178,43 +67,7 @@
const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
""")
- self.assertEquals(output, expected_output)
-
- def test_construct_bpf(self):
- syscalls = cStringIO.StringIO(textwrap.dedent("""\
- int __llseek:_llseek(int, unsigned long, unsigned long, off64_t*, int) arm,x86
- int fchown:fchown(int, uid_t, gid_t) arm64,x86_64
- """))
-
- allowlist = cStringIO.StringIO(textwrap.dedent("""\
- ssize_t read(int, void*, size_t) all
- """))
-
- blocklist = cStringIO.StringIO(textwrap.dedent("""\
- """))
-
- syscall_files = [syscalls, allowlist, blocklist]
- output = genseccomp.construct_bpf(syscall_files, "arm", self.get_headers("arm"),
- self.get_switches("arm"))
-
- expected_output = textwrap.dedent("""\
- // Autogenerated file - edit at your peril!!
-
- #include <linux/filter.h>
- #include <errno.h>
-
- #include "seccomp_bpfs.h"
- const sock_filter arm_filter[] = {
- BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 3, 0, 4),
- BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 140, 1, 0),
- BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 4, 2, 1), //read
- BPF_JUMP(BPF_JMP|BPF_JGE|BPF_K, 141, 1, 0), //_llseek
- BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
- };
-
- const size_t arm_filter_size = sizeof(arm_filter) / sizeof(struct sock_filter);
- """)
- self.assertEquals(output, expected_output)
+ self.assertEqual(output, expected_output)
if __name__ == '__main__':
diff --git a/libm/Android.bp b/libm/Android.bp
index 735b1cf..723d126 100644
--- a/libm/Android.bp
+++ b/libm/Android.bp
@@ -475,6 +475,7 @@
"-fno-math-errno",
"-Wall",
"-Werror",
+ "-Wno-ignored-pragmas",
"-Wno-missing-braces",
"-Wno-parentheses",
"-Wno-sign-compare",
diff --git a/tests/Android.bp b/tests/Android.bp
index a6a930e..5840018 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -17,7 +17,6 @@
cc_defaults {
name: "bionic_tests_defaults",
host_supported: true,
- cpp_std: "experimental",
target: {
darwin: {
enabled: false,
@@ -1017,6 +1016,10 @@
// For now, these tests run forever, so do not use the isolation framework.
isolated: false,
+ // Running forever, do not consider unit test.
+ test_options: {
+ unit_test: false,
+ },
srcs: [
"malloc_stress_test.cpp",
diff --git a/tools/Android.bp b/tools/Android.bp
index c540c3c..dfeea19 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -3,4 +3,5 @@
filegroup {
name: "bionic-generate-version-script",
srcs: ["generate-version-script.py"],
+ bazel_module: { bp2build_available: true },
}
diff --git a/tools/update_notice.sh b/tools/update_notice.sh
index a309bc2..302974f 100755
--- a/tools/update_notice.sh
+++ b/tools/update_notice.sh
@@ -1,7 +1,11 @@
#!/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR/..
-./libc/tools/generate-NOTICE.py libc libm > libc/NOTICE
+python3 ./libc/tools/generate_notice.py libc libm > libc/NOTICE
+if [ $? -ne 0 ]; then
+ >&2 echo NOTICE file generation failed
+ exit 1
+fi
git diff --exit-code HEAD libc/NOTICE
exit $?