Add NetBSD syscall hooks skeleton in sanitizers

Summary:
Implement the skeleton of NetBSD syscall hooks for use with sanitizers.

Add a script that generates the rules to handle syscalls
on NetBSD: generate_netbsd_syscalls.awk. It has been written
in NetBSD awk(1) (patched nawk) and is compatible with gawk.

Generate lib/sanitizer_common/sanitizer_platform_limits_netbsd.h
that is a public header for applications, and included as:
<sanitizer_common/sanitizer_platform_limits_netbsd.h>.

Generate sanitizer_syscalls_netbsd.inc that defines all the
syscall rules for NetBSD. This file is modeled after the Linux
specific file: sanitizer_common_syscalls.inc.

Start recognizing NetBSD syscalls with existing sanitizers:
ASan, ESan, HWASan, TSan, MSan.

Sponsored by <The NetBSD Foundation>

Reviewers: joerg, vitalybuka, kcc, dvyukov, eugenis

Reviewed By: vitalybuka

Subscribers: hintonda, kubamracek, mgorny, llvm-commits, #sanitizers

Tags: #sanitizers

Differential Revision: https://reviews.llvm.org/D42048

llvm-svn: 325206
This commit is contained in:
Kamil Rytarowski 2018-02-15 02:43:02 +00:00
parent 9491643c4b
commit 39628a7ab0
10 changed files with 575 additions and 0 deletions

View File

@ -10,6 +10,7 @@ if (COMPILER_RT_BUILD_SANITIZERS)
sanitizer/linux_syscall_hooks.h
sanitizer/lsan_interface.h
sanitizer/msan_interface.h
sanitizer/netbsd_syscall_hooks.h
sanitizer/scudo_interface.h
sanitizer/tsan_interface.h
sanitizer/tsan_interface_atomic.h)

View File

@ -0,0 +1,45 @@
//===-- netbsd_syscall_hooks.h --------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of public sanitizer interface.
//
// System call handlers.
//
// Interface methods declared in this header implement pre- and post- syscall
// actions for the active sanitizer.
// Usage:
// __sanitizer_syscall_pre_getfoo(...args...);
// long long res = syscall(SYS_getfoo, ...args...);
// __sanitizer_syscall_post_getfoo(res, ...args...);
//
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
//
// Generated with: generate_netbsd_syscalls.awk
// Generated date: 2018-02-15
// Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H
#define SANITIZER_NETBSD_SYSCALL_HOOKS_H
#ifdef __cplusplus
extern "C" {
#endif
// Private declarations. Do not call directly from user code. Use macros above.
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
#ifdef __cplusplus
} // extern "C"
#endif
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
#endif // SANITIZER_NETBSD_SYSCALL_HOOKS_H

View File

@ -178,6 +178,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
(void)(s); \
} while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
struct ThreadStartParam {
atomic_uintptr_t t;

View File

@ -232,6 +232,7 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
} while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
//===----------------------------------------------------------------------===//
// Custom interceptors

View File

@ -457,6 +457,7 @@ int OnExit() {
(void)(s); \
} while (false)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"

View File

@ -1392,6 +1392,7 @@ static uptr signal_impl(int signo, uptr cb) {
} while (false)
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
struct dlinfo {
char *dli_fname;

View File

@ -143,6 +143,7 @@ set(SANITIZER_HEADERS
sanitizer_syscall_generic.inc
sanitizer_syscall_linux_x86_64.inc
sanitizer_syscall_linux_aarch64.inc
sanitizer_syscalls_netbsd.inc
sanitizer_thread_registry.h
sanitizer_vector.h
sanitizer_win.h)

View File

@ -0,0 +1,107 @@
//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Common syscalls handlers for tools like AddressSanitizer,
// ThreadSanitizer, MemorySanitizer, etc.
//
// This file should be included into the tool's interceptor file,
// which has to define it's own macros:
// COMMON_SYSCALL_PRE_READ_RANGE
// Called in prehook for regions that will be read by the kernel and
// must be initialized.
// COMMON_SYSCALL_PRE_WRITE_RANGE
// Called in prehook for regions that will be written to by the kernel
// and must be addressable. The actual write range may be smaller than
// reported in the prehook. See POST_WRITE_RANGE.
// COMMON_SYSCALL_POST_READ_RANGE
// Called in posthook for regions that were read by the kernel. Does
// not make much sense.
// COMMON_SYSCALL_POST_WRITE_RANGE
// Called in posthook for regions that were written to by the kernel
// and are now initialized.
// COMMON_SYSCALL_ACQUIRE(addr)
// Acquire memory visibility from addr.
// COMMON_SYSCALL_RELEASE(addr)
// Release memory visibility to addr.
// COMMON_SYSCALL_FD_CLOSE(fd)
// Called before closing file descriptor fd.
// COMMON_SYSCALL_FD_ACQUIRE(fd)
// Acquire memory visibility from fd.
// COMMON_SYSCALL_FD_RELEASE(fd)
// Release memory visibility to fd.
// COMMON_SYSCALL_PRE_FORK()
// Called before fork syscall.
// COMMON_SYSCALL_POST_FORK(long long res)
// Called after fork syscall.
//
// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!
//
// Generated with: generate_netbsd_syscalls.awk
// Generated date: 2018-02-15
// Generated from: syscalls.master,v 1.291 2018/01/06 16:41:23 kamil Exp
//
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
#if SANITIZER_NETBSD
#include "sanitizer_libc.h"
#define PRE_SYSCALL(name) \
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name
#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)
#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)
#define POST_SYSCALL(name) \
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name
#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)
#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)
#ifndef COMMON_SYSCALL_ACQUIRE
#define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))
#endif
#ifndef COMMON_SYSCALL_RELEASE
#define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))
#endif
#ifndef COMMON_SYSCALL_FD_CLOSE
#define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))
#endif
#ifndef COMMON_SYSCALL_FD_ACQUIRE
#define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))
#endif
#ifndef COMMON_SYSCALL_FD_RELEASE
#define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))
#endif
#ifndef COMMON_SYSCALL_PRE_FORK
#define COMMON_SYSCALL_PRE_FORK() \
{}
#endif
#ifndef COMMON_SYSCALL_POST_FORK
#define COMMON_SYSCALL_POST_FORK(res) \
{}
#endif
// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
extern "C" {} // extern "C"
#undef PRE_SYSCALL
#undef PRE_READ
#undef PRE_WRITE
#undef POST_SYSCALL
#undef POST_READ
#undef POST_WRITE
#endif // SANITIZER_NETBSD

View File

@ -2517,6 +2517,7 @@ static void syscall_post_fork(uptr pc, int pid) {
syscall_post_fork(GET_CALLER_PC(), res)
#include "sanitizer_common/sanitizer_common_syscalls.inc"
#include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
#ifdef NEED_TLS_GET_ADDR
// Define own interceptor instead of sanitizer_common's for three reasons:

View File

@ -0,0 +1,416 @@
#!/usr/bin/awk -f
#===-- generate_netbsd_syscalls.awk ----------------------------------------===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
#
# This file is a generator of:
# - include/sanitizer/netbsd_syscall_hooks.h
# - lib/sanitizer_common/sanitizer_syscalls_netbsd.inc
#
# This script accepts on the input syscalls.master by default located in the
# /usr/src/sys/kern/syscalls.master path in the NetBSD distribution.
#
# NetBSD version 8.0.
#
#===------------------------------------------------------------------------===#
BEGIN {
# harcode the script name
script_name = "generate_netbsd_syscalls.awk"
outputh = "../include/sanitizer/netbsd_syscall_hooks.h"
outputinc = "../lib/sanitizer_common/sanitizer_syscalls_netbsd.inc"
# assert that we are in the directory with scripts
in_utils = system("test -f " script_name " && exit 1 || exit 0")
if (in_utils == 0) {
usage()
}
# assert 1 argument passed
if (ARGC != 2) {
usage()
}
# assert argument is a valid file path to syscall.master
if (system("test -f " ARGV[1]) != 0) {
usage()
}
# sanity check that the path ends with "syscall.master"
if (ARGV[1] !~ /syscalls\.master$/) {
usage()
}
# accept overloading CLANGFORMAT from environment
clangformat = "clang-format"
if ("CLANGFORMAT" in ENVIRON) {
clangformat = ENVIRON["CLANGFORMAT"]
}
# parsing specific symbols
parsingheader=1
parsedsyscalls=0
# Hardcoded in algorithm
SYS_MAXSYSARGS=8
}
# Parse the RCS ID from syscall.master
parsingheader == 1 && NR == 1 {
if (match($0, /\$[^$]+\$/)) {
# trim initial 'NetBSD: ' and trailing ' $'
syscallmasterversion = substr($0, RSTART + 9, RLENGTH - 11)
} else {
# wrong file?
usage()
}
}
# skip the following lines
# - empty
NF == 0 {
next
}
# - comment
$1 == ";" {
next
}
# separator between the header and table with syscalls
$0 == "%%" {
parsingheader = 0
next
}
# preserve 'if/elif/else/endif' C preprocessor as-is
parsingheader == 0 && $0 ~ /^#/ {
if (parsedsyscalls in ifelifelseendif) {
ifelifelseendif[parsedsyscalls] = ifelifelseendif[parsedsyscalls] "\n" $0
} else {
ifelifelseendif[parsedsyscalls] = $0
}
next
}
# parsing of syscall definitions
parsingheader == 0 && $1 ~ /^[0-9]+$/ {
# first join multiple lines into single one
while (sub(/\\$/, "")) {
getline line
$0 = $0 "" line
}
# Skip unwanted syscalls
skip=0
if ($0 ~ /OBSOL/ || $0 ~ /EXCL/ || $0 ~ /UNIMPL/) {
skip=1
}
# Compose the syscall name
# - compat?
compat=""
if (match($0, /COMPAT_[0-9]+/)) {
compat = tolower(substr($0, RSTART, RLENGTH))
}
# - alias name?
alias=""
if ($(NF) != "}" && !skip) {
alias = alias "" $(NF)
}
# - compat version?
compatver=""
if (match($0, /\|[0-9]+\|/)) {
compatver = tolower(substr($0, RSTART + 1, RLENGTH - 2))
}
# - basename?
basename=""
if (skip) {
basename = $1
} else {
if (match($0, /\|[_a-z0-9]+\(/)) {
basename = tolower(substr($0, RSTART + 1, RLENGTH - 2))
}
}
syscallname=""
if (skip) {
syscallname= syscallname "$"
}
if (length(compat) > 0) {
syscallname = syscallname "" compat "_"
}
if (length(alias) > 0) {
syscallname = syscallname "" alias
} else {
if (length(compatver) > 0) {
syscallname = syscallname "__" basename "" compatver
} else {
syscallname = syscallname "" basename
}
}
# Store the syscallname
syscalls[parsedsyscalls]=syscallname
# Extract syscall arguments
if (match($0, /\([^)]+\)/)) {
args = substr($0, RSTART + 1, RLENGTH - 2)
if (args == "void") {
syscallargs[parsedsyscalls] = "void"
syscallfullargs[parsedsyscalls] = "void"
} else {
# Normalize 'type * argument' to 'type *argument'
gsub("\\*[ \t]+", "*", args)
n = split(args, a, ",")
# Handle the first argument
match(a[1], /[*_a-z0-9\[\]]+$/)
syscallfullargs[parsedsyscalls] = substr(a[1], RSTART) "_"
gsub(".+[ *]", "", a[1])
syscallargs[parsedsyscalls] = a[1]
# Handle the rest of arguments
for (i = 2; i <= n; i++) {
match(a[i], /[*_a-zA-Z0-9\[\]]+$/)
fs = substr(a[i], RSTART)
if (fs ~ /\[/) {
sub(/\[/, "_[", fs)
} else {
fs = fs "_"
}
syscallfullargs[parsedsyscalls] = syscallfullargs[parsedsyscalls] "$" fs
gsub(".+[ *]", "", a[i])
syscallargs[parsedsyscalls] = syscallargs[parsedsyscalls] "$" a[i]
}
# Handle array arguments for syscall(2) and __syscall(2)
nargs = "arg0$arg1$arg2$arg3$arg4$arg5$arg6$arg7"
gsub(/args\[SYS_MAXSYSARGS\]/, nargs, syscallargs[parsedsyscalls])
}
}
parsedsyscalls++
# Done with this line
next
}
END {
# empty file?
if (NR < 1 && !abnormal_exit) {
usage()
}
# Handle abnormal exit
if (abnormal_exit) {
exit(abnormal_exit)
}
# Generate sanitizer_syscalls_netbsd.inc
# open pipe
cmd = clangformat " > " outputh
pcmd("//===-- netbsd_syscall_hooks.h --------------------------------------------===//")
pcmd("//")
pcmd("// The LLVM Compiler Infrastructure")
pcmd("//")
pcmd("// This file is distributed under the University of Illinois Open Source")
pcmd("// License. See LICENSE.TXT for details.")
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("//")
pcmd("// This file is a part of public sanitizer interface.")
pcmd("//")
pcmd("// System call handlers.")
pcmd("//")
pcmd("// Interface methods declared in this header implement pre- and post- syscall")
pcmd("// actions for the active sanitizer.")
pcmd("// Usage:")
pcmd("// __sanitizer_syscall_pre_getfoo(...args...);")
pcmd("// long long res = syscall(SYS_getfoo, ...args...);")
pcmd("// __sanitizer_syscall_post_getfoo(res, ...args...);")
pcmd("//")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("//")
pcmd("// Generated with: " script_name)
pcmd("// Generated date: " strftime("%F"))
pcmd("// Generated from: " syscallmasterversion)
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("#ifndef SANITIZER_NETBSD_SYSCALL_HOOKS_H")
pcmd("#define SANITIZER_NETBSD_SYSCALL_HOOKS_H")
pcmd("")
# TODO
pcmd("")
pcmd("#ifdef __cplusplus")
pcmd("extern \"C\" {")
pcmd("#endif")
pcmd("")
pcmd("// Private declarations. Do not call directly from user code. Use macros above.")
pcmd("")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("")
# TODO
pcmd("")
pcmd("#ifdef __cplusplus")
pcmd("} // extern \"C\"")
pcmd("#endif")
pcmd("")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("")
pcmd("#endif // SANITIZER_NETBSD_SYSCALL_HOOKS_H")
close(cmd)
# Generate sanitizer_syscalls_netbsd.inc
# open pipe
cmd = clangformat " > " outputinc
pcmd("//===-- sanitizer_syscalls_netbsd.inc ---------------------------*- C++ -*-===//")
pcmd("//")
pcmd("// The LLVM Compiler Infrastructure")
pcmd("//")
pcmd("// This file is distributed under the University of Illinois Open Source")
pcmd("// License. See LICENSE.TXT for details.")
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("//")
pcmd("// Common syscalls handlers for tools like AddressSanitizer,")
pcmd("// ThreadSanitizer, MemorySanitizer, etc.")
pcmd("//")
pcmd("// This file should be included into the tool's interceptor file,")
pcmd("// which has to define it's own macros:")
pcmd("// COMMON_SYSCALL_PRE_READ_RANGE")
pcmd("// Called in prehook for regions that will be read by the kernel and")
pcmd("// must be initialized.")
pcmd("// COMMON_SYSCALL_PRE_WRITE_RANGE")
pcmd("// Called in prehook for regions that will be written to by the kernel")
pcmd("// and must be addressable. The actual write range may be smaller than")
pcmd("// reported in the prehook. See POST_WRITE_RANGE.")
pcmd("// COMMON_SYSCALL_POST_READ_RANGE")
pcmd("// Called in posthook for regions that were read by the kernel. Does")
pcmd("// not make much sense.")
pcmd("// COMMON_SYSCALL_POST_WRITE_RANGE")
pcmd("// Called in posthook for regions that were written to by the kernel")
pcmd("// and are now initialized.")
pcmd("// COMMON_SYSCALL_ACQUIRE(addr)")
pcmd("// Acquire memory visibility from addr.")
pcmd("// COMMON_SYSCALL_RELEASE(addr)")
pcmd("// Release memory visibility to addr.")
pcmd("// COMMON_SYSCALL_FD_CLOSE(fd)")
pcmd("// Called before closing file descriptor fd.")
pcmd("// COMMON_SYSCALL_FD_ACQUIRE(fd)")
pcmd("// Acquire memory visibility from fd.")
pcmd("// COMMON_SYSCALL_FD_RELEASE(fd)")
pcmd("// Release memory visibility to fd.")
pcmd("// COMMON_SYSCALL_PRE_FORK()")
pcmd("// Called before fork syscall.")
pcmd("// COMMON_SYSCALL_POST_FORK(long long res)")
pcmd("// Called after fork syscall.")
pcmd("//")
pcmd("// DO NOT EDIT! THIS FILE HAS BEEN GENERATED!")
pcmd("//")
pcmd("// Generated with: " script_name)
pcmd("// Generated date: " strftime("%F"))
pcmd("// Generated from: " syscallmasterversion)
pcmd("//")
pcmd("//===----------------------------------------------------------------------===//")
pcmd("")
pcmd("#include \"sanitizer_platform.h\"")
pcmd("#if SANITIZER_NETBSD")
pcmd("")
pcmd("#include \"sanitizer_libc.h\"")
pcmd("")
pcmd("#define PRE_SYSCALL(name) \\")
pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name")
pcmd("#define PRE_READ(p, s) COMMON_SYSCALL_PRE_READ_RANGE(p, s)")
pcmd("#define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s)")
pcmd("")
pcmd("#define POST_SYSCALL(name) \\")
pcmd(" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_post_impl_##name")
pcmd("#define POST_READ(p, s) COMMON_SYSCALL_POST_READ_RANGE(p, s)")
pcmd("#define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s)")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_ACQUIRE")
pcmd("# define COMMON_SYSCALL_ACQUIRE(addr) ((void)(addr))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_RELEASE")
pcmd("# define COMMON_SYSCALL_RELEASE(addr) ((void)(addr))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_FD_CLOSE")
pcmd("# define COMMON_SYSCALL_FD_CLOSE(fd) ((void)(fd))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_FD_ACQUIRE")
pcmd("# define COMMON_SYSCALL_FD_ACQUIRE(fd) ((void)(fd))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_FD_RELEASE")
pcmd("# define COMMON_SYSCALL_FD_RELEASE(fd) ((void)(fd))")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_PRE_FORK")
pcmd("# define COMMON_SYSCALL_PRE_FORK() {}")
pcmd("#endif")
pcmd("")
pcmd("#ifndef COMMON_SYSCALL_POST_FORK")
pcmd("# define COMMON_SYSCALL_POST_FORK(res) {}")
pcmd("#endif")
pcmd("")
pcmd("// FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).")
pcmd("")
pcmd("extern \"C\" {")
# TODO
pcmd("} // extern \"C\"")
pcmd("")
pcmd("#undef PRE_SYSCALL")
pcmd("#undef PRE_READ")
pcmd("#undef PRE_WRITE")
pcmd("#undef POST_SYSCALL")
pcmd("#undef POST_READ")
pcmd("#undef POST_WRITE")
pcmd("")
pcmd("#endif // SANITIZER_NETBSD")
close(cmd)
# Hack for preprocessed code
system("sed -i 's,^ \\([^ ]\\), \\1,' " outputinc)
}
function usage()
{
print "Usage: " script_name " syscalls.master"
abnormal_exit = 1
exit 1
}
function pcmd(string)
{
print string | cmd
}