BoxFort-master/0002755000175000017500000000000013603450524012376 5ustar sasasasaBoxFort-master/.cirrus.yml0000644000175000017500000000250213603450524014503 0ustar sasasasa_pipeline: &pipeline info_script: | meson --version ninja --version configure_script: meson build compile_script: ninja -C build test_script: ninja -C build test Debian (gcc)_task: container: image: snaipe/ci-meson:debian-10 <<: *pipeline Alpine (gcc,x86_64)_task: container: image: snaipe/ci-meson:alpine <<: *pipeline Alpine (gcc,i386)_task: container: image: snaipe/ci-meson:alpine-x86 <<: *pipeline Alpine (gcc,arm)_task: container: image: snaipe/ci-meson:alpine-armhf env: CIRRUS_SHELL: /sbin/qemu-sh <<: *pipeline Alpine (gcc,aarch64)_task: container: image: snaipe/ci-meson:alpine-aarch64 env: CIRRUS_SHELL: /sbin/qemu-sh <<: *pipeline MacOS_task: osx_instance: image: mojave-xcode-10.2 setup_script: brew install meson <<: *pipeline FreeBSD_task: freebsd_instance: image_family: freebsd-12-0 setup_script: pkg install -y meson <<: *pipeline Windows_task: windows_container: image: cirrusci/windowsservercore:cmake os_version: 2019 env: PATH: C:\\Python;C:\\Python\\Scripts;C:\\ProgramData\\chocolatey\\lib\\ninja\\tools;%PATH% meson-setup_script: |- choco install -y --no-progress python3 --params "/InstallDir:C:\Python" pip install meson ninja-setup_script: choco install -y --no-progress ninja <<: *pipeline BoxFort-master/.githooks/0002755000175000017500000000000013603450524014303 5ustar sasasasaBoxFort-master/.githooks/canonicalize_filename.sh0000644000175000017500000000320113603450524021130 0ustar sasasasa#!/bin/sh # Provide the canonicalize filename (physical filename with out any symlinks) # like the GNU version readlink with the -f option regardless of the version of # readlink (GNU or BSD). # This file is part of a set of unofficial pre-commit hooks available # at github. # Link: https://github.com/githubbrowser/Pre-commit-hooks # Contact: David Martin, david.martin.mailbox@googlemail.com ########################################################### # There should be no need to change anything below this line. # Canonicalize by recursively following every symlink in every component of the # specified filename. This should reproduce the results of the GNU version of # readlink with the -f option. # # Reference: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac canonicalize_filename () { local target_file="$1" local physical_directory="" local result="" # Need to restore the working directory after work. local working_dir="`pwd`" cd -- "$(dirname -- "$target_file")" target_file="$(basename -- "$target_file")" # Iterate down a (possible) chain of symlinks while [ -L "$target_file" ] do target_file="$(readlink -- "$target_file")" cd -- "$(dirname -- "$target_file")" target_file="$(basename -- "$target_file")" done # Compute the canonicalized name by finding the physical path # for the directory we're in and appending the target file. physical_directory="`pwd -P`" result="$physical_directory/$target_file" # restore the working directory after work. cd -- "$working_dir" echo "$result" } BoxFort-master/.githooks/install.sh0000755000175000017500000000007313603450524016306 0ustar sasasasa#!/bin/sh rm -Rf .git/hooks ln -s ../.githooks .git/hooks BoxFort-master/.githooks/pre-commit0000755000175000017500000001424613603450524016312 0ustar sasasasa#!/bin/sh # git pre-commit hook that runs an Uncrustify stylecheck. # Features: # - abort commit when commit does not comply with the style guidelines # - create a patch of the proposed style changes # # More info on Uncrustify: http://uncrustify.sourceforge.net/ # This file is part of a set of unofficial pre-commit hooks available # at github. # Link: https://github.com/githubbrowser/Pre-commit-hooks # Contact: David Martin, david.martin.mailbox@googlemail.com ################################################################## # CONFIGURATION # set uncrustify path or executable # UNCRUSTIFY="/usr/bin/uncrustify" UNCRUSTIFY="uncrustify" # set uncrustify config location # CONFIG="/home/user/.config/uncrustify.cfg" CONFIG=".uncrustify.cfg" # the source language: C, CPP, D, CS, JAVA, PAWN, VALA, OC, OC+ # use AUTO to let Uncrustify decide which language a given file uses. # the detected language is printed to the console when Uncrustify is called. # override if the automatic detection seems off. # SOURCE_LANGUAGE="AUTO" SOURCE_LANGUAGE="AUTO" # remove any older patches from previous commits. Set to true or false. # DELETE_OLD_PATCHES=false DELETE_OLD_PATCHES=false # only parse files with the extensions in FILE_EXTS. Set to true or false. # if false every changed file in the commit will be parsed with Uncrustify. # if true only files matching one of the extensions are parsed with Uncrustify. # PARSE_EXTS=true PARSE_EXTS=true # file types to parse. Only effective when PARSE_EXTS is true. # FILE_EXTS=".c .h .cpp .hpp" FILE_EXTS=".c .h .cc .hh .cpp .hpp .hxx" ################################################################## # There should be no need to change anything below this line. . "$(dirname -- "$0")/canonicalize_filename.sh" # exit on error set -e # check whether the given file matches any of the set extensions matches_extension() { local filename="$(basename -- "$1")" local extension=".${filename##*.}" local ext for ext in $FILE_EXTS; do [ "$ext" = "$extension" ] && return 0; done return 1 } # necessary check for initial commit if git rev-parse --verify HEAD >/dev/null 2>&1 ; then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi # make sure the config file and executable are correctly set if [ ! -f "$CONFIG" ] ; then printf "Error: uncrustify config file not found.\n" printf "Set the correct path in $(canonicalize_filename "$0").\n" exit 1 fi if ! command -v "$UNCRUSTIFY" > /dev/null ; then printf "Error: uncrustify executable not found.\n" printf "Set the correct path in $(canonicalize_filename "$0").\n" exit 1 fi # create a filename to store our generated patch prefix="pre-commit-uncrustify" suffix="$(date +%C%y-%m-%d_%Hh%Mm%Ss)" patch="/tmp/$prefix-$suffix.patch" # clean up any older uncrustify patches $DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch # create one patch containing all changes to the files # sed to remove quotes around the filename, if inserted by the system # (done sometimes, if the filename contains special characters, like the quote itself) git diff-index --cached --diff-filter=ACMR --name-only $against -- | \ sed -e 's/^"\(.*\)"$/\1/' | \ while read file do # ignore file if we do check for file extensions and the file # does not match any of the extensions specified in $FILE_EXTS if $PARSE_EXTS && ! matches_extension "$file"; then continue; fi # escape special characters in the source filename: # - '\': backslash needs to be escaped # - '*': used as matching string => '*' would mean expansion # (curiously, '?' must not be escaped) # - '[': used as matching string => '[' would mean start of set # - '|': used as sed split char instead of '/', so it needs to be escaped # in the filename # printf %s particularly important if the filename contains the % character file_escaped_source=$(printf "%s" "$file" | sed -e 's/[\*[|]/\\&/g') # escape special characters in the target filename: # phase 1 (characters escaped in the output diff): # - '\': backslash needs to be escaped in the output diff # - '"': quote needs to be escaped in the output diff if present inside # of the filename, as it used to bracket the entire filename part # phase 2 (characters escaped in the match replacement): # - '\': backslash needs to be escaped again for sed itself # (i.e. double escaping after phase 1) # - '&': would expand to matched string # - '|': used as sed split char instead of '/' # printf %s particularly important if the filename contains the % character file_escaped_target=$(printf "%s" "$file" | sed -e 's/[\"]/\\&/g' -e 's/[\&|]/\\&/g') # Uncrustify detects the language automatically if it is not specified language_option="" if [ "$SOURCE_LANGUAGE" != "AUTO" ] ; then language_option="-l $SOURCE_LANGUAGE" fi # uncrustify our sourcefile, create a patch with diff and append it to our $patch # The sed call is necessary to transform the patch from # --- $file timestamp # +++ - timestamp # to both lines working on the same file and having a a/ and b/ prefix. # Else it can not be applied with 'git apply'. "$UNCRUSTIFY" -c "$CONFIG" -f "$file" $language_option | \ git --no-pager diff --color=always --no-index -- "$file" - | \ sed -e "1s|--- $file_escaped_source|--- \"a/$file_escaped_target\"|" -e "2s|+++ -|+++ \"b/$file_escaped_target\"|" >> "$patch" done # if no patch has been generated all is ok, clean up the file stub and exit if [ ! -s "$patch" ] ; then printf "Files in this commit comply with the uncrustify rules.\n" rm -f "$patch" exit 0 fi # a patch has been created, notify the user and exit printf "\nThe following differences were found between the code to commit " printf "and the uncrustify rules:\n\n" cat "$patch" printf "\nYou can apply these changes with:\n git apply $patch\n" printf "(may need to be called from the root directory of your repository)\n" printf "Aborting commit. Apply changes and commit again or skip checking with" printf " --no-verify (not recommended).\n" exit 1 BoxFort-master/.gitignore0000644000175000017500000000002713603450524014363 0ustar sasasasabuild/ *.swp *.swo *~ BoxFort-master/.uncrustify.cfg0000644000175000017500000001571713603450524015361 0ustar sasasasa# General tok_split_gte=false utf8_byte=false utf8_force=true code_width=80 newlines=lf utf8_bom=remove input_tab_size=4 output_tab_size=4 # Comments cmt_indent_multi=true cmt_c_group=false cmt_c_nl_start=false cmt_c_nl_end=false cmt_cpp_group=true cmt_cpp_nl_start=false cmt_cpp_nl_end=false cmt_cpp_to_c=true cmt_star_cont=false cmt_multi_check_last=true cmt_insert_before_preproc=false # Indentation indent_columns=4 indent_continue=8 indent_xml_string=2 indent_ctor_init=4 indent_switch_case=4 indent_label=1 indent_access_spec=0 indent_with_tabs=0 indent_cmt_with_tabs=false indent_align_string=true indent_braces=false indent_braces_no_func=false indent_braces_no_class=false indent_braces_no_struct=false indent_brace_parent=false indent_namespace=false indent_extern=false indent_class=false indent_class_colon=true indent_else_if=true indent_var_def_cont=false indent_func_call_param=true indent_func_def_param=true indent_func_proto_param=true indent_func_class_param=true indent_func_ctor_var_param=true indent_template_param=true indent_func_param_double=true indent_relative_single_line_comments=false indent_col1_comment=false indent_access_spec_body=true indent_paren_nl=false indent_comma_paren=false indent_bool_paren=false indent_first_bool_expr=false indent_square_nl=false indent_preserve_sql=false indent_align_assign=true # Alignment align_var_def_span=0 align_assign_span=1 align_assign_thresh=3 align_enum_equ_span=1 align_enum_equ_thresh=3 align_var_struct_span=0 align_struct_init_span=1 align_right_cmt_span=1 align_keep_tabs=false align_with_tabs=false align_on_tabstop=false align_number_left=false align_func_params=false align_same_func_call_params=false align_var_def_colon=true align_var_def_attribute=false align_var_def_inline=true align_right_cmt_mix=false align_on_operator=false align_mix_var_proto=false align_single_line_func=true align_single_line_brace=true align_nl_cont=true align_left_shift=true align_oc_decl_colon=false # Spacing sp_arith=force sp_assign=force sp_assign_default=force sp_enum_assign=force sp_pp_concat=force sp_pp_stringify=remove sp_bool=force sp_compare=force sp_inside_paren=remove sp_paren_paren=remove sp_paren_brace=force sp_before_ptr_star=force sp_between_ptr_star=remove sp_after_ptr_star=remove sp_after_ptr_star_func=remove sp_before_ptr_star_func=force sp_before_byref=force sp_before_unnamed_byref=force sp_after_byref=remove sp_after_byref_func=remove sp_before_byref_func=force sp_after_type=force sp_template_angle=add sp_before_angle=remove sp_inside_angle=remove sp_after_angle=force sp_angle_paren=remove sp_angle_word=force sp_angle_shift=ignore sp_before_sparen=force sp_inside_sparen=remove sp_after_sparen=force sp_sparen_brace=force sp_special_semi=remove sp_before_semi=remove sp_before_semi_for=remove sp_before_semi_for_empty=remove sp_after_semi=force sp_after_semi_for=force sp_after_semi_for_empty=remove sp_before_square=remove sp_before_squares=remove sp_inside_square=remove sp_after_comma=force sp_before_comma=remove sp_paren_comma=ignore sp_before_ellipsis=remove sp_after_class_colon=force sp_before_class_colon=force sp_before_case_colon=remove sp_after_operator=remove sp_after_operator_sym=remove sp_after_cast=force sp_inside_paren_cast=remove sp_cpp_cast_paren=force sp_sizeof_paren=force sp_inside_braces_enum=force sp_inside_braces_struct=force sp_inside_braces=force sp_inside_braces_empty=remove sp_func_proto_paren=remove sp_func_def_paren=remove sp_inside_fparens=remove sp_inside_fparen=remove sp_square_fparen=remove sp_fparen_brace=force sp_func_call_paren=remove sp_func_call_user_paren=remove sp_func_class_paren=remove sp_return_paren=force sp_attribute_paren=remove sp_defined_paren=force sp_throw_paren=force sp_catch_paren=force sp_macro=force sp_macro_func=force sp_else_brace=force sp_brace_else=force sp_brace_typedef=force sp_catch_brace=force sp_brace_catch=force sp_finally_brace=force sp_brace_finally=force sp_try_brace=force sp_getset_brace=force sp_before_dc=remove sp_after_dc=remove sp_not=remove sp_inv=remove sp_addr=remove sp_member=remove sp_deref=remove sp_sign=remove sp_incdec=remove sp_before_nl_cont=force sp_cond_colon=force sp_cond_question=force sp_case_label=force sp_cmt_cpp_start=force sp_endif_cmt=force sp_after_new=force sp_before_tr_emb_cmt=force sp_num_before_tr_emb_cmt=1 sp_balance_nested_parens=false cmt_sp_before_star_cont=0 cmt_sp_after_star_cont=1 # Newlines nl_max=2 nl_end_of_file_min=1 nl_func_var_def_blk=1 nl_start_of_file=remove nl_end_of_file=force nl_assign_brace=remove nl_fcall_brace=remove nl_enum_brace=remove nl_struct_brace=remove nl_union_brace=remove nl_if_brace=remove nl_brace_else=remove nl_elseif_brace=remove nl_else_brace=remove nl_else_if=remove nl_brace_finally=remove nl_finally_brace=remove nl_try_brace=remove nl_getset_brace=remove nl_for_brace=remove nl_catch_brace=remove nl_brace_catch=remove nl_while_brace=remove nl_using_brace=remove nl_brace_brace=ignore nl_do_brace=remove nl_brace_while=remove nl_switch_brace=remove nl_namespace_brace=remove nl_template_class=force nl_class_brace=remove nl_func_type_name=remove nl_func_type_name_class=remove nl_func_scope_name=remove nl_func_proto_type_name=remove nl_func_paren=remove nl_func_def_paren=remove nl_func_decl_end=remove nl_func_def_end=remove nl_func_decl_empty=remove nl_func_def_empty=remove nl_fdef_brace=force nl_return_expr=remove nl_collapse_empty_body=false nl_assign_leave_one_liners=true nl_class_leave_one_liners=true nl_enum_leave_one_liners=true nl_getset_leave_one_liners=true nl_func_leave_one_liners=false nl_if_leave_one_liners=false nl_multi_line_cond=true nl_multi_line_define=true nl_before_case=false nl_after_case=false nl_after_return=false nl_after_semicolon=true nl_after_brace_open=false nl_after_brace_open_cmt=false nl_after_vbrace_open=true nl_after_vbrace_open_empty=false nl_after_brace_close=false nl_after_vbrace_close=true nl_define_macro=true nl_squeeze_ifdef=false nl_ds_struct_enum_cmt=false nl_ds_struct_enum_close_brace=false nl_create_if_one_liner=false nl_create_for_one_liner=false nl_create_while_one_liner=false nl_after_multiline_comment=false ls_for_split_full=true ls_func_split_full=true eat_blanks_after_open_brace=false eat_blanks_before_close_brace=false # Positioning pos_arith=lead pos_assign=trail pos_bool=lead pos_compare=lead pos_conditional=lead pos_comma=trail pos_class_comma=trail pos_class_colon=lead # Modifications mod_full_brace_do=force mod_full_brace_for=remove mod_full_brace_if=remove mod_full_brace_while=remove mod_full_brace_using=remove mod_paren_on_return=remove mod_full_brace_nl=2 mod_full_brace_if_chain=true mod_pawn_semicolon=false mod_full_paren_if_bool=false mod_remove_extra_semicolon=true mod_sort_import=false mod_sort_using=false mod_sort_include=false mod_move_case_break=false mod_remove_empty_return=true # Preprocessor pp_indent=remove pp_space=force pp_space_count=1 pp_indent_at_level=false pp_region_indent_code=false pp_if_indent_code=false pp_define_at_level=false # nonstd cast attributes set cpp_cast nonstd # gettext macros set func_call_user _ N_ BoxFort-master/LICENSE0000644000175000017500000000212513603450524013401 0ustar sasasasaThe MIT License (MIT) Copyright © 2016 Franklin "Snaipe" Mathieu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BoxFort-master/README.md0000644000175000017500000000213713603450524013656 0ustar sasasasa# BoxFort [![Build Status](https://api.cirrus-ci.com/github/Snaipe/BoxFort.svg)](https://cirrus-ci.com/github/Snaipe/BoxFort) [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/diacritic/BoxFort/blob/master/LICENSE) [![Version](https://img.shields.io/badge/version-experimental-orange.svg?style=flat)](https://github.com/diacritic/BoxFort/releases) A simple, cross-platform sandboxing C library powering [Criterion][criterion]. **Warning**: This library is experimental. APIs may change without notice until Beta is hit. Use at your own risk. BoxFort provides a simple API to run user code in isolated processes. Although BoxFort provides some kind of security of the parent process from spawned sandboxes, a sandbox has by default the same system permissions and access than its parent, and is hence, without care, ill-fitted for security purposes. The main goal of this project **is not** security, but portable code isolation -- if you want complete system isolation, consider using properly configured containers. [criterion]: https://github.com/Snaipe/Criterion BoxFort-master/ci/0002755000175000017500000000000013603450524012771 5ustar sasasasaBoxFort-master/ci/cram-env.patch0000644000175000017500000000133613603450524015523 0ustar sasasasa--- _test.py.orig 2016-09-03 00:50:27.505527300 +0200 +++ "/c/Program Files/Python35/lib/site-packages/cram/_test.py" 2016-09-03 00:48:48.708932100 +0200 @@ -143,11 +143,15 @@ after.setdefault(pos, []).append(line) stdin.append(b('echo %s %s $?\n' % (usalt, i + 1))) + env = {k: v.decode('utf-8') if isinstance(v, bytes) else v for k, v in env.items()} + output, retcode = execute(shell + ['-'], stdin=b('').join(stdin), stdout=PIPE, stderr=STDOUT, env=env) if retcode == 80: return (refout, None, []) + output = output.replace(b'\r\n', b'\n').replace(b'\r', b'\n') + pos = -1 ret = 0 for i, line in enumerate(output[:-1].splitlines(True)): BoxFort-master/ci/isdir.py0000755000175000017500000000020113603450524014447 0ustar sasasasa#!/usr/bin/env python3 import os, sys os.chdir(os.environ['MESON_SOURCE_ROOT']) sys.exit(0 if os.path.isdir(sys.argv[1]) else 1) BoxFort-master/include/0002755000175000017500000000000013603450524014021 5ustar sasasasaBoxFort-master/include/boxfort.h0000644000175000017500000002035613603450524015661 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef BOXFORT_H_ #define BOXFORT_H_ #include #include #include #include #ifdef __cplusplus extern "C" { #endif #if !defined BXF_STATIC_LIB && !defined BXF_API # if defined _WIN32 || defined __CYGWIN__ # ifdef BXF_BUILDING_LIB # ifdef __GNUC__ # define BXF_API __attribute__((dllexport)) # else # define BXF_API __declspec(dllexport) # endif # else # ifdef __GNUC__ # define BXF_API __attribute__((dllimport)) # else # define BXF_API __declspec(dllimport) # endif # endif # else # if __GNUC__ >= 4 # define BXF_API __attribute__((visibility("default"))) # else # define BXF_API # endif # endif #elif !defined BXF_API # define BXF_API #endif /* Arena API */ /** * The opaque handle type representing a BoxFort memory arena. */ typedef struct bxf_arena_s *bxf_arena; enum { /** * Allow the arena to be resized during allocations. */ BXF_ARENA_RESIZE = (1 << 0), /** * Memory may be reclaimed with bxf_arena_free. */ BXF_ARENA_DYNAMIC = (1 << 1), /** * If BXF_ARENA_RESIZE is specified, allow the arena to be moved in * memory. * * All allocation operations invalidate virtual addresses inside the arena. */ BXF_ARENA_MAYMOVE = (1 << 2), /** * Map 1:1 the arena in the sandbox instance, exactly where the arena * exists in the parent's address space. * * All virtual pointers used by the parent are kept valid in the sandbox * instance. */ BXF_ARENA_IDENTITY = (1 << 3), /** * The arena in the sandbox instance is mapped read-only. All write * accesses to memory allocated inside the arena result in a segmentation * fault. */ BXF_ARENA_IMMUTABLE = (1 << 4), /** * The arena in the parent is not unmapped upon termination. All related * shared memory resources are still cleaned up. * * This is necessary for special languages semantics like C++ destructors * of static objects that assume that the heap is still mapped before * a call free(). */ BXF_ARENA_KEEPMAPPED = (1 << 5), }; typedef intptr_t bxf_ptr; typedef int (bxf_arena_fn)(void *, size_t, void *); BXF_API int bxf_arena_init(size_t initial, int flags, bxf_arena *arena); BXF_API int bxf_arena_copy(bxf_arena orig, int flags, bxf_arena *arena); BXF_API int bxf_arena_term(bxf_arena *arena); BXF_API bxf_ptr bxf_arena_alloc(bxf_arena *arena, size_t size); BXF_API bxf_ptr bxf_arena_realloc(bxf_arena *arena, bxf_ptr ptr, size_t newsize); BXF_API int bxf_arena_grow(bxf_arena *arena, bxf_ptr ptr, size_t newsize); BXF_API int bxf_arena_free(bxf_arena *arena, bxf_ptr ptr); BXF_API int bxf_arena_iter(bxf_arena arena, bxf_arena_fn *fn, void *user); BXF_API void *bxf_arena_ptr(bxf_arena arena, bxf_ptr ptr); /* Resource context API */ #ifdef _WIN32 typedef void *bxf_fhandle; #else typedef int bxf_fhandle; #endif typedef struct bxf_context_s *bxf_context; BXF_API int bxf_context_init(bxf_context *ctx); BXF_API int bxf_context_term(bxf_context ctx); BXF_API int bxf_context_addstatic(bxf_context ctx, const void *ptr, size_t size); BXF_API int bxf_context_addarena(bxf_context ctx, bxf_arena arena); BXF_API int bxf_context_addobject(bxf_context ctx, const char *name, const void *ptr, size_t size); BXF_API int bxf_context_getobject(bxf_context ctx, const char *name, void **ptr); BXF_API int bxf_context_addaddr(bxf_context ctx, const char *name, const void *addr); BXF_API int bxf_context_getaddr(bxf_context ctx, const char *name, void **addr); BXF_API int bxf_context_addfnaddr(bxf_context ctx, const char *name, void (*fn)(void)); BXF_API int bxf_context_getfnaddr(bxf_context ctx, const char *name, void(**fn)(void)); BXF_API int bxf_context_addfhandle(bxf_context ctx, bxf_fhandle hndl); BXF_API int bxf_context_addfile(bxf_context ctx, const char *name, FILE *file); BXF_API int bxf_context_getfile(bxf_context ctx, const char *name, FILE **file); BXF_API bxf_context bxf_context_current(void); /* Sandbox API */ typedef unsigned long long bxf_pid; typedef int (bxf_fn)(void); struct bxf_quotas { size_t memory; size_t subprocesses; size_t files; double runtime; }; struct bxf_inheritance { unsigned files : 1; unsigned data : 1; bxf_context context; }; enum bxf_debugger { BXF_DBG_NONE, /* Do not debug the sandbox */ BXF_DBG_GDB, /* Spawn with gdbserver */ BXF_DBG_LLDB, /* Spawn with lldb-server */ BXF_DBG_WINDBG, /* Spawn with windbg (Windows only) */ }; #if defined (__clang__) # define BXF_DBG_NATIVE BXF_DBG_LLDB #elif defined (__GNUC__) # define BXF_DBG_NATIVE BXF_DBG_GDB #elif defined (_WIN32) # define BXF_DBG_NATIVE BXF_DBG_WINDBG #endif struct bxf_debug { enum bxf_debugger debugger; int tcp; }; #define BXFI_SANDBOX_FIELDS \ int suspended; \ struct bxf_quotas quotas; \ struct bxf_quotas iquotas; \ struct bxf_inheritance inherit; \ struct bxf_debug debug; struct bxf_sandbox_s { BXFI_SANDBOX_FIELDS }; typedef const struct bxf_sandbox_s bxf_sandbox; struct bxf_instance_s { bxf_sandbox *sandbox; bxf_pid pid; volatile struct { int signal; int exit; int alive; int stopped; int timed_out; } status; volatile struct { uint64_t start; uint64_t end; uint64_t elapsed; } time; void *user; }; typedef const struct bxf_instance_s bxf_instance; typedef void (bxf_callback)(bxf_instance *); typedef int (bxf_preexec)(bxf_instance *); typedef void (bxf_dtor)(bxf_instance *, void *); struct bxf_spawn_params_s { int bxfi_sentinel_; /* Reserved */ bxf_fn *fn; bxf_preexec *preexec; void *user; bxf_dtor *user_dtor; bxf_callback *callback; BXFI_SANDBOX_FIELDS }; typedef const struct bxf_spawn_params_s *bxf_spawn_params; struct bxf_start_params_s { int bxfi_sentinel_; /* Reserved */ bxf_fn *fn; bxf_preexec *preexec; void *user; bxf_dtor *user_dtor; bxf_callback *callback; }; #define BXF_FOREVER INFINITY typedef const struct bxf_start_params_s *bxf_start_params; #define bxf_start(Instance, Sandbox, ...) \ (bxf_start_struct((Instance), \ (Sandbox), \ &(struct bxf_start_params_s) { .bxfi_sentinel_ = 0, __VA_ARGS__ })) BXF_API int bxf_start_struct(bxf_instance **instance, bxf_sandbox *sandbox, bxf_start_params params); BXF_API int bxf_term(bxf_instance *instance); BXF_API int bxf_wait(bxf_instance *instance, double timeout); #define bxf_spawn(Instance, ...) \ (bxf_spawn_struct((Instance), \ &(struct bxf_spawn_params_s) { .bxfi_sentinel_ = 0, __VA_ARGS__ })) BXF_API int bxf_spawn_struct(bxf_instance **instance, bxf_spawn_params params); #define bxf_run(...) \ (bxf_run_struct( \ &(struct bxf_spawn_params_s) { .bxfi_sentinel_ = 0, __VA_ARGS__ })) BXF_API int bxf_run_struct(bxf_spawn_params params); BXF_API void bxf_suspend(bxf_instance *instance); BXF_API void bxf_resume(bxf_instance *instance); #ifdef __cplusplus } #endif #endif /* !BOXFORT_H_ */ BoxFort-master/meson.build0000644000175000017500000001172113603450524014540 0ustar sasasasaproject('boxfort', 'c', meson_version : '>= 0.48.0', license : 'MIT', version : '0.0.1', default_options : ['c_std=c99', 'warning_level=3', 'b_lundef=false']) # standard install directories prefix = get_option('prefix') # Helper scripts auxdir = join_paths(meson.current_source_dir(), 'ci') isdir = join_paths(auxdir, 'isdir.py') python3 = find_program('python3') git = find_program('git', required: false) # Get the right version is_git_repo = run_command([isdir, '.git']).returncode() == 0 version = 'v' + meson.project_version() if git.found() and is_git_repo version = run_command([git.path(), 'describe', '--dirty', '--tags']).stdout().strip() branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip() if branch != 'master' version = '@0@ (@1@)'.format(version, branch) endif endif cc = meson.get_compiler('c') add_project_arguments( cc.get_supported_arguments([ '-Wno-unused-parameter', '-Wno-unused-value', '-fvisibility=hidden', # MSVC-specific stuff '/SAFESEH:NO', '/source-charset:utf-8', ]), '-DBXF_BUILDING_LIB', '-D_GNU_SOURCE', language: ['c', 'cpp']) if host_machine.system() == 'windows' add_project_arguments( '-DVC_EXTRALEAN', '-DWIN32_LEAN_AND_MEAN', '-D_CRT_SECURE_NO_WARNINGS', '-D_WIN32_WINNT=0x600', language: ['c', 'cpp']) endif boxfort_includedir = include_directories( 'include', 'src', ) threads = dependency('threads') # optional platform-dependent standard libs librt = cc.find_library('rt', required: false) libm = cc.find_library('m', required: false) config = configuration_data() config.set('package', meson.project_name()) config.set('version', version) os = host_machine.system() arch = host_machine.cpu_family() mangling = 'none' if cc.symbols_have_underscore_prefix() mangling = 'leading-underscore' endif if arch == 'x86' bitness = 32 elif arch == 'x86_64' bitness = 64 elif arch == 'arm' bitness = 32 elif arch == 'aarch64' bitness = 64 else error('Architecture "@0@" is not supported.'.format(arch)) endif if get_option('arena_reopen_shm') config.set('BXF_ARENA_REOPEN_SHM', 1) endif if get_option('arena_file_backed') config.set('BXF_ARENA_FILE_BACKED', 1) endif binfmt = 'elf' os_family = 'posix' if os == 'windows' binfmt = 'pe' os_family = 'windows' elif os == 'darwin' binfmt = 'mach-o' # This is mandatory because OS X fails silently when mmap'ing an inherited # shm file descriptor config.set('BXF_ARENA_REOPEN_SHM', 1) config.set('BXF_ARENA_FILE_BACKED', 1) endif config.set('BXF_EXE_FORMAT', binfmt) config.set('BXF_EXE_FMT_@0@'.format(binfmt.to_upper().underscorify()), 1) config.set('BXF_OS_FAMILY', os_family) config.set('BXF_ARCH', '"' + arch + '"') config.set('BXF_ARCH_@0@'.format(arch), 1) config.set('BXF_MANGLING', mangling) config.set('BXF_BITS', bitness) checks = [ {'fn': 'clock_gettime'}, {'fn': 'gettimeofday'}, {'fn': 'mincore'}, {'fn': 'prctl'}, {'fn': 'shm_open'}, # some platforms define mincore with an unsigned vector { 'fn': 'mincore', 'proto': 'int _(void *, size_t, unsigned char *)', 'headers': ['unistd.h', 'sys/mman.h'], 'var': 'HAVE_UNSIGNED_MINCORE_VEC', }, {'sym': 'PR_SET_PDEATHSIG', 'header': 'sys/prctl.h'}, {'sym': 'CLOCK_MONOTONIC_RAW', 'header': 'time.h'}, {'sym': 'environ', 'header': 'unistd.h'}, ] if binfmt == 'elf' checks += [ {'sym': '_r_debug', 'header': 'link.h'}, {'sym': '_DYNAMIC', 'header': 'link.h'}, ] endif check_prelude = ''' #define _GNU_SOURCE ''' prototype_check = check_prelude + ''' @0@ typedef @1@; static _ *check = @2@; ''' foreach check : checks chk_prefix = check.get('prefix', '') if chk_prefix != '' chk_prefix = chk_prefix + '_' endif result = false if check.has_key('proto') includes = '' foreach hdr : check.get('headers') includes += '#include <@0@>\n'.format(hdr) endforeach result = cc.compiles(prototype_check.format(includes, check.get('proto'), check.get('fn'))) elif check.has_key('fn') name = check.get('fn') libs = ['c'] if librt.found() libs += 'rt' endif if libm.found() libs += 'm' endif if check.has_key('libs') libs += check.get('libs') endif args = [] foreach lib : libs args += '-l' + lib endforeach result = cc.has_function(name, prefix: check_prelude, args: args) elif check.has_key('sym') name = check.get('sym') result = cc.has_header_symbol(check.get('header'), name, prefix: check_prelude) elif check.has_key('hdr') name = check.get('hdr') result = cc.has_header(name) endif if check.has_key('var') name = check.get('var') else name = 'HAVE_@1@@0@'.format(name.to_upper(), chk_prefix.to_upper()) endif config.set(name, result) endforeach api = files('include/boxfort.h') if not meson.is_subproject() install_headers(api) endif includedir = include_directories( 'include', 'src', ) if target_machine.system() == 'windows' config.set10('HAVE_WIN32_THREADS', true) else config.set10('HAVE_PTHREADS', true) endif subdir('src') subdir('sample') subdir('test') BoxFort-master/meson_options.txt0000644000175000017500000000046513603450524016036 0ustar sasasasaoption('arena_reopen_shm', type: 'boolean', value: false, description: 'Reopen shared memory file in worker process rather than just inherit a file descriptor') option('arena_file_backed', type: 'boolean', value: false, description: 'Use a file in tempfs to store the arena rather than using shm facilities') BoxFort-master/sample/0002755000175000017500000000000013603450524013657 5ustar sasasasaBoxFort-master/sample/callback.c0000644000175000017500000000106213603450524015554 0ustar sasasasa#include #include #include #include #include "boxfort.h" #define _assert(Cond) do { if (!(Cond)) abort(); } while (0) #ifdef _WIN32 # define EXPORT __declspec(dllexport) #else # define EXPORT #endif static volatile int called; static int child(void) { return 5; } static void callback(bxf_instance *instance) { printf("Child exited with code %d\n", instance->status.exit); called = 1; } EXPORT int main(void) { _assert(!bxf_run(child, .callback = callback)); while (!called); return 0; } BoxFort-master/sample/context.c0000644000175000017500000000265013603450524015510 0ustar sasasasa#include #include #include #include #include "boxfort.h" #define _assert(Cond) do { if (!(Cond)) abort(); } while (0) #ifdef _WIN32 # define EXPORT __declspec(dllexport) #else # define EXPORT #endif static int *my_int; static int child(void) { bxf_context ctx = bxf_context_current(); long *my_long = NULL; bxf_context_getobject(ctx, "long_id", (void **)&my_long); printf("my_int = %d\n", *my_int); printf("my_long = %ld\n", *my_long); return 0; } EXPORT int main(void) { bxf_context ctx; _assert(!bxf_context_init(&ctx)); /* The value of the `my_int` global variable shall be inherited */ _assert(!bxf_context_addstatic(ctx, &my_int, sizeof (my_int))); /* We create an arena that shall be mapped 1:1 */ bxf_arena arena; _assert(!bxf_arena_init(0, BXF_ARENA_IDENTITY, &arena)); /* The newly created arena shall also be inherited. */ _assert(!bxf_context_addarena(ctx, arena)); bxf_ptr intp = bxf_arena_alloc(&arena, sizeof (int)); _assert(intp > 0); my_int = bxf_arena_ptr(arena, intp); *my_int = 42; long my_long = 24; _assert(!bxf_context_addobject(ctx, "long_id", &my_long, sizeof (my_long))); /* We run the child function with the created context */ _assert(!bxf_run(child, .inherit.context = ctx)); _assert(!bxf_arena_term(&arena)); _assert(!bxf_context_term(ctx)); return 0; } BoxFort-master/sample/meson.build0000644000175000017500000000052413603450524016020 0ustar sasasasasamples = [ 'nested.c', 'callback.c', 'timeout.c', 'context.c', ] foreach sample : samples e = executable(sample + '.bin', sample, include_directories: includedir, dependencies: [libm], link_with: libboxfort, c_args: [ cc.get_supported_arguments([ '-fvisibility=default', ]) ]) test(sample, e) endforeach BoxFort-master/sample/nested.c0000644000175000017500000000102213603450524015276 0ustar sasasasa#include #include #include #include #include "boxfort.h" #define _assert(Cond) do { if (!(Cond)) abort(); } while (0) #ifdef _WIN32 # define EXPORT __declspec(dllexport) #else # define EXPORT #endif int second(void) { printf("I am a nested worker!\n"); fflush(stdout); return 0; } int first(void) { printf("I am a worker!\n"); fflush(stdout); _assert(!bxf_run(second)); return 0; } EXPORT int main(void) { _assert(!bxf_run(first)); return 0; } BoxFort-master/sample/timeout.c0000644000175000017500000000117113603450524015507 0ustar sasasasa#include #include #include #include #include "boxfort.h" #define _assert(Cond) do { if (!(Cond)) abort(); } while (0) #ifdef _WIN32 # define EXPORT __declspec(dllexport) #else # define EXPORT #endif static int child(void) { for (;;); return 0; } EXPORT int main(void) { bxf_instance *box; _assert(!bxf_spawn(&box, child, .quotas.runtime = 2.0)); bxf_wait(box, 1.0); printf("Wait timed out after 1 second\n"); bxf_wait(box, BXF_FOREVER); printf("Process killed after %.1f seconds\n", box->time.elapsed / 1000000000.); bxf_term(box); return 0; } BoxFort-master/src/0002755000175000017500000000000013603450524013165 5ustar sasasasaBoxFort-master/src/addr.c0000644000175000017500000000356513603450524014252 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include "addr.h" #include "exe.h" int bxfi_normalize_addr(const void *addr, struct bxfi_addr *to) { size_t seg; const char *name; uintptr_t slide = bxfi_slide_from_addr(addr, &name, &seg); if (slide == (uintptr_t) -1) return -errno; to->addr = (char *) addr - slide; to->soname = name; to->seg = seg; return 0; } void *bxfi_denormalize_addr(struct bxfi_addr *addr) { uintptr_t slide = bxfi_slide_from_name(addr->soname, addr->seg); if (slide == (uintptr_t) -1) return NULL; return (char *) addr->addr + slide; } void bxfi_addr_term(struct bxfi_addr *addr) { bxfi_lib_name_term(addr->soname); } BoxFort-master/src/addr.h0000644000175000017500000000340113603450524014244 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef ADDR_H_ #define ADDR_H_ #include "boxfort.h" #include "common.h" struct bxfi_addr { const char *soname; const void *addr; size_t seg; }; int bxfi_normalize_addr(const void *addr, struct bxfi_addr *to); void *bxfi_denormalize_addr(struct bxfi_addr *addr); void bxfi_addr_term(struct bxfi_addr *addr); static inline int bxfi_normalize_fnaddr(bxf_fn *addr, struct bxfi_addr *to) { return bxfi_normalize_addr(nonstd (void *) addr, to); } static inline bxf_fn *bxfi_denormalize_fnaddr(struct bxfi_addr *addr) { return nonstd (bxf_fn *) bxfi_denormalize_addr(addr); } #endif /* !ADDR_H_ */ BoxFort-master/src/arena.c0000644000175000017500000004576413603450524014435 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifdef _WIN32 # define _CRT_RAND_S #endif #include #include #include #include #include #include "arena.h" #include "boxfort.h" #include "common.h" #include "timestamp.h" #ifndef _WIN32 # include # define __BSD_VISIBLE 1 # include # undef __BSD_VISIBLE # include # include #endif #define GROWTH_RATIO (1.61) #define MAP_RETRIES 10 #if BXF_BITS == 32 static void *mmap_base = (void *) 0x40000000; static void *mmap_max = (void *) 0x80000000; static intptr_t mmap_off = (intptr_t) 1 << 16; static intptr_t mmap_off_mask = 0x3fff; #elif BXF_BITS == 64 /* On Linux it seems that you cannot map > 48-bit addresses */ static void *mmap_base = (void *) 0x200000000000; static void *mmap_max = (void *) 0x7f0000000000; static intptr_t mmap_off = (intptr_t) 1 << 24; static intptr_t mmap_off_mask = 0x3fffff; #else # error Platform not supported #endif static unsigned int mmap_seed; static inline void *ptr_add(void *ptr, size_t off) { return (char *) ptr + off; } #define chunk_next(Chunk) \ ((struct bxfi_arena_chunk *) ((Chunk)->next ? ptr_add(*arena, \ (Chunk)->next) : NULL)) #define get_free_chunks(arena) (ptr_add(*arena, (*arena)->free_chunks)) static int page_mapped(void *addr) { #ifdef _WIN32 MEMORY_BASIC_INFORMATION mbi; memset(&mbi, 0, sizeof (mbi)); if (VirtualQuery(addr, &mbi, sizeof (mbi))) if (mbi.State != MEM_FREE) return 1; return 0; #elif defined (HAVE_MINCORE) && !defined (__APPLE__) /* mincore is somewhat broken on OS X, for some reason. */ # if defined(HAVE_UNSIGNED_MINCORE_VEC) unsigned # endif char p; errno = EAGAIN; while (errno == EAGAIN) { if (!mincore(addr, pagesize(), &p)) return 1; if (errno == ENOMEM) return 0; } bug("mincore(2) returned an unexpected error"); #else if (!msync(addr, pagesize(), MS_ASYNC)) return 1; if (errno == ENOMEM) return 0; bug("msync(2) returned an unexpected error"); #endif } int bxf_arena_init(size_t initial, int flags, bxf_arena *arena) { initial = align2_up(initial, PAGE_SIZE); if (!initial) initial = 32 * PAGE_SIZE; #ifdef _WIN32 SECURITY_ATTRIBUTES inherit = { .nLength = sizeof (SECURITY_ATTRIBUTES), .bInheritHandle = TRUE, }; /* Consider available commit limit for possible max heap size */ MEMORYSTATUSEX mem = { .dwLength = sizeof (mem) }; if (!GlobalMemoryStatusEx(&mem)) return -ENOMEM; LARGE_INTEGER sz = { .QuadPart = mem.ullAvailPageFile }; HANDLE hndl = CreateFileMapping(INVALID_HANDLE_VALUE, &inherit, PAGE_READWRITE | SEC_RESERVE, sz.HighPart, sz.LowPart, NULL); if (!hndl) return -EINVAL; if (!mmap_seed) mmap_seed = bxfi_timestamp_monotonic(); intptr_t r; struct bxf_arena_s *a; int tries = 0; for (tries = 0; tries < MAP_RETRIES;) { rand_s(&mmap_seed); r = mmap_seed; r &= mmap_off_mask; void *base = ptr_add(mmap_base, r * mmap_off); if (base > mmap_max || base < mmap_base) continue; for (void *addr = base; addr < ptr_add(base, initial); addr = ptr_add(addr, PAGE_SIZE)) { if (page_mapped(addr)) goto retry; } a = MapViewOfFileEx(hndl, FILE_MAP_WRITE, 0, 0, initial, base); if (!a) goto error; if (!VirtualAlloc(a, initial, MEM_COMMIT, PAGE_READWRITE)) goto error; if ((void *) a < mmap_max && (void *) a > mmap_base) break; UnmapViewOfFile(a); retry: ; ++tries; } if (tries == MAP_RETRIES) goto error; #else char name[BXFI_ARENA_NAME_SIZE]; /* Some platforms (like OS X) have the *great* idea of silently failing all mapping operations on inherited shm file descriptors. We have to provide a fallback for these dipshits by reopening the shm file in the child instance. */ # ifdef BXF_ARENA_REOPEN_SHM static size_t count; size_t id = __sync_fetch_and_add(&count, 1); # ifdef BXF_ARENA_FILE_BACKED snprintf(name, sizeof (name), "/tmp/bxf_arena_%d_%zu", getpid(), id); # else snprintf(name, sizeof (name), "/bxf_arena_%d_%zu", getpid(), id); # endif # else # ifdef BXF_ARENA_FILE_BACKED snprintf(name, sizeof (name), "/tmp/bxf_arena_%d", getpid()); # else snprintf(name, sizeof (name), "/bxf_arena_%d", getpid()); # endif # endif # ifdef BXF_ARENA_FILE_BACKED int fd = open(name, O_CREAT | O_RDWR | O_EXCL, 0600); # else int fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600); # endif if (fd == -1) goto error; # ifndef BXF_ARENA_REOPEN_SHM # ifdef BXF_ARENA_FILE_BACKED unlink(name); # else shm_unlink(name); # endif # endif if (ftruncate(fd, initial) == -1) goto error; if (!mmap_seed) mmap_seed = bxfi_timestamp_monotonic(); intptr_t r; struct bxf_arena_s *a; int tries = 0; for (tries = 0; tries < MAP_RETRIES;) { r = rand_r(&mmap_seed) & mmap_off_mask; void *base = ptr_add(mmap_base, r * mmap_off); if (base > mmap_max || base < mmap_base) continue; for (void *addr = base; addr < ptr_add(base, initial); addr = ptr_add(addr, PAGE_SIZE)) { if (page_mapped(addr)) goto retry; } a = mmap(base, initial, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0); if (a == MAP_FAILED) goto error; if ((void *) a < mmap_max && (void *) a > mmap_base) break; munmap(a, initial); retry: ; ++tries; } if (tries == MAP_RETRIES) goto error; #endif a->flags = flags; a->size = initial; a->addr = a; a->free_chunks = sizeof (*a); #ifdef BXF_ARENA_REOPEN_SHM strcpy(a->name, name); #endif #ifdef _WIN32 a->handle = hndl; #else a->handle = fd; #endif struct bxfi_arena_chunk *first = ptr_add(a, a->free_chunks); *first = (struct bxfi_arena_chunk) { .size = initial - sizeof (*a), }; *arena = a; return 0; error:; #ifdef _WIN32 CloseHandle(hndl); return -ENOMEM; #else int errnum = errno; if (fd != -1) { # ifdef BXF_ARENA_REOPEN_SHM # ifdef BXF_ARENA_FILE_BACKED unlink(name); # else shm_unlink(name); # endif # endif close(fd); } return -errnum; #endif } int bxfi_arena_inherit(bxf_fhandle hndl, int flags, bxf_arena *arena) { void *base = NULL; if (flags & BXF_ARENA_IDENTITY) base = *arena; #ifdef _WIN32 DWORD prot; if (flags & BXF_ARENA_IMMUTABLE) prot = FILE_MAP_READ; else prot = FILE_MAP_COPY; struct bxf_arena_s *a = MapViewOfFile(hndl, prot, 0, 0, sizeof (*a)); if (!a) return -ENOMEM; size_t size = a->size; UnmapViewOfFile(a); a = MapViewOfFileEx(hndl, prot, 0, 0, size, base); if (!a) return -ENOMEM; #else int mmapfl = MAP_PRIVATE; if (flags & BXF_ARENA_IDENTITY) mmapfl |= MAP_FIXED; int prot = PROT_READ; if (!(flags & BXF_ARENA_IMMUTABLE)) prot |= PROT_WRITE; struct bxf_arena_s *a = mmap(NULL, sizeof (*a), prot, MAP_PRIVATE, hndl, 0); if (a == MAP_FAILED) return -errno; size_t size = a->size; munmap(a, sizeof (*a)); a = mmap(base, size, prot, mmapfl, hndl, 0); if (a == MAP_FAILED) return -errno; #endif *arena = a; return 0; } int bxf_arena_copy(bxf_arena orig, int flags, bxf_arena *arena) { int rc = bxf_arena_init(orig->size, flags, arena); if (rc > 0) { memcpy(*arena + 1, orig + 1, orig->size - sizeof (orig)); (*arena)->free_chunks = orig->free_chunks; } return rc; } int bxf_arena_term(bxf_arena *arena) { #ifdef _WIN32 CloseHandle((*arena)->handle); if (!((*arena)->flags & BXF_ARENA_KEEPMAPPED)) UnmapViewOfFile(*arena); #else # ifdef BXF_ARENA_REOPEN_SHM # ifdef BXF_ARENA_FILE_BACKED unlink((*arena)->name); # else shm_unlink((*arena)->name); # endif # endif close((*arena)->handle); if (!((*arena)->flags & BXF_ARENA_KEEPMAPPED)) munmap(*arena, (*arena)->size); #endif *arena = NULL; return 0; } static inline int arena_valid(bxf_arena arena) { return arena && arena->addr == arena; } static int arena_resize(bxf_arena *arena, size_t newsize) { size_t size = (*arena)->size; #ifdef _WIN32 void *base = ptr_add(*arena, (*arena)->size); LARGE_INTEGER off = { .QuadPart = (*arena)->size }; void *addr = MapViewOfFileEx((*arena)->handle, FILE_MAP_WRITE, off.HighPart, off.LowPart, newsize - size, base); if (addr != base) { if (!((*arena)->flags & BXF_ARENA_MAYMOVE)) return -ENOMEM; FlushViewOfFile(*arena, size); struct bxf_arena_s *a = MapViewOfFile((*arena)->handle, FILE_MAP_WRITE, 0, 0, newsize); if (!a) return -ENOMEM; addr = ptr_add(a, size); a->addr = a; UnmapViewOfFile(*arena); *arena = a; } if (!VirtualAlloc(addr, newsize - size, MEM_COMMIT, PAGE_READWRITE)) return -ENOMEM; return 0; #else if (ftruncate((*arena)->handle, newsize) < 0) return -ENOMEM; # if defined (HAVE_MREMAP) int flags = (*arena)->flags & BXF_ARENA_MAYMOVE ? MREMAP_MAYMOVE : 0; struct bxf_arena_s *a = mremap(*arena, (*arena)->size, newsize, flags); if (a == MAP_FAILED) return -errno; a->addr = a; *arena = a; # else size_t remsz = newsize - (*arena)->size; char *addr_hi = ptr_add(*arena, (*arena)->size); int move = 0; for (char *addr = addr_hi; remsz; remsz -= PAGE_SIZE, addr += PAGE_SIZE) { if (page_mapped(addr)) { move = 1; break; } } if (move) { if (!((*arena)->flags & BXF_ARENA_MAYMOVE)) return -ENOMEM; msync(*arena, (*arena)->size, MS_SYNC); struct bxf_arena_s *a = mmap(*arena, newsize, PROT_READ | PROT_WRITE, MAP_SHARED, (*arena)->handle, 0); if (a == MAP_FAILED) return -ENOMEM; a->addr = a; munmap(*arena, (*arena)->size); *arena = a; } else { size_t remsz = newsize - (*arena)->size; void *raddr = mmap(addr_hi, remsz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, (*arena)->handle, (*arena)->size); if (raddr == MAP_FAILED) return -errno; } # endif /* Extend the free chunk at the end of the arena. If it's not free, then initialize a new free chunk. */ struct bxfi_arena_chunk *last; for (last = get_free_chunks(arena); last; last = chunk_next(last)) { if (ptr_add(last, last->size) == ptr_add(*arena, size)) { break; } } if (last) { last->size += newsize - size; } else { last->next = (intptr_t) size; last = ptr_add(*arena, size); *last = (struct bxfi_arena_chunk) { .size = newsize - size, }; } (*arena)->size = newsize; return 0; #endif return -ENOMEM; } bxf_ptr bxf_arena_alloc(bxf_arena *arena, size_t size) { if (!arena_valid(*arena)) return -EINVAL; size = align2_up(size + sizeof (struct bxfi_arena_chunk), sizeof (void *)); struct bxfi_arena_chunk *best = NULL; intptr_t *nptr_best = NULL; intptr_t *nptr; find_chunk: nptr = &(*arena)->free_chunks; for (struct bxfi_arena_chunk *c = get_free_chunks(arena); c; c = chunk_next(c)) { if ((c->size >= size && (!best || best->size > c->size)) || (!c->next && !best)) { best = c; nptr_best = nptr; } if (c->size == size) break; nptr = &c->next; } size_t next_off_end = (size_t) ((intptr_t) best + size - (intptr_t) *arena + sizeof (*best)); if (next_off_end > (*arena)->size || best->size < size) { if (!((*arena)->flags & BXF_ARENA_RESIZE)) return -ENOMEM; /* size - best->size is the extra space we need, but we need to take the size of the next chunk header into account when calculating the required space. */ size_t oksize = (*arena)->size + size - best->size + sizeof (*best); size_t newsize = (*arena)->size; while (newsize < oksize) newsize *= GROWTH_RATIO; newsize = align2_up(newsize, PAGE_SIZE); int rc = arena_resize(arena, newsize); if (rc < 0) return rc; /* Everything was invalidated, because the arena might have moved. Just give up and retry. */ goto find_chunk; } size_t remsz = best->size - size; best->size = size; struct bxfi_arena_chunk *next = ptr_add(best, best->size); *next = (struct bxfi_arena_chunk) { .size = remsz, .next = best->next, }; *nptr_best = (intptr_t) next - (intptr_t) *arena; best->addr = (intptr_t) (best + 1) - (intptr_t) *arena; return best->addr; } bxf_ptr bxf_arena_realloc(bxf_arena *arena, bxf_ptr ptr, size_t size) { if (!arena_valid(*arena)) return -EINVAL; if (!ptr) return bxf_arena_alloc(arena, size); void *p = ptr_add(*arena, ptr); if (p <= ptr_add(*arena, sizeof (struct bxfi_arena_chunk)) || p >= ptr_add(*arena, (*arena)->size)) return -EFAULT; struct bxfi_arena_chunk *chunk = p; --chunk; if (ptr_add(*arena, chunk->addr) != p) return -EFAULT; int rc = bxf_arena_grow(arena, ptr, size); if (rc == -ENOMEM) { /* If we can't call free, give up and let the user call alloc */ if (!((*arena)->flags & BXF_ARENA_DYNAMIC)) return rc; rc = bxf_arena_alloc(arena, size); if (rc > 0) { void *np = ptr_add(*arena, rc); memcpy(np, p, chunk->size); bxf_arena_free(arena, ptr); } } return rc; } int bxf_arena_grow(bxf_arena *arena, bxf_ptr p, size_t size) { if (!arena_valid(*arena)) return -EINVAL; void *ptr = ptr_add(*arena, p); size = align2_up(size + sizeof (struct bxfi_arena_chunk), sizeof (void *)); if (!ptr || ptr <= ptr_add(*arena, sizeof (struct bxfi_arena_chunk)) || ptr >= ptr_add(*arena, (*arena)->size)) return -EFAULT; struct bxfi_arena_chunk *chunk = ptr; --chunk; if (ptr_add(*arena, chunk->addr) != ptr) return -EFAULT; struct bxfi_arena_chunk *next = ptr_add(chunk, chunk->size); if (next->addr) return -ENOMEM; if (ptr_add(next, size) > ptr_add(*arena, (*arena)->size)) { if (!((*arena)->flags & BXF_ARENA_RESIZE)) return -ENOMEM; size_t oksize = (*arena)->size + size - next->size + sizeof (*next); size_t newsize = (*arena)->size; while (newsize < oksize) newsize *= GROWTH_RATIO; size_t oldsize = (*arena)->size; intptr_t off = (intptr_t) *arena; newsize = align2_up(newsize, PAGE_SIZE); int rc = arena_resize(arena, newsize); if (rc < 0) return rc; off = (intptr_t) *arena - off; ptr = ptr_add(ptr, off); chunk = ptr_add(chunk, off); next = ptr_add(next, off); next->size += newsize - oldsize; } if (next->size < size - chunk->size) return -ENOMEM; /* Remove the next chunk from the free list */ intptr_t *nptr = &(*arena)->free_chunks; for (struct bxfi_arena_chunk *c = get_free_chunks(arena); c; c = chunk_next(c)) { if (c == next) break; nptr = &c->next; } *nptr = next->next; chunk->size += next->size; /* If there is enough space to fit another chunk at the end of the newly * merged block, do so */ size_t asize = align2_down(chunk->size, sizeof (void *)); if (chunk->size - asize >= align2_up(sizeof (*chunk) + 1, sizeof (void *)) && asize >= size) { struct bxfi_arena_chunk *next = ptr_add(chunk, size); *next = (struct bxfi_arena_chunk) { .next = *nptr, }; *nptr = (intptr_t) next - (intptr_t) *arena; } return 0; } int bxf_arena_free(bxf_arena *arena, bxf_ptr p) { if (!arena_valid(*arena)) return -EINVAL; if (!((*arena)->flags & BXF_ARENA_DYNAMIC)) return -ENOTSUP; if (!p) return 0; void *ptr = ptr_add(*arena, p); if (ptr <= ptr_add(*arena, sizeof (struct bxfi_arena_chunk)) || ptr >= ptr_add(*arena, (*arena)->size)) return -EFAULT; struct bxfi_arena_chunk *chunk = ptr; --chunk; if (ptr_add(*arena, chunk->addr) != ptr) return -EFAULT; intptr_t *nptr = &(*arena)->free_chunks; struct bxfi_arena_chunk *prev = NULL; for (struct bxfi_arena_chunk *c = get_free_chunks(arena); c; c = chunk_next(c)) { if (c > chunk) break; nptr = &c->next; prev = c; } chunk->next = *nptr; *nptr = (intptr_t) chunk - (intptr_t) *arena; if (prev) { prev->size += chunk->size; prev->next = chunk->next; chunk = prev; } if (chunk->next) { chunk->size += chunk_next(chunk)->size; chunk->next = chunk->next; } chunk->addr = 0; return 0; } int bxf_arena_iter(bxf_arena arena, bxf_arena_fn *fn, void *user) { struct bxfi_arena_chunk *c = (void *) (arena + 1); for (; (void *) c < ptr_add(arena, arena->size); c = ptr_add(c, c->size)) { if (c->addr) { int rc = fn(ptr_add(arena, c->addr), c->size - sizeof (*c), user); if (rc) return rc; } } return 0; } void *bxf_arena_ptr(bxf_arena arena, bxf_ptr ptr) { return ptr_add(arena, ptr); } BoxFort-master/src/arena.h0000644000175000017500000000403613603450524014425 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef ARENA_H_ #define ARENA_H_ #ifdef _WIN32 # include #endif #include #include "boxfort.h" #include "config.h" struct bxfi_arena_chunk { intptr_t addr; size_t size; intptr_t next; }; #ifdef BXF_ARENA_REOPEN_SHM # ifdef BXF_ARENA_FILE_BACKED # define BXFI_ARENA_NAME_SIZE (sizeof ("/tmp/bxf_arena__") + 31) # else # define BXFI_ARENA_NAME_SIZE (sizeof ("/bxf_arena__") + 31) # endif #else # ifdef BXF_ARENA_FILE_BACKED # define BXFI_ARENA_NAME_SIZE (sizeof ("/tmp/bxf_arena_") + 11) # else # define BXFI_ARENA_NAME_SIZE (sizeof ("/bxf_arena_") + 11) # endif #endif struct bxf_arena_s { void *addr; size_t size; intptr_t free_chunks; int flags; bxf_fhandle handle; #ifdef BXF_ARENA_REOPEN_SHM char name[BXFI_ARENA_NAME_SIZE]; #endif }; int bxfi_arena_inherit(bxf_fhandle hndl, int flags, bxf_arena *arena); #endif /* !ARENA_H_ */ BoxFort-master/src/asm/0002755000175000017500000000000013603450524013745 5ustar sasasasaBoxFort-master/src/asm/mangling.h0000644000175000017500000000301513603450524015707 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef ASM_MANGLING_H_ #define ASM_MANGLING_H_ #include "config.h" #define MANGLING_STR_(x) #x #define MANGLING_STR(x) MANGLING_STR_(x) /* *INDENT-OFF* - formatters try to add spaces here */ #define MANGLING_HEADER_ mangling/BXF_MANGLING.h #define MANGLING_HEADER MANGLING_STR(MANGLING_HEADER_) /* *INDENT-ON* */ #include MANGLING_HEADER #endif /* !ASM_MANGLING_H_ */ BoxFort-master/src/asm/mangling/0002755000175000017500000000000013603450524015541 5ustar sasasasaBoxFort-master/src/asm/mangling/leading-underscore.h0000644000175000017500000000003113603450524021454 0ustar sasasasa#define MANGLE(x) _ ## x BoxFort-master/src/asm/mangling/none.h0000644000175000017500000000002413603450524016643 0ustar sasasasa#define MANGLE(x) x BoxFort-master/src/asm/setjmp-x86.asm0000644000175000017500000000401413603450524016371 0ustar sasasasa; ; The MIT License (MIT) ; ; Copyright © 2016 Franklin "Snaipe" Mathieu ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal ; in the Software without restriction, including without limitation the rights ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the Software is ; furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ; THE SOFTWARE. ; .386 .MODEL FLAT, C .CODE ; The windows CRT defines the jmp_buf on x86 as: ; uint32_t Ebp; ; uint32_t Ebx; ; uint32_t Edi; ; uint32_t Esi; ; uint32_t Esp; ; uint32_t Eip; ; uint32_t Registration; ; uint32_t TryLevel; ; uint32_t Cookie; ; uint32_t UnwindFunc; ; uint32_t UnwindData[6]; ; We're only setting the first 6 fields. bxfi_setjmp label far mov eax, [esp+4] mov [eax], ebp mov [eax + 4], ebx mov [eax + 8], edi mov [eax + 12], esi mov [eax + 16], esp mov esi, [esp] mov [eax + 20], esi xor eax, eax ret bxfi_longjmp label far mov esi, [esp+4] mov eax, [esi + 20] ; EIP mov ebx, [esi + 16] ; ESP mov [ebx], eax mov eax, [esp + 8] ; return value mov ebp, [esi] mov ebx, [esi + 4] mov edi, [esi + 8] mov esp, [esi + 16] mov esi, [esi + 12] ret public bxfi_setjmp public bxfi_longjmp end BoxFort-master/src/asm/setjmp-x86_64.asm0000644000175000017500000000443013603450524016704 0ustar sasasasa; ; The MIT License (MIT) ; ; Copyright © 2016 Franklin "Snaipe" Mathieu ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal ; in the Software without restriction, including without limitation the rights ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the Software is ; furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ; THE SOFTWARE. ; .CODE ; The windows CRT defines the jmp_buf on x86_64 as: ; uint64_t Frame; ; uint64_t Rbx; ; uint64_t Rsp; ; uint64_t Rbp; ; uint64_t Rsi; ; uint64_t Rdi; ; uint64_t R12; ; uint64_t R13; ; uint64_t R14; ; uint64_t R15; ; uint64_t Rip; ; uint64_t Spare; ; uint128_t Xmm6; ; uint128_t Xmm7; ; uint128_t Xmm8; ; uint128_t Xmm9; ; uint128_t Xmm10; ; uint128_t Xmm11; ; uint128_t Xmm12; ; uint128_t Xmm13; ; uint128_t Xmm14; ; uint128_t Xmm15; bxfi_setjmp label far mov [rcx + 8], rbx mov [rcx + 16], rsp mov [rcx + 24], rbp mov [rcx + 32], rsi mov [rcx + 40], rdi mov [rcx + 48], r12 mov [rcx + 56], r13 mov [rcx + 64], r14 mov [rcx + 72], r15 pop [rcx + 80] ; rip push [rcx + 80] xor rax, rax ret bxfi_longjmp label far mov rbx, [rcx + 8] mov rsp, [rcx + 16] mov rbp, [rcx + 24] mov rsi, [rcx + 32] mov rdi, [rcx + 40] mov r12, [rcx + 48] mov r13, [rcx + 56] mov r14, [rcx + 64] mov r15, [rcx + 72] pop rax push [rcx + 80] mov rax, rdx ; return value ret public bxfi_setjmp public bxfi_longjmp end BoxFort-master/src/asm/stackfix.h0000644000175000017500000000270213603450524015731 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ /* This patch is necessary to harden the stack on ELF targets; otherwise, programs compiled with BoxFort will ask for an executable stack, which is not ideal, and even not supported on some platforms. */ #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits #endif BoxFort-master/src/asm/trampoline-aarch64.S0000644000175000017500000000330413603450524017467 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2018 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "config.h" #include "mangling.h" #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline) #endif .globl MANGLE(bxfi_trampoline) MANGLE(bxfi_trampoline): ldr x16, addr_data br x16 .align 3 #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_addr) #endif .globl MANGLE(bxfi_trampoline_addr) MANGLE(bxfi_trampoline_addr): addr_data: .fill 8, 1, 0 #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_end) #endif .globl MANGLE(bxfi_trampoline_end) MANGLE(bxfi_trampoline_end): #include "stackfix.h" BoxFort-master/src/asm/trampoline-arm.S0000644000175000017500000000326313603450524017022 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "config.h" #include "mangling.h" #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline) #endif .globl MANGLE(bxfi_trampoline) MANGLE(bxfi_trampoline): ldr pc, addr_data .align 2 #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_addr) #endif .globl MANGLE(bxfi_trampoline_addr) MANGLE(bxfi_trampoline_addr): addr_data: .fill 4, 1, 0 #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_end) #endif .globl MANGLE(bxfi_trampoline_end) MANGLE(bxfi_trampoline_end): #include "stackfix.h" BoxFort-master/src/asm/trampoline-x86.S0000644000175000017500000000341413603450524016666 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "config.h" #include "mangling.h" #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline) #endif .globl MANGLE(bxfi_trampoline) MANGLE(bxfi_trampoline): call next next: pop %eax jmp *(addr_data - next)(%eax) #ifdef BXF_EXE_FMT_MACH_O .align 2 #else .align 4 #endif #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_addr) #endif .globl MANGLE(bxfi_trampoline_addr) MANGLE(bxfi_trampoline_addr): addr_data: .fill 4, 1, 0 #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_end) #endif .globl MANGLE(bxfi_trampoline_end) MANGLE(bxfi_trampoline_end): #include "stackfix.h" BoxFort-master/src/asm/trampoline-x86.asm0000644000175000017500000000275313603450524017251 0ustar sasasasa; ; The MIT License (MIT) ; ; Copyright © 2016 Franklin "Snaipe" Mathieu ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal ; in the Software without restriction, including without limitation the rights ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the Software is ; furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ; THE SOFTWARE. ; .386 .MODEL FLAT, C .CODE bxfi_trampoline label far call next ; Retrieve IP next: pop eax jmp dword ptr (addr_data - next) [eax] ALIGN 4 bxfi_trampoline_addr label far addr_data byte 4 dup (0) bxfi_trampoline_end label far public bxfi_trampoline public bxfi_trampoline_addr public bxfi_trampoline_end end BoxFort-master/src/asm/trampoline-x86_64.S0000644000175000017500000000334213603450524017177 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "config.h" #include "mangling.h" #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline) #endif .globl MANGLE(bxfi_trampoline) MANGLE(bxfi_trampoline): jmp *addr_data(%rip) #ifdef BXF_EXE_FMT_MACH_O .align 3 #else .align 8 #endif #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_addr) #endif .globl MANGLE(bxfi_trampoline_addr) MANGLE(bxfi_trampoline_addr): addr_data: .fill 8, 1, 0 #ifdef ASSEMBLER_SUPPORTS_HIDDEN .hidden MANGLE(bxfi_trampoline_end) #endif .globl MANGLE(bxfi_trampoline_end) MANGLE(bxfi_trampoline_end): #include "stackfix.h" BoxFort-master/src/asm/trampoline-x86_64.asm0000644000175000017500000000256313603450524017561 0ustar sasasasa; ; The MIT License (MIT) ; ; Copyright © 2016 Franklin "Snaipe" Mathieu ; ; Permission is hereby granted, free of charge, to any person obtaining a copy ; of this software and associated documentation files (the "Software"), to deal ; in the Software without restriction, including without limitation the rights ; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ; copies of the Software, and to permit persons to whom the Software is ; furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ; THE SOFTWARE. ; .CODE bxfi_trampoline label far jmp qword ptr addr_data ALIGN 8 bxfi_trampoline_addr label far addr_data byte 8 dup (0) bxfi_trampoline_end label far public bxfi_trampoline public bxfi_trampoline_addr public bxfi_trampoline_end end BoxFort-master/src/common.h0000644000175000017500000000452013603450524014625 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef COMMON_H_ #define COMMON_H_ #include #include #include #include #ifdef __GNUC__ # define nonstd __extension__ #else # define nonstd #endif #ifdef _WIN32 # include #else # include #endif #define align2_down(v, d) ((v) & ~((d) - 1)) #define align2_up(v, d) ((((v) - 1) & ~((d) - 1)) + (d)) #define bxfi_cont(Var, Type, Member) \ (Var ? ((Type *) (((char *) Var) - offsetof(Type, Member))) : NULL) static inline size_t pagesize(void) { static size_t cached; if (!cached) { #ifdef _WIN32 SYSTEM_INFO si; GetSystemInfo(&si); cached = (size_t) si.dwPageSize; #else cached = (size_t) sysconf(_SC_PAGESIZE); #endif } return cached; } #define PAGE_SIZE (pagesize()) #define bug(...) do { \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, ": %s\n" \ "This is a bug; please report it " \ "on the repository's issue tracker.\n", \ strerror(errno)); \ abort(); \ } while (0) #endif /* !COMMON_H_ */ BoxFort-master/src/config.h.in0000644000175000017500000000415313603450524015211 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef CONFIG_H_IN_ # define CONFIG_H_IN_ #mesondefine BXF_ARCH #mesondefine BXF_BITS #mesondefine BXF_MANGLING #mesondefine BXF_OS_FAMILY # ifdef BXF_OS_FAMILY # define BXF_OS_FAMILY_STR #BXF_OS_FAMILY # endif #mesondefine BXF_ARCH_x86 #mesondefine BXF_ARCH_x86_64 #mesondefine BXF_ARCH_ARM #mesondefine BXF_ARCH_ARM64 #mesondefine BXF_EXE_FMT_ELF #mesondefine BXF_EXE_FMT_PE #mesondefine BXF_EXE_FMT_MACH_O #mesondefine BXF_ARENA_REOPEN_SHM #mesondefine BXF_ARENA_FILE_BACKED #mesondefine BXF_FORK_RESILIENCE #mesondefine HAVE__R_DEBUG #mesondefine HAVE__DYNAMIC #mesondefine HAVE_PR_SET_PDEATHSIG #mesondefine HAVE_CLOCK_GETTIME #mesondefine HAVE_CLOCK_MONOTONIC_RAW #mesondefine HAVE_GETTIMEOFDAY #mesondefine HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP #mesondefine HAVE_ENVIRON #mesondefine HAVE_MINCORE #mesondefine HAVE_UNSIGNED_MINCORE_VEC #mesondefine ASSEMBLER_SUPPORTS_HIDDEN # define BXFI_STR_(x) #x # define BXFI_STR(x) BXFI_STR_(x) #endif /* !CONFIG_H_IN_ */ BoxFort-master/src/context.c0000644000175000017500000002415213603450524015017 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "arena.h" #include "boxfort.h" #include "context.h" #ifdef _WIN32 # include #endif #ifdef BXF_ARENA_REOPEN_SHM # include # include #endif int bxf_context_init(bxf_context *ctx) { struct bxf_context_s *nctx = malloc(sizeof (*nctx)); if (!nctx) return -ENOMEM; int rc = bxf_arena_init(0, BXF_ARENA_RESIZE | BXF_ARENA_MAYMOVE, &nctx->arena); if (!rc) *ctx = nctx; return rc; } int bxf_context_addstatic(bxf_context ctx, const void *ptr, size_t size) { struct bxfi_ctx_static *elt; struct bxfi_addr addr; int rc = bxfi_normalize_addr(ptr, &addr); if (rc < 0) return rc; bxf_ptr p = bxf_arena_alloc(&ctx->arena, sizeof (*elt) + size + strlen(addr.soname) + 1); if (p < 0) return p; elt = bxf_arena_ptr(ctx->arena, p); elt->tag = BXFI_TAG_STATIC; elt->addr = addr.addr; elt->seg = addr.seg; elt->size = size; strcpy(&elt->data[size], addr.soname); return 0; } int bxf_context_addarena(bxf_context ctx, bxf_arena arena) { struct bxfi_ctx_arena *elt; bxf_ptr p = bxf_arena_alloc(&ctx->arena, sizeof (*elt)); if (p < 0) return p; elt = bxf_arena_ptr(ctx->arena, p); elt->tag = BXFI_TAG_ARENA; elt->flags = arena->flags; elt->base = arena->flags & BXF_ARENA_IDENTITY ? arena : NULL; #ifdef BXF_ARENA_REOPEN_SHM strcpy(elt->name, arena->name); #else elt->handle = arena->handle; #endif return 0; } int bxf_context_addobject(bxf_context ctx, const char *name, const void *ptr, size_t size) { struct bxfi_ctx_object *elt; size_t len = strlen(name) + 1; bxf_ptr p = bxf_arena_alloc(&ctx->arena, sizeof (*elt) + len + size); if (p < 0) return p; elt = bxf_arena_ptr(ctx->arena, p); elt->tag = BXFI_TAG_OBJECT; elt->namesz = len; memcpy(&elt->data, name, len); memcpy(&elt->data[elt->namesz], ptr, size); return 0; } struct bxfi_find_ctx { const char *name; void *result; }; static int find_obj(void *ptr, size_t size, void *user) { (void) size; struct bxfi_find_ctx *ctx = user; enum bxfi_ctx_tag *tag = ptr; if (*tag != BXFI_TAG_OBJECT) return 0; struct bxfi_ctx_object *obj = ptr; if (!strcmp(obj->data, ctx->name)) { ctx->result = &obj->data[obj->namesz]; return 1; } return 0; } int bxf_context_getobject(bxf_context ctx, const char *name, void **ptr) { struct bxfi_find_ctx fctx = { .name = name }; int found = bxf_arena_iter(ctx->arena, find_obj, &fctx); if (found) *ptr = fctx.result; return found; } int bxf_context_addaddr(bxf_context ctx, const char *name, const void *addr) { struct bxfi_addr norm; int rc = bxfi_normalize_addr(addr, &norm); if (rc < 0) return rc; struct bxfi_ctx_object *elt; size_t sonamelen = strlen(norm.soname) + 1; size_t size = sizeof (void *) + sizeof (norm.seg) + sonamelen; size_t len = strlen(name) + 1; bxf_ptr p = bxf_arena_alloc(&ctx->arena, sizeof (*elt) + len + size); if (p < 0) return p; elt = bxf_arena_ptr(ctx->arena, p); elt->tag = BXFI_TAG_OBJECT; elt->namesz = len; size_t i = 0; memcpy(&elt->data[i], name, len); i += elt->namesz; memcpy(&elt->data[i], &norm.addr, sizeof (void *)); i += sizeof (void *); memcpy(&elt->data[i], &norm.seg, sizeof (norm.seg)); i += sizeof (norm.seg); memcpy(&elt->data[i], norm.soname, sonamelen); return 0; } int bxf_context_getaddr(bxf_context ctx, const char *name, void **addr) { struct { void *addr; size_t seg; const char soname[]; } *serialized; int rc = bxf_context_getobject(ctx, name, (void **) &serialized); if (rc > 0) { struct bxfi_addr norm = { .addr = serialized->addr, .soname = serialized->soname, .seg = serialized->seg, }; *addr = bxfi_denormalize_addr(&norm); } return rc; } int bxf_context_addfnaddr(bxf_context ctx, const char *name, void (*fn)(void)) { return bxf_context_addaddr(ctx, name, nonstd (void *) fn); } int bxf_context_getfnaddr(bxf_context ctx, const char *name, void(**fn)(void)) { return bxf_context_getaddr(ctx, name, nonstd (void **) fn); } int bxf_context_addfhandle(bxf_context ctx, bxf_fhandle hndl) { struct bxfi_ctx_fhandle *elt; bxf_ptr p = bxf_arena_alloc(&ctx->arena, sizeof (*elt)); if (p < 0) return p; elt = bxf_arena_ptr(ctx->arena, p); elt->tag = BXFI_TAG_FHANDLE; elt->handle = hndl; return 0; } int bxf_context_addfile(bxf_context ctx, const char *name, FILE *file) { #ifdef _WIN32 HANDLE hndl = (HANDLE) _get_osfhandle(_fileno(file)); int rc = bxf_context_addfhandle(ctx, hndl); if (!rc) rc = bxf_context_addobject(ctx, name, &hndl, sizeof (hndl)); #else int fd = fileno(file); int rc = bxf_context_addfhandle(ctx, fd); if (!rc) rc = bxf_context_addobject(ctx, name, &fd, sizeof (int)); #endif return rc; } int bxf_context_getfile(bxf_context ctx, const char *name, FILE **file) { #ifdef _WIN32 HANDLE *hndl; int rc = bxf_context_getobject(ctx, name, (void **) &hndl); if (rc > 0) *file = _fdopen(_open_osfhandle((intptr_t) *hndl, 0), "r+"); #else int *fd; int rc = bxf_context_getobject(ctx, name, (void **) &fd); if (rc > 0) *file = fdopen(*fd, "r+"); #endif return rc; } int bxf_context_term(bxf_context ctx) { int rc = bxf_arena_term(&ctx->arena); free(ctx); return rc; } bxf_fhandle bxfi_context_gethandle(bxf_context ctx) { return ctx->arena->handle; } struct bxfi_prepare_ctx { bxf_fhandle_fn *fn; void *user; }; static int prepare_elt(void *ptr, size_t size, void *user) { (void) size; struct bxfi_prepare_ctx *ctx = user; enum bxfi_ctx_tag *tag = ptr; switch (*tag) { case BXFI_TAG_STATIC: { struct bxfi_ctx_static *elt = ptr; struct bxfi_addr a = { .addr = elt->addr, .soname = &elt->data[elt->size], .seg = elt->seg, }; void *addr = bxfi_denormalize_addr(&a); if (!addr) return -EINVAL; memcpy(elt->data, addr, elt->size); } break; #ifndef BXF_ARENA_REOPEN_SHM case BXFI_TAG_ARENA: { struct bxfi_ctx_arena *elt = ptr; if (ctx->fn) return ctx->fn(elt->handle, ctx->user); } break; #endif case BXFI_TAG_FHANDLE: { struct bxfi_ctx_fhandle *elt = ptr; if (ctx->fn) return ctx->fn(elt->handle, ctx->user); } break; default: break; } return 0; } int bxfi_context_prepare(bxf_context ctx, bxf_fhandle_fn *fn, void *user) { struct bxfi_prepare_ctx uctx = { .fn = fn, .user = user, }; if (fn) { int rc = fn(ctx->arena->handle, user); if (rc < 0) return rc; } return bxf_arena_iter(ctx->arena, prepare_elt, &uctx); } static int inherit_elt(void *ptr, size_t size, void *user) { (void) size, (void) user; enum bxfi_ctx_tag *tag = ptr; switch (*tag) { case BXFI_TAG_STATIC: { struct bxfi_ctx_static *elt = ptr; struct bxfi_addr a = { .addr = elt->addr, .soname = &elt->data[elt->size], .seg = elt->seg, }; void *addr = bxfi_denormalize_addr(&a); if (!addr) return -EINVAL; memcpy(addr, elt->data, elt->size); } break; case BXFI_TAG_ARENA: { struct bxfi_ctx_arena *elt = ptr; bxf_arena arena = elt->base; #ifdef BXF_ARENA_REOPEN_SHM # ifdef BXF_ARENA_FILE_BACKED int hndl = open(elt->name, O_RDONLY, 0600); # else int hndl = shm_open(elt->name, O_RDONLY, 0600); # endif if (hndl < 0) return -errno; #else bxf_fhandle hndl = elt->handle; #endif bxfi_arena_inherit(hndl, elt->flags, &arena); } break; default: break; } return 0; } static struct bxf_context_s current_ctx; int bxfi_context_inherit(struct bxfi_ctx_arena *ctx) { #ifdef BXF_ARENA_REOPEN_SHM if (!ctx->name[0]) return 0; # ifdef BXF_ARENA_FILE_BACKED int hndl = open(ctx->name, O_RDONLY, 0600); # else int hndl = shm_open(ctx->name, O_RDONLY, 0600); # endif if (hndl < 0) return -errno; #else bxf_fhandle hndl = ctx->handle; if (!hndl) return 0; #endif bxf_arena arena = NULL; int rc = bxfi_arena_inherit(hndl, 0, &arena); if (rc < 0) return rc; current_ctx.arena = arena; return bxf_arena_iter(arena, inherit_elt, NULL); } bxf_context bxf_context_current(void) { if (!current_ctx.arena) return NULL; return ¤t_ctx; } BoxFort-master/src/context.h0000644000175000017500000000415713603450524015027 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef CONTEXT_H_ #define CONTEXT_H_ #include "addr.h" #include "arena.h" struct bxf_context_s { bxf_arena arena; }; enum bxfi_ctx_tag { BXFI_TAG_STATIC, BXFI_TAG_ARENA, BXFI_TAG_OBJECT, BXFI_TAG_FHANDLE, }; struct bxfi_ctx_static { enum bxfi_ctx_tag tag; const void *addr; size_t seg; size_t size; char data[]; }; struct bxfi_ctx_arena { enum bxfi_ctx_tag tag; int flags; void *base; #ifdef BXF_ARENA_REOPEN_SHM char name[BXFI_ARENA_NAME_SIZE]; #else bxf_fhandle handle; #endif }; struct bxfi_ctx_object { enum bxfi_ctx_tag tag; size_t namesz; char data[]; }; struct bxfi_ctx_fhandle { enum bxfi_ctx_tag tag; bxf_fhandle handle; }; typedef int (bxf_fhandle_fn)(bxf_fhandle, void *); bxf_fhandle bxfi_context_gethandle(bxf_context ctx); int bxfi_context_prepare(bxf_context ctx, bxf_fhandle_fn *fn, void *user); int bxfi_context_inherit(struct bxfi_ctx_arena *ctx); #endif /* !CONTEXT_H_ */ BoxFort-master/src/exe-elf.c0000644000175000017500000002271413603450524014662 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include "config.h" #include "exe.h" #include "addr.h" #include "common.h" #if BXF_BITS == 32 typedef Elf32_Word ElfWord; typedef Elf32_Sword ElfSWord; # ifndef ELF_R_SYM # define ELF_R_SYM(i) ELF32_R_SYM(i) # endif #elif BXF_BITS == 64 typedef Elf64_Xword ElfWord; typedef Elf64_Sxword ElfSWord; # ifndef ELF_R_SYM # define ELF_R_SYM(i) ELF64_R_SYM(i) # endif #else # error Unsupported architecture #endif typedef ElfW (Addr) ElfAddr; typedef ElfW (Dyn) ElfDyn; typedef ElfW (Sym) ElfSym; typedef ElfW (Word) ElfWWord; typedef ElfW (Off) ElfOff; extern char **environ; static void *lib_dt_lookup(bxfi_exe_lib lib, ElfSWord tag) { ElfAddr base = (ElfAddr) lib->l_addr; for (const ElfDyn *dyn = lib->l_ld; dyn->d_tag != DT_NULL; ++dyn) { if (dyn->d_tag == tag) { if (dyn->d_un.d_ptr >= base && (dyn->d_un.d_ptr >> (BXF_BITS - 8)) ^ 0xff) return (void *) dyn->d_un.d_ptr; else return (char *) base + dyn->d_un.d_ptr; } } return NULL; } static ElfWord lib_dt_lookup_val(bxfi_exe_lib lib, ElfSWord tag) { for (const ElfDyn *dyn = lib->l_ld; dyn->d_tag != DT_NULL; ++dyn) { if (dyn->d_tag == tag) return dyn->d_un.d_val; } return (ElfWord) - 1; } #if !defined HAVE__R_DEBUG static int find_dynamic(struct dl_phdr_info *info, size_t size, void *data) { ElfAddr *ctx = data; (void)size; for (ElfOff i = 0; i < info->dlpi_phnum; ++i) { if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) { *ctx = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; return 1; } } return -1; } static struct r_debug *r_debug_from_dynamic(void *dynamic) { for (const ElfDyn *dyn = dynamic; dyn->d_tag != DT_NULL; ++dyn) { if (dyn->d_tag == DT_DEBUG) return (struct r_debug *) dyn->d_un.d_ptr; } return NULL; } #endif static struct r_debug *get_r_debug(void) { /* Find our own r_debug */ struct r_debug *dbg = NULL; /* First use some known shortcuts */ #if defined HAVE__R_DEBUG dbg = &_r_debug; #elif defined HAVE__DYNAMIC dbg = r_debug_from_dynamic(_DYNAMIC); #endif #if !defined HAVE__R_DEBUG /* If there are no available shortcuts, we manually query our own phdrs */ /* *INDENT-OFF* (formatters cannot handle this part of the code) */ # if defined HAVE__DYNAMIC if (!dbg) { # endif ElfAddr dynamic; if (dl_iterate_phdr(find_dynamic, &dynamic) > 0) dbg = r_debug_from_dynamic((void *) dynamic); # if defined HAVE__DYNAMIC } # endif /* *INDENT-ON* */ #endif return dbg; } static bxfi_exe_ctx init_exe_ctx(void) { static struct r_debug *dbg = (void *) -1; if (dbg == (void *) -1) dbg = get_r_debug(); return dbg; } static unsigned long elf_hash(const char *s) { unsigned long h = 0, high; while (*s) { h = (h << 4) + (unsigned char) *s++; if ((high = h & 0xf0000000)) h ^= high >> 24; h &= ~high; } return h; } static ElfSym *elf_hash_find(ElfWWord *hash, ElfSym *symtab, const char *strtab, const char *name) { struct { ElfWWord nb_buckets; ElfWWord nb_chains; } *h_info = (void *) hash; ElfWWord *buckets = (ElfWWord *) (h_info + 1); ElfWWord *chains = (ElfWWord *) (h_info + 1) + h_info->nb_buckets; unsigned long idx = elf_hash(name) % h_info->nb_buckets; for (ElfWWord si = buckets[idx]; si != STN_UNDEF; si = chains[si]) { if (!strcmp(&strtab[symtab[si].st_name], name)) return &symtab[si]; } return NULL; } static ElfSym *dynsym_lookup(bxfi_exe_lib lib, const char *name) { ElfWWord *hash = lib_dt_lookup(lib, DT_HASH); ElfSym *symtab = lib_dt_lookup(lib, DT_SYMTAB); const char *strtab = lib_dt_lookup(lib, DT_STRTAB); if (!hash || !symtab || !strtab) return NULL; return elf_hash_find(hash, symtab, strtab, name); } extern int main(void); extern void *bxfi_trampoline; extern void *bxfi_trampoline_addr; extern void *bxfi_trampoline_end; #define BXFI_TRAMPOLINE_SIZE \ ((uintptr_t) &bxfi_trampoline_end \ - (uintptr_t) &bxfi_trampoline) int bxfi_exe_patch_main(bxfi_exe_fn *new_main) { void *addr = nonstd (void *) &main; if (!addr) return -1; /* Reserve enough space for the trampoline and copy the default opcodes */ char opcodes[BXFI_TRAMPOLINE_SIZE]; memcpy(opcodes, &bxfi_trampoline, sizeof (opcodes)); uintptr_t jmp_offset = (uintptr_t) &bxfi_trampoline_addr - (uintptr_t) &bxfi_trampoline; /* The trampoline code is a jump followed by an aligned pointer value -- after copying the jmp opcode, we write this pointer value. */ *(uintptr_t *) (&opcodes[jmp_offset]) = (uintptr_t) new_main; void *base = (void *) align2_down((uintptr_t) addr, PAGE_SIZE); uintptr_t offset = (uintptr_t) addr - (uintptr_t) base; size_t len = align2_up(offset + sizeof (opcodes), PAGE_SIZE); mprotect(base, len, PROT_READ | PROT_WRITE | PROT_EXEC); memcpy(nonstd (void *) addr, opcodes, sizeof (opcodes)); mprotect(base, len, PROT_READ | PROT_EXEC); return 0; } struct find_lib_from_addr_ctx { const void *addr; const char *name; size_t segidx; void *base; int first; }; static int find_lib_from_addr(struct dl_phdr_info *info, size_t size, void *data) { (void) size; struct find_lib_from_addr_ctx *ctx = data; size_t segidx = 0; for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) { const ElfW(Phdr) *phdr = &info->dlpi_phdr[i]; if (phdr->p_type != PT_LOAD) continue; void *base = (void *) (info->dlpi_addr + phdr->p_vaddr); void *end = (char *) base + phdr->p_memsz; if (ctx->addr >= base && ctx->addr < end) { if (!ctx->first) { ctx->name = info->dlpi_name; } else { ctx->name = ""; } ctx->segidx = segidx; ctx->base = base; return 1; } ++segidx; } ctx->first = 0; return 0; } uintptr_t bxfi_slide_from_addr(const void *addr, const char **name, size_t *seg) { struct find_lib_from_addr_ctx ctx = { .addr = addr, .first = 1, }; if (!dl_iterate_phdr(find_lib_from_addr, &ctx)) { errno = EINVAL; return (uintptr_t) -1; } *name = ctx.name; *seg = ctx.segidx; return (uintptr_t) ctx.base; } struct find_lib_from_name_ctx { const char *name; size_t segidx; void *base; int first; }; static int find_lib_from_name(struct dl_phdr_info *info, size_t size, void *data) { (void) size; struct find_lib_from_name_ctx *ctx = data; size_t segidx = 0; if (!(ctx->first && !ctx->name[0]) && strcmp(info->dlpi_name, ctx->name)) return 0; ctx->first = 0; for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) { const ElfW(Phdr) *phdr = &info->dlpi_phdr[i]; if (phdr->p_type != PT_LOAD) continue; if (segidx == ctx->segidx) { ctx->base = (void *) (info->dlpi_addr + phdr->p_vaddr); return 1; } ++segidx; } return 0; } uintptr_t bxfi_slide_from_name(const char *name, size_t seg) { struct find_lib_from_name_ctx ctx = { .name = name, .segidx = seg, .first = 1, }; if (!dl_iterate_phdr(find_lib_from_name, &ctx)) { errno = EINVAL; return (uintptr_t) -1; } return (uintptr_t) ctx.base; } const char *bxfi_lib_name(bxfi_exe_lib lib) { bxfi_exe_ctx ctx = init_exe_ctx(); /* The name of the main shared object is the empty string, we return something to be consistent with the eglibc weirdity */ if (lib == ctx->r_map) return "self"; /* Somewhy, eglibc always set l_name to the empty string. */ if (lib->l_name[0]) return lib->l_name; const char *strtab = lib_dt_lookup(lib, DT_STRTAB); ElfWord soname_off = lib_dt_lookup_val(lib, DT_SONAME); if (!strtab || soname_off == (ElfWord) - 1) return NULL; return &strtab[soname_off]; } void bxfi_lib_name_term(const char *str) { (void) str; } size_t bxfi_exe_get_vmslide(bxfi_exe_lib lib) { return (size_t)lib->l_addr; } BoxFort-master/src/exe-elf.h0000644000175000017500000000305113603450524014660 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef PLT_ELF_H_ #define PLT_ELF_H_ #include #ifdef __FreeBSD__ # include # define ElfW(type) ElfW_(Elf, type) # define ElfW_(e, t) ElfW__(e, _ ## t) # define ElfW__(e, t) e ## t #endif typedef struct link_map *bxfi_exe_lib; typedef struct r_debug *bxfi_exe_ctx; typedef void (bxfi_exe_fn)(void); #define BXFI_INVALID_LIB ((bxfi_exe_lib) 0) #endif /* !PLT_ELF_H_ */ BoxFort-master/src/exe-mach-o.c0000644000175000017500000001342313603450524015255 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include "config.h" #include "exe.h" #include "addr.h" #include "common.h" #if BXF_BITS == 32 typedef struct mach_header mach_hdr; typedef struct nlist sym; typedef struct section section; typedef struct segment_command segment_cmd; # define BXF_LC_SEGMENT LC_SEGMENT #elif BXF_BITS == 64 typedef struct mach_header_64 mach_hdr; typedef struct nlist_64 sym; typedef struct section_64 section; typedef struct segment_command_64 segment_cmd; # define BXF_LC_SEGMENT LC_SEGMENT_64 #else # error Unsupported architecture #endif static inline void *ptr_add(const void *ptr, size_t off) { return (char *) ptr + off; } void *get_main_addr(void) { return dlsym(RTLD_DEFAULT, "main"); } extern void *bxfi_trampoline; extern void *bxfi_trampoline_addr; extern void *bxfi_trampoline_end; #define BXFI_TRAMPOLINE_SIZE \ ((uintptr_t) &bxfi_trampoline_end \ - (uintptr_t) &bxfi_trampoline) int bxfi_exe_patch_main(bxfi_exe_fn *new_main) { void *addr = get_main_addr(); if (!addr) return -1; /* Reserve enough space for the trampoline and copy the default opcodes */ char opcodes[BXFI_TRAMPOLINE_SIZE]; memcpy(opcodes, &bxfi_trampoline, sizeof (opcodes)); uintptr_t jmp_offset = (uintptr_t) &bxfi_trampoline_addr - (uintptr_t) &bxfi_trampoline; /* The trampoline code is a jump followed by an aligned pointer value -- after copying the jmp opcode, we write this pointer value. */ *(uintptr_t *) (&opcodes[jmp_offset]) = (uintptr_t) new_main; void *base = (void *) align2_down((uintptr_t) addr, PAGE_SIZE); uintptr_t offset = (uintptr_t) addr - (uintptr_t) base; size_t len = align2_up(offset + sizeof (opcodes), PAGE_SIZE); mprotect(base, len, PROT_READ | PROT_WRITE | PROT_EXEC); memcpy(nonstd (void *) addr, opcodes, sizeof (opcodes)); mprotect(base, len, PROT_READ | PROT_EXEC); return 0; } uintptr_t bxfi_slide_from_addr(const void *addr, const char **name, size_t *seg) { /* TODO: this is not thread safe, as another thread can load or unload * images on the fly -- find a way to fix this. */ bxfi_exe_lib nb_images = _dyld_image_count(); for (bxfi_exe_lib i = 0; i < nb_images; ++i) { const mach_hdr *hdr = (const mach_hdr *) _dyld_get_image_header(i); intptr_t slide = bxfi_exe_get_vmslide(i); size_t segidx = 0; const struct load_command *lc = ptr_add(hdr, sizeof (mach_hdr)); for (size_t c = 0; c < hdr->ncmds; ++c, lc = ptr_add(lc, lc->cmdsize)) { if (lc->cmd == BXF_LC_SEGMENT) { const segment_cmd *sc = (void *) lc; uintptr_t start = sc->vmaddr + slide; uintptr_t end = start + sc->vmsize - 1; if ((uintptr_t) addr >= start && (uintptr_t) addr <= end) { *name = bxfi_lib_name(i); *seg = segidx; return start; } ++segidx; } } } errno = EINVAL; return (uintptr_t) -1; } uintptr_t bxfi_slide_from_name(const char *name, size_t seg) { bxfi_exe_lib lib = 0; if (strcmp("self", name)) { /* TODO: this is not thread safe, as another thread can load or unload * images on the fly -- find a way to fix this. */ bxfi_exe_lib nb_images = _dyld_image_count(); for (bxfi_exe_lib i = 1; i < nb_images; ++i) { const char *img_name = _dyld_get_image_name(i); if (img_name && !strcmp(img_name, name)) { lib = i; break; } } if (!lib) { errno = EINVAL; return (uintptr_t) -1; } } const mach_hdr *hdr = (const mach_hdr *) _dyld_get_image_header(lib); uintptr_t slide = bxfi_exe_get_vmslide(lib); size_t segidx = 0; const struct load_command *lc = ptr_add(hdr, sizeof (mach_hdr)); for (size_t c = 0; c < hdr->ncmds; ++c, lc = ptr_add(lc, lc->cmdsize)) { if (lc->cmd != BXF_LC_SEGMENT) continue; const segment_cmd *sc = (void *) lc; if (segidx == seg) return sc->vmaddr + slide; ++segidx; } errno = EINVAL; return (uintptr_t) -1; } const char *bxfi_lib_name(bxfi_exe_lib lib) { if (!lib) return "self"; return _dyld_get_image_name(lib); } void bxfi_lib_name_term(const char *str) { (void) str; } size_t bxfi_exe_get_vmslide(bxfi_exe_lib lib) { return _dyld_get_image_vmaddr_slide(lib); } BoxFort-master/src/exe-mach-o.h0000644000175000017500000000255013603450524015261 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef EXE_MACH_O_H_ #define EXE_MACH_O_H_ typedef int bxfi_exe_lib; typedef void *bxfi_exe_ctx; typedef void (bxfi_exe_fn)(void); #define BXFI_INVALID_LIB ((bxfi_exe_lib) - 1) #endif /* !EXE_MACH_O_H_ */ BoxFort-master/src/exe-pe.c0000644000175000017500000001026313603450524014514 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "exe.h" #include "common.h" #include #include #ifdef _MSC_VER # include #endif static void *get_main_addr(void) { HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); if (snap == INVALID_HANDLE_VALUE) return NULL; MODULEENTRY32 mod = { .dwSize = sizeof (MODULEENTRY32) }; for (BOOL more = Module32First(snap, &mod); more; more = Module32Next(snap, &mod)) { FARPROC fn = GetProcAddress(mod.hModule, "main"); if (fn != NULL) return nonstd (void *) fn; } return NULL; } extern void *bxfi_trampoline; extern void *bxfi_trampoline_addr; extern void *bxfi_trampoline_end; int bxfi_exe_patch_main(bxfi_exe_fn *new_main) { void *addr = get_main_addr(); if (!addr) return -1; #if defined (BXF_ARCH_x86) || defined (BXF_ARCH_x86_64) /* If we got stuck on a jmp table entry we need to follow the trail */ if (*(char *) addr == (char) 0xE9) addr = (char *) addr + *(DWORD *) ((char *) addr + 1) + 5; #endif /* Reserve enough space for the trampoline and copy the default opcodes */ uintptr_t size = (uintptr_t) &bxfi_trampoline_end - (uintptr_t) &bxfi_trampoline; #ifndef _MSC_VER char opcodes[size]; /* VLA */ #else char *opcodes = alloca(size); #endif memcpy(opcodes, &bxfi_trampoline, size); uintptr_t jmp_offset = (uintptr_t) &bxfi_trampoline_addr - (uintptr_t) &bxfi_trampoline; /* The trampoline code is a jump followed by an aligned pointer value -- after copying the jmp opcode, we write this pointer value. */ *(uintptr_t *) (&opcodes[jmp_offset]) = (uintptr_t) new_main; void *base = (void *) align2_down((uintptr_t) addr, PAGE_SIZE); uintptr_t offset = (uintptr_t) addr - (uintptr_t) base; size_t len = align2_up(offset + size, PAGE_SIZE); DWORD old; VirtualProtect(base, len, PAGE_EXECUTE_READWRITE, &old); memcpy(nonstd (void *) addr, opcodes, size); VirtualProtect(base, len, old, NULL); return 0; } uintptr_t bxfi_slide_from_addr(const void *addr, const char **name, size_t *seg) { MEMORY_BASIC_INFORMATION mbi; if (VirtualQuery(addr, &mbi, sizeof (mbi))) { HMODULE hmod = mbi.AllocationBase; *name = bxfi_lib_name(hmod); *seg = 0; return (uintptr_t) hmod; } errno = EINVAL; return (uintptr_t) -1; } uintptr_t bxfi_slide_from_name(const char *name, size_t seg) { (void) seg; if (!strcmp(name, "self")) name = NULL; HMODULE hmod = GetModuleHandle(name); if (!hmod) { errno = EINVAL; return (uintptr_t) -1; } return (uintptr_t) hmod; } const char *bxfi_lib_name(bxfi_exe_lib lib) { char *out = LocalAlloc(LMEM_FIXED, MAX_PATH); if (GetModuleFileNameA(lib, out, MAX_PATH)) return out; LocalFree(out); return NULL; } void bxfi_lib_name_term(const char *str) { LocalFree((char *) str); } size_t bxfi_exe_get_vmslide(bxfi_exe_lib lib) { return (size_t) lib; } BoxFort-master/src/exe-pe.h0000644000175000017500000000256713603450524014531 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef EXE_PE_H_ #define EXE_PE_H_ #include typedef HMODULE bxfi_exe_lib; typedef void *bxfi_exe_ctx; typedef void (bxfi_exe_fn)(void); #define BXFI_INVALID_LIB ((bxfi_exe_lib) NULL) #endif /* !EXE_PE_H_ */ BoxFort-master/src/exe.h0000644000175000017500000000334213603450524014117 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef PLT_H_ #define PLT_H_ #include #include "config.h" #if defined BXF_EXE_FMT_ELF # include "exe-elf.h" #elif defined BXF_EXE_FMT_PE # include "exe-pe.h" #elif defined BXF_EXE_FMT_MACH_O # include "exe-mach-o.h" #endif int bxfi_exe_patch_main(bxfi_exe_fn *new_main); uintptr_t bxfi_slide_from_addr(const void *addr, const char **name, size_t *seg); uintptr_t bxfi_slide_from_name(const char *name, size_t seg); const char *bxfi_lib_name(bxfi_exe_lib lib); void bxfi_lib_name_term(const char *str); size_t bxfi_exe_get_vmslide(bxfi_exe_lib lib); #endif /* !PLT_H_ */ BoxFort-master/src/meson.build0000644000175000017500000000356713603450524015340 0ustar sasasasasources = files( 'addr.c', 'addr.h', 'arena.c', 'arena.h', 'context.c', 'context.h', 'exe.h', 'exe-@0@.c'.format(binfmt), 'exe-@0@.h'.format(binfmt), 'sandbox-@0@.c'.format(os_family), 'sandbox-@0@.h'.format(os_family), 'sandbox.c', 'sandbox.h', 'timeout-@0@.c'.format(os_family), 'timeout.h', 'timestamp.c', 'timestamp.h', ) asm_extension = '.S' if cc.get_id() == 'msvc' asm_extension = '.asm' endif asm = files('asm/trampoline-@0@@1@'.format(arch, asm_extension)) if cc.get_id() == 'msvc' if bitness == 32 masm = find_program('ml') else masm = find_program('ml64') endif masm_gen = generator(masm, output: '@BASENAME@.obj', depfile: '@BASENAME@.obj.ndep', arguments: [ '/I', '@CURRENT_SOURCE_DIR@/asm/', '/I', '@0@/'.format(meson.current_build_dir()), '/safeseh', '@EXTRA_ARGS@', '/Fo', '@OUTPUT@', '/c', '@INPUT@', ]) asm += 'asm/setjmp-@0@@1@'.format(arch, asm_extension) sources += masm_gen.process(asm) else sources += asm endif configure_file(input : 'config.h.in', output : 'config.h', configuration : config) deps = [ threads, librt, libm, ] extra_cflags = cc.get_supported_arguments([ '-DBXF_STATIC_LIB=1', ]) libboxfort = static_library('boxfort', sources, include_directories: [boxfort_includedir], dependencies: deps, install: not meson.is_subproject(), link_args: cc.get_supported_link_arguments([ '-Wl,--exclude-libs,ALL', ]), ) boxfort = declare_dependency( compile_args: extra_cflags, include_directories: [boxfort_includedir], dependencies: [threads, librt, libm], link_with: [libboxfort]) if not meson.is_subproject() pkgconfig = import('pkgconfig') pkgconfig.generate( name: meson.project_name(), description: 'A portable process sandboxing library', url: 'https://snai.pe/git/boxfort', extra_cflags: extra_cflags, libraries: [libboxfort], ) endif BoxFort-master/src/sandbox-posix.c0000644000175000017500000006035413603450524016135 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ # include #endif #if defined (HAVE_CLOCK_GETTIME) # include #elif defined (HAVE_GETTIMEOFDAY) # include #endif #include "addr.h" #include "boxfort.h" #include "context.h" #include "sandbox.h" #include "timestamp.h" #include "timeout.h" #if defined (HAVE_PR_SET_PDEATHSIG) # include #endif #if defined (__APPLE__) # include #endif #ifndef HAVE_ENVIRON # ifdef __APPLE__ # include # define environ (*_NSGetEnviron()) # else extern char **environ; # endif #endif static struct { struct bxfi_sandbox *alive; struct bxfi_sandbox *dead; pthread_mutex_t sync; pthread_cond_t cond; pthread_t child_pump; int child_pump_active; } self = { .sync = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, }; static struct bxfi_sandbox *reap_child(pid_t pid, uint64_t ts_end, uint64_t mts_end) { struct bxfi_sandbox *s; pthread_mutex_lock(&self.sync); for (s = self.alive; s; s = s->next) { if (s->wait_pid == pid) break; } if (!s) { pthread_mutex_unlock(&self.sync); return NULL; } pthread_mutex_unlock(&self.sync); bxfi_cancel_timeout(s); int status; pid_t rc = waitpid(pid, &status, WNOHANG); if (rc != pid) return NULL; pthread_mutex_lock(&s->sync); s->props.time.end = ts_end; s->props.time.elapsed = mts_end - s->start_monotonic; if (WIFEXITED(status)) s->props.status.exit = WEXITSTATUS(status); if (WIFSIGNALED(status)) s->props.status.signal = WTERMSIG(status); s->props.status.stopped = WIFSTOPPED(status); s->props.status.alive = WIFSTOPPED(status); if (!s->props.status.alive && s->callback) s->callback(&s->props); pthread_mutex_unlock(&s->sync); return s; } static void remove_alive_by_pid(bxf_pid pid) { struct bxfi_sandbox **prev = &self.alive; for (struct bxfi_sandbox *s = self.alive; s; s = s->next) { if (s->wait_pid == (pid_t) pid) { *prev = s->next; s->next = self.dead; self.dead = s; break; } prev = &s->next; } } static void *child_pump_fn(void *nil) { int wflags = WEXITED | WNOWAIT; for (;;) { pthread_mutex_lock(&self.sync); while (!self.alive) pthread_cond_wait(&self.cond, &self.sync); pthread_mutex_unlock(&self.sync); siginfo_t infop; memset(&infop, 0, sizeof (infop)); int rc; for (;;) { rc = waitid(P_ALL, 0, &infop, wflags); if (rc != -1 || errno == EINTR) break; } if (rc) continue; uint64_t mts_end = bxfi_timestamp_monotonic(); uint64_t ts_end = bxfi_timestamp(); for (;;) { memset(&infop, 0, sizeof (infop)); if (waitid(P_ALL, 0, &infop, wflags | WNOHANG) == -1) break; if (!infop.si_pid) break; struct bxfi_sandbox *instance = reap_child(infop.si_pid, ts_end, mts_end); if (!instance) continue; int alive; pthread_mutex_lock(&self.sync); remove_alive_by_pid((bxf_pid) infop.si_pid); alive = !!self.alive; pthread_mutex_unlock(&self.sync); pthread_mutex_lock(&instance->sync); instance->waited = 1; pthread_cond_broadcast(&instance->cond); pthread_mutex_unlock(&instance->sync); if (!alive) goto end; } } end: return nil; } static int bxfi_create_local_ctx(struct bxfi_map *map, const char *name, size_t sz) { shm_unlink(name); int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); if (fd == -1) goto error; if (ftruncate(fd, sizeof (struct bxfi_context) + sz) == -1) goto error; struct bxfi_context *ctx = mmap(NULL, sizeof (struct bxfi_context) + sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (ctx == MAP_FAILED) goto error; ctx->total_sz = sizeof (struct bxfi_context) + sz; *map = (struct bxfi_map) { .ctx = ctx, .fd = fd }; return 0; error:; int err = errno; shm_unlink(name); if (fd != -1) close(fd); return -err; } static void bxfi_unmap_local_ctx(struct bxfi_map *map) { size_t sz = map->ctx->total_sz; munmap(map->ctx, sz); close(map->fd); } int bxfi_check_sandbox_ctx(void) { return !!getenv("BXFI_MAP"); } int bxfi_init_sandbox_ctx(struct bxfi_map *map) { const char *ctx_path = getenv("BXFI_MAP"); int fd = shm_open(ctx_path, O_RDWR, 0600); if (fd == -1) goto error; size_t total_sz; size_t *sz = mmap(NULL, sizeof (total_sz), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (sz == MAP_FAILED) goto error; total_sz = *sz; munmap(sz, sizeof (total_sz)); struct bxfi_context *ctx = mmap(NULL, total_sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (ctx == MAP_FAILED) goto error; *map = (struct bxfi_map) { .ctx = ctx, .fd = fd }; return 0; error:; int err = errno; if (fd != -1) close(fd); return -err; } int bxfi_term_sandbox_ctx(struct bxfi_map *map) { /* This is either our PID or the debugging server's PID */ pid_t control_pid = map->ctx->pid; int suspend = map->ctx->suspend; map->ctx->ok = 1; map->ctx->pid = getpid(); bxfi_unmap_local_ctx(map); const char *ctx_path = getenv("BXFI_MAP"); if (shm_unlink(ctx_path) == -1) return -errno; /* Notify the parent to finalize initialization */ kill(control_pid, SIGSTOP); if (suspend) raise(SIGSTOP); return 0; } static int get_exe_path(char *buf, size_t sz) { #if defined (__linux__) const char *self = "/proc/self/exe"; #elif defined __NetBSD__ const char *self = "/proc/curproc/exe"; #elif defined __FreeBSD__ const char *self = "/proc/curproc/file"; int fd = open(self, O_RDONLY); /* Fallback */ char path[PATH_MAX]; if (fd == -1 && errno == ENOENT) { int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; size_t cb = sizeof (path); sysctl(mib, sizeof (mib) / sizeof (int), path, &cb, NULL, 0); self = path; } if (fd != -1) close(fd); #elif defined __OpenBSD__ || defined __DragonFly__ const char *self = "/proc/curproc/file"; #elif defined (__APPLE__) uint32_t size = sz; if (_NSGetExecutablePath(buf, &size) == -1) return -ENAMETOOLONG; /* _NSGetExecutablePath already returns the correct path */ char *self; (void) self; return 0; #else # error Platform not supported #endif /* We can't just use /proc/self/exe or equivalent to re-exec the executable, because tools like valgrind use this path to open and map the ELF file -- which would point to the valgrind binary. */ ssize_t rc = readlink(self, buf, sz); if (rc == -1) { if (errno == EINVAL) { strncpy(buf, self, sz); return 0; } return -errno; } if ((size_t) rc == sz) return -ENAMETOOLONG; memset(buf + rc, 0, sz - rc); return 0; } static pid_t wait_stop(pid_t pid) { int status; pid_t rc; for (;;) { rc = waitpid(pid, &status, WUNTRACED); if (rc != -1 || errno != EINTR) break; } if (rc == -1) return -pid; if (!WIFSTOPPED(status)) { errno = EPROTO; return 0; } return pid; } static int setup_limit(int limit, size_t iquota, size_t quota) { if (!quota && !iquota) return 0; struct rlimit rl; if (getrlimit(limit, &rl) < 0) return -errno; if (quota) rl.rlim_max = quota; if (iquota) rl.rlim_cur = iquota; else if (quota) rl.rlim_cur = quota; if (setrlimit(limit, &rl) < 0) return -errno; return 0; } #define setup_limit(Limit, Quota) \ (setup_limit((Limit), \ sandbox->iquotas.Quota, \ sandbox->quotas.Quota)) static int setup_limits(bxf_sandbox *sandbox) { int errnum; errnum = setup_limit(RLIMIT_AS, memory); if (errnum < 0) return errnum; errnum = setup_limit(RLIMIT_NOFILE, files); if (errnum < 0) return errnum; errnum = setup_limit(RLIMIT_NPROC, subprocesses); if (errnum < 0) return errnum; return 0; } static int nocloexec_fd(bxf_fhandle fd, void *ctx) { (void) ctx; int flags = fcntl(fd, F_GETFD); if (flags < 0) return -errno; flags &= ~FD_CLOEXEC; int rc = fcntl(fd, F_SETFD, flags); if (rc < 0) return -errno; return 0; } static int inherit_fd(bxf_fhandle fd, void *ctx) { int rc = nocloexec_fd(fd, NULL); if (rc < 0) return rc; uint8_t *do_close = ctx; do_close[fd] = 0; return 0; } static int setup_inheritance(bxf_sandbox *sandbox) { bxf_context ctx = sandbox->inherit.context; if (sandbox->inherit.files) { int rc = 0; if (ctx) rc = bxfi_context_prepare(ctx, nocloexec_fd, NULL); return rc; } else { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) < 0) return -errno; uint8_t *do_close = malloc(rl.rlim_cur); if (!do_close) return -errno; memset(do_close, 1, rl.rlim_cur); do_close[STDIN_FILENO] = 0; do_close[STDOUT_FILENO] = 0; do_close[STDERR_FILENO] = 0; if (ctx) { int rc = bxfi_context_prepare(ctx, inherit_fd, do_close); if (rc < 0) { free(do_close); return rc; } } /* /dev/fd is somewhat more common than /proc/self/fd; we'll handle special cases later. */ int fds = open("/dev/fd", O_RDONLY | O_DIRECTORY); if (fds >= 0) { /* this is somewhat problematic, as fdopendir/readdir are not signal-safe, and thus not fork-safe. We can thread the needle here by assuming deadlocks are going to be extremely unlikely, but not using these APIs and rolling with a custom-made readdir might be a better choice for the unforseeable future. */ DIR *dirfd = fdopendir(fds); /* we have a shortcut; iterate through the directory entries */ struct dirent *dir; while ((dir = readdir(dirfd)) != NULL) { errno = 0; long fd = strtol(dir->d_name, NULL, 10); if (errno != 0 || fd < 0 || fd > (long) rl.rlim_cur || !do_close[fd]) continue; close(fd); } return 0; } else { for (int fd = 0; fd < (int) rl.rlim_cur; ++fd) { if (!do_close[fd]) continue; int flags = fcntl(fd, F_GETFD); if (flags > 0 && !(flags & FD_CLOEXEC)) close(fd); } } free(do_close); } return 0; } #ifdef BXF_FORK_RESILIENCE static void prefork(void) { pthread_mutex_lock(&self.sync); for (struct bxfi_sandbox *s = self.alive; s; s = s->next) pthread_mutex_lock(&s->sync); for (struct bxfi_sandbox *s = self.dead; s; s = s->next) pthread_mutex_lock(&s->sync); } static void postfork_parent(void) { for (struct bxfi_sandbox *s = self.dead; s; s = s->next) pthread_mutex_unlock(&s->sync); for (struct bxfi_sandbox *s = self.alive; s; s = s->next) pthread_mutex_unlock(&s->sync); pthread_mutex_unlock(&self.sync); } static void postfork_child(void) { postfork_parent(); pthread_cond_t nil = PTHREAD_COND_INITIALIZER; memcpy(&self.cond, &nil, sizeof (nil)); if (self.alive) pthread_join(self.child_pump, NULL); for (struct bxfi_sandbox *s = self.alive; s; s = self.alive) { memset((void *) &s->props.status, 0, sizeof (s->props.status)); self.alive = s->next; s->next = self.dead; self.dead = s; } bxfi_reset_timeout_killer(); } static void init_atfork(void) { pthread_atfork(prefork, postfork_parent, postfork_child); } #endif static void init_child_pump(pid_t pid) { if (pthread_create(&self.child_pump, NULL, child_pump_fn, NULL)) goto thread_err; self.child_pump_active = 1; return; thread_err: perror("boxfort: could not initialize child pump"); kill(pid, SIGKILL); waitpid(pid, NULL, 0); abort(); } static void term_child_pump(void) { if (self.child_pump_active) { pthread_join(self.child_pump, NULL); self.child_pump_active = 0; } } static int find_exe(const char *progname, char *out, size_t size) { char *sptr = NULL; char *path = strdup(getenv("PATH")); char *p = strtok_r(path, ":", &sptr); while (p) { snprintf(out, size, "%s/%s", *p ? p : ".", progname); struct stat sb; int rc = stat(out, &sb); if (!rc && (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode))) break; p = strtok_r(NULL, ":", &sptr); } free(path); if (!p) return -ENOENT; return 0; } static char **dupenv(char **concat) { size_t len = 0, clen = 0; for (char **e = environ; *e; ++e, ++len) ; for (char **e = concat; *e; ++e, ++clen) ; char **dupe = malloc(sizeof (void *) * (len + clen + 1)); memcpy(dupe, environ, (len + 1) * sizeof (void *)); char **d = dupe + len; for (char **e = concat; *e; ++e) { char **de = dupe; for (; *de; ++de) { char *eq1 = strchr(*e, '='), *eq2 = strchr(*de, '='); if (!eq1 || !eq2) continue; size_t l1 = (size_t)(eq1 - *e), l2 = (size_t)(eq2 - *de); if (l1 != l2) continue; if (!strncmp(*e, *de, l1)) { *de = *e; break; } } if (!*de) { *d++ = *e; *d = NULL; } } return dupe; } int bxfi_exec(bxf_instance **out, bxf_sandbox *sandbox, int mantled, bxf_fn *fn, bxf_preexec *preexec, bxf_callback *callback, void *user, bxf_dtor user_dtor) { static char exe[PATH_MAX + 1]; #ifdef BXF_FORK_RESILIENCE static pthread_once_t atfork = PTHREAD_ONCE_INIT; pthread_once(&atfork, init_atfork); #endif char map_name[sizeof ("/bxfi_") + 21]; struct bxfi_sandbox *instance = NULL; struct bxfi_map local_ctx; pid_t pid = 0; memset(&local_ctx, 0, sizeof (local_ctx)); intptr_t errnum; int map_rc = -1; if (!exe[0] && (errnum = get_exe_path(exe, sizeof (exe))) < 0) return errnum; struct bxfi_addr addr; if (bxfi_normalize_fnaddr(fn, &addr) < 0) return -EINVAL; char dbg_full[PATH_MAX]; if (sandbox->debug.debugger) { const char *dbg = NULL; switch (sandbox->debug.debugger) { case BXF_DBG_GDB: dbg = "gdbserver"; break; case BXF_DBG_LLDB: dbg = "lldb-server"; break; default: return -EINVAL; } if (find_exe(dbg, dbg_full, sizeof (dbg_full)) < 0) return -ENOENT; } errnum = -ENOMEM; instance = malloc(sizeof (*instance)); if (!instance) goto err; *instance = (struct bxfi_sandbox) { .mantled = mantled, .callback = callback, .user = user, .user_dtor = user_dtor, }; if ((errnum = -pthread_mutex_init(&instance->sync, NULL))) goto err; if ((errnum = -pthread_cond_init(&instance->cond, NULL))) goto err; pid = fork(); if (pid == -1) { errnum = -errno; goto err; } else if (pid) { instance->start_monotonic = bxfi_timestamp_monotonic(); instance->wait_pid = pid; instance->props = (struct bxf_instance_s) { .sandbox = sandbox, .pid = pid, .status.alive = 1, .time.start = bxfi_timestamp(), .user = instance->user, }; if ((pid = wait_stop(pid)) <= 0) { errnum = -errno; goto err; } snprintf(map_name, sizeof (map_name), "/bxfi_%d", pid); size_t len = strlen(addr.soname); map_rc = bxfi_create_local_ctx(&local_ctx, map_name, len + 1); errnum = map_rc; if (map_rc < 0) goto err; local_ctx.ctx->ok = 0; local_ctx.ctx->fn = addr.addr; local_ctx.ctx->seg = addr.seg; local_ctx.ctx->pid = pid; local_ctx.ctx->suspend = sandbox->suspended; bxf_context ictx = sandbox->inherit.context; if (ictx) { #ifdef BXF_ARENA_REOPEN_SHM strcpy(local_ctx.ctx->context.name, ictx->arena->name); #else local_ctx.ctx->context.handle = ictx->arena->handle; #endif } memcpy(local_ctx.ctx + 1, addr.soname, len + 1); local_ctx.ctx->fn_soname_sz = len + 1; kill(pid, SIGCONT); if ((pid = wait_stop(pid)) <= 0) { errnum = -errno; goto err; } if (!local_ctx.ctx->ok) goto err; instance->props.pid = local_ctx.ctx->pid; if (sandbox->quotas.runtime > 0) if (bxfi_push_timeout(instance, sandbox->quotas.runtime) < 0) goto err; if (sandbox->iquotas.runtime > 0) if (bxfi_push_timeout(instance, sandbox->iquotas.runtime) < 0) goto err; pthread_mutex_lock(&self.sync); /* spawn a wait thread if no sandboxes are alive right now */ if (!self.alive) { term_child_pump(); init_child_pump(pid); } instance->next = self.alive; self.alive = instance; pthread_cond_broadcast(&self.cond); pthread_mutex_unlock(&self.sync); bxfi_unmap_local_ctx(&local_ctx); kill(pid, SIGCONT); if (sandbox->suspended) instance->props.status.stopped = 1; *out = &instance->props; return 0; } #if defined (HAVE_PR_SET_PDEATHSIG) int pdeathsig = sandbox->debug.debugger ? SIGTERM : SIGKILL; prctl(PR_SET_PDEATHSIG, pdeathsig); #endif pid = getpid(); instance->props = (struct bxf_instance_s) { .sandbox = sandbox, .pid = pid, }; if (preexec && preexec(&instance->props) < 0) abort(); if (setup_limits(sandbox) < 0) abort(); if (setup_inheritance(sandbox) < 0) abort(); setsid(); raise(SIGSTOP); snprintf(map_name, sizeof (map_name), "/bxfi_%d", pid); char env_map[sizeof ("BXFI_MAP=") + sizeof (map_name)]; snprintf(env_map, sizeof (env_map), "BXFI_MAP=%s", map_name); char **env = dupenv((char *[]) { env_map, "GMON_OUT_PREFIX=sandbox-gmon", NULL }); char *fullpath = exe; char *argv[16] = { "boxfort-worker" }; size_t argc = 1; if (sandbox->debug.debugger) { char port[11]; switch (sandbox->debug.debugger) { case BXF_DBG_GDB: snprintf(port, sizeof (port), ":%d", sandbox->debug.tcp); break; case BXF_DBG_LLDB: argv[argc++] = "gdbserver"; snprintf(port, sizeof (port), "*:%d", sandbox->debug.tcp); break; default: abort(); } argv[argc++] = port; argv[argc++] = exe; fullpath = dbg_full; } argv[argc++] = NULL; execve(fullpath, argv, env); _exit(errno); err: if (pid) { kill(pid, SIGKILL); waitpid(pid, NULL, 0); } if (!map_rc) { bxfi_unmap_local_ctx(&local_ctx); shm_unlink(map_name); } free(instance); return errnum; } int bxf_term(bxf_instance *instance) { if (instance->status.alive) return -EINVAL; struct bxfi_sandbox *sb = bxfi_cont(instance, struct bxfi_sandbox, props); if (!sb->waited) return -EINVAL; pthread_mutex_lock(&self.sync); struct bxfi_sandbox **prev = &self.dead; int ok = 0; for (struct bxfi_sandbox *s = self.dead; s; s = s->next) { if (s == sb) { *prev = s->next; ok = 1; break; } prev = &s->next; } pthread_mutex_unlock(&self.sync); if (!ok) return -EINVAL; if (sb->user && sb->user_dtor) sb->user_dtor(instance, sb->user); if (sb->mantled) free((void *) instance->sandbox); pthread_mutex_destroy(&sb->sync); pthread_cond_destroy(&sb->cond); free(sb); return 0; } int bxf_wait(bxf_instance *instance, double timeout) { if (timeout < 0) timeout = 0; static const size_t nanosecs = 1000000000; size_t to_ns = (timeout - (size_t) timeout) * nanosecs; size_t to_s = timeout; struct timespec timeo; #if defined (HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP) timeo = (struct timespec) { .tv_sec = to_ns, .tv_nsec = to_s }; typedef int (*const f_timedwait)(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); static f_timedwait pthread_cond_timedwait = pthread_cond_timedwait_relative_np; #elif defined (HAVE_CLOCK_GETTIME) clock_gettime(CLOCK_REALTIME, &timeo); size_t new_nsec = (timeo.tv_nsec + to_ns) % nanosecs; timeo.tv_sec += to_s + (timeo.tv_nsec + to_ns) / nanosecs; timeo.tv_nsec = new_nsec; #elif defined (HAVE_GETTIMEOFDAY) struct timeval tv; gettimeofday(&tv, NULL); timeo = (struct timespec) { .tv_sec = tv.tv_sec + to_s + (tv.tv_usec * 1000 + to_ns) / nanosecs, .tv_nsec = (tv.tv_usec * 1000 + to_ns) % nanosecs, }; #else # error bxf_wait needs a way to get the current time. #endif struct bxfi_sandbox *sb = bxfi_cont(instance, struct bxfi_sandbox, props); pthread_mutex_lock(&sb->sync); int rc = 0; while (!sb->waited) { if (timeout == BXF_FOREVER || !isfinite(timeout)) rc = pthread_cond_wait(&sb->cond, &sb->sync); else rc = pthread_cond_timedwait(&sb->cond, &sb->sync, &timeo); if (!rc || rc == ETIMEDOUT) break; } if (!rc) sb->waited = 1; pthread_mutex_unlock(&sb->sync); if (rc) return -rc; pthread_mutex_lock(&self.sync); if (!self.alive) term_child_pump(); pthread_mutex_unlock(&self.sync); /* Enforce the deletion of the shm file */ if (!instance->status.alive) { char map_name[sizeof ("/bxfi_") + 21]; snprintf(map_name, sizeof (map_name), "/bxfi_%d", (int) instance->pid); shm_unlink(map_name); } return 0; } void bxf_suspend(bxf_instance *instance) { kill((pid_t) instance->pid, SIGSTOP); } void bxf_resume(bxf_instance *instance) { kill((pid_t) instance->pid, SIGCONT); } BoxFort-master/src/sandbox-posix.h0000644000175000017500000000440613603450524016136 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef SANDBOX_POSIX_H_ #define SANDBOX_POSIX_H_ #include #include #include #include "context.h" struct bxfi_context { size_t total_sz; const void *fn; size_t seg; pid_t pid; struct bxfi_ctx_arena context; size_t fn_soname_sz; int ok; int suspend; }; struct bxfi_map { struct bxfi_context *ctx; int fd; }; struct bxfi_sandbox { struct bxf_instance_s props; /* A sandbox is said to be mantled if there is an unique instance managing its memory. */ int mantled; /* Set to 1 if the instance has been waited for in the child pump */ int waited; /* The monotonic timestamp representing the start of the sandbox instance. * Only used to calculate more accurate run times */ uint64_t start_monotonic; /* The child PID. Might be different from the sandbox PID, e.g. if run * with a debugging server. */ pid_t wait_pid; pthread_mutex_t sync; pthread_cond_t cond; bxf_callback *callback; void *user; bxf_dtor *user_dtor; struct bxfi_sandbox *next; }; #endif /* !SANDBOX_POSIX_H_ */ BoxFort-master/src/sandbox-windows.c0000644000175000017500000004324013603450524016460 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include "addr.h" #include "context.h" #include "sandbox.h" #include "timestamp.h" #include "timeout.h" int bxfi_check_sandbox_ctx(void) { int is_sandbox = !!_tcsstr(GetCommandLine(), TEXT("BXFI_MAP=")); /* If we are a sandbox, first thing we do is disable the crash dialog */ if (is_sandbox) SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); return is_sandbox; } static int bxfi_create_local_ctx(struct bxfi_map *map, LPTCH name, size_t sz) { HANDLE shm = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sz, name); if (!shm || GetLastError() == ERROR_ALREADY_EXISTS) return -EEXIST; struct bxfi_context *ctx = MapViewOfFile(shm, FILE_MAP_ALL_ACCESS, 0, 0, sizeof (struct bxfi_context) + sz); if (!ctx) return -ENOMEM; *map = (struct bxfi_map) { .ctx = ctx, .handle = shm }; memcpy(map->map_name, name, (_tcslen(name) + 1) * sizeof (TCHAR)); return 0; } int bxfi_init_sandbox_ctx(struct bxfi_map *map) { TCHAR *env = _tcsstr(GetCommandLine(), TEXT("BXFI_MAP=")); TCHAR *name = env + sizeof ("BXFI_MAP=") - 1; HANDLE shm = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, name); if (!shm) return -ENOENT; struct bxfi_context *ctx = MapViewOfFile(shm, FILE_MAP_ALL_ACCESS, 0, 0, sizeof (struct bxfi_context)); errno = -ENOMEM; if (!ctx) goto error; DWORD size = ctx->total_sz; errno = -EINVAL; if (!UnmapViewOfFile(ctx)) goto error; ctx = MapViewOfFile(shm, FILE_MAP_ALL_ACCESS, 0, 0, size); errno = -ENOMEM; if (!ctx) goto error; *map = (struct bxfi_map) { .ctx = ctx, .handle = shm }; memcpy(map->map_name, name, (_tcslen(name) + 1) * sizeof (TCHAR)); return 0; error: if (shm) CloseHandle(shm); return -errno; } int bxfi_unmap_local_ctx(struct bxfi_map *map) { UnmapViewOfFile(map->ctx); CloseHandle(map->handle); return 0; } int bxfi_term_sandbox_ctx(struct bxfi_map *map) { HANDLE sync = map->ctx->sync; int waitfordebugger = map->ctx->suspend; int rc = bxfi_unmap_local_ctx(map); SetEvent(sync); if (waitfordebugger) { while (!IsDebuggerPresent()) Sleep(100); } return rc; } struct callback_ctx { HANDLE whandle; bxf_callback *callback; struct bxfi_sandbox *instance; }; #ifndef STATUS_BAD_STACK # define STATUS_BAD_STACK 0xC0000028L #endif /* * NTSTATUS specification, from ntstatus.h: * * > Values are 32 bit values laid out as follows: * > * > 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 * > 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 * > +---+-+-+-----------------------+-------------------------------+ * > |Sev|C|R| Facility | Code | * > +---+-+-+-----------------------+-------------------------------+ * > * > where * > * > Sev - is the severity code * > * > 00 - Success * > 01 - Informational * > 10 - Warning * > 11 - Error * > * > C - is the Customer code flag * > * > R - is a reserved bit * > * > Facility - is the facility code * > * > Code - is the facility's status code * * We consider that all exit codes with error severity bits that cannot * be directly translated to translate to SIGSYS. * */ static void get_status(HANDLE handle, struct bxf_instance_s *instance) { DWORD exit_code; GetExitCodeProcess(handle, &exit_code); unsigned int sig = 0; switch (exit_code) { case STATUS_FLOAT_DENORMAL_OPERAND: case STATUS_FLOAT_DIVIDE_BY_ZERO: case STATUS_FLOAT_INEXACT_RESULT: case STATUS_FLOAT_INVALID_OPERATION: case STATUS_FLOAT_OVERFLOW: case STATUS_FLOAT_STACK_CHECK: case STATUS_FLOAT_UNDERFLOW: case STATUS_INTEGER_DIVIDE_BY_ZERO: case STATUS_INTEGER_OVERFLOW: sig = SIGFPE; break; case STATUS_ILLEGAL_INSTRUCTION: case STATUS_PRIVILEGED_INSTRUCTION: case STATUS_NONCONTINUABLE_EXCEPTION: sig = SIGILL; break; case STATUS_ACCESS_VIOLATION: case STATUS_DATATYPE_MISALIGNMENT: case STATUS_ARRAY_BOUNDS_EXCEEDED: case STATUS_GUARD_PAGE_VIOLATION: case STATUS_IN_PAGE_ERROR: case STATUS_NO_MEMORY: case STATUS_INVALID_DISPOSITION: case STATUS_BAD_STACK: case STATUS_STACK_OVERFLOW: sig = SIGSEGV; break; case STATUS_CONTROL_C_EXIT: sig = SIGINT; break; default: break; } if (!sig && exit_code & 0xC0000000) sig = SIGABRT; instance->status.signal = sig; instance->status.exit = exit_code; instance->status.alive = 0; } static void CALLBACK handle_child_terminated(PVOID lpParameter, BOOLEAN TimerOrWaitFired) { (void) TimerOrWaitFired; uint64_t mts_end = bxfi_timestamp_monotonic(); uint64_t ts_end = bxfi_timestamp(); struct callback_ctx *ctx = lpParameter; struct bxfi_sandbox *instance = ctx->instance; bxf_callback *callback = ctx->callback; bxfi_cancel_timeout(instance); get_status(instance->proc, &instance->props); instance->props.time.end = ts_end; instance->props.time.elapsed = mts_end - instance->start_monotonic; HANDLE whandle = ctx->whandle; free(lpParameter); UnregisterWaitEx(whandle, NULL); if (callback) callback(&instance->props); SetEvent(instance->waited); } struct bxfi_prepare_ctx { HANDLE *handles; uint8_t *inherited; size_t size; size_t capacity; LPPROC_THREAD_ATTRIBUTE_LIST attr; }; static void prepare_ctx_term(struct bxfi_prepare_ctx *ctx) { for (size_t i = 0; i < ctx->size; ++i) { if (!ctx->inherited[i]) { if (!SetHandleInformation(ctx->handles[i], HANDLE_FLAG_INHERIT, 0)) continue; } } free(ctx->handles); free(ctx->inherited); if (ctx->attr) free(ctx->attr); ctx->capacity = 0; } static int do_inherit_handle(bxf_fhandle handle, void *user) { struct bxfi_prepare_ctx *ctx = user; if (!ctx->handles) { ctx->handles = malloc(32 * sizeof (HANDLE)); ctx->inherited = malloc(32); ctx->capacity = 32; } /* Reserve a slot for the sync event handle */ if (ctx->size + 2 >= ctx->capacity) { ctx->capacity *= 1.61; ctx->handles = realloc(ctx->handles, ctx->capacity); ctx->inherited = realloc(ctx->inherited, ctx->capacity); } ctx->handles[ctx->size++] = handle; ctx->inherited[ctx->size - 1] = 1; DWORD info; if (!GetHandleInformation(handle, &info)) return -EINVAL; if (info & HANDLE_FLAG_INHERIT) return 0; if (!SetHandleInformation(handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) return -EINVAL; ctx->inherited[ctx->size - 1] = 0; return 0; } static int prepare_context(bxf_context ictx, bxf_sandbox *sandbox, HANDLE sync, STARTUPINFOEX *si, struct bxfi_prepare_ctx *prep) { if (ictx) { if (bxfi_context_prepare(ictx, do_inherit_handle, prep) < 0) return 0; } if (!prep->handles) { prep->handles = malloc(sizeof (HANDLE)); *prep->handles = sync; prep->size = 1; } else { prep->handles[prep->size++] = sync; } if (!sandbox->inherit.files) { SIZE_T attrsz = 0; InitializeProcThreadAttributeList(NULL, 1, 0, &attrsz); LPPROC_THREAD_ATTRIBUTE_LIST attr = malloc(attrsz); if (!attr) return 0; BOOL ok = InitializeProcThreadAttributeList(attr, 1, 0, &attrsz); if (!ok) return 0; si->lpAttributeList = attr; ok = UpdateProcThreadAttribute(attr, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, prep->handles, prep->size * sizeof (HANDLE), NULL, NULL); prep->attr = attr; if (!ok) return 0; } return 1; } int bxfi_exec(bxf_instance **out, bxf_sandbox *sandbox, int mantled, bxf_fn *fn, bxf_preexec *preexec, bxf_callback *callback, void *user, bxf_dtor user_dtor) { int errnum = 0; struct bxfi_sandbox *instance = NULL; BOOL success = FALSE; struct bxfi_prepare_ctx prep = { .handles = NULL, }; /* Process params and allocate relevant ressources */ struct bxfi_addr addr; if (bxfi_normalize_fnaddr(fn, &addr) < 0) return -EINVAL; errnum = -ENOMEM; instance = malloc(sizeof (*instance)); if (!instance) goto error; instance->mantled = mantled; instance->user = user; instance->user_dtor = user_dtor; instance->waited = CreateEvent(NULL, FALSE, FALSE, NULL); if (!instance->waited) goto error; PROCESS_INFORMATION info; STARTUPINFOEX si = { .StartupInfo.cb = sizeof (si) }; ZeroMemory(&info, sizeof (info)); SECURITY_ATTRIBUTES inherit_handle = { .nLength = sizeof (SECURITY_ATTRIBUTES), .bInheritHandle = TRUE }; HANDLE sync = CreateEvent(&inherit_handle, FALSE, FALSE, NULL); errnum = -EPROTO; if (!sync) goto error; /* Process initialization */ bxf_context ictx = sandbox->inherit.context; if (!prepare_context(ictx, sandbox, sync, &si, &prep)) goto error; TCHAR filename[MAX_PATH]; GetModuleFileName(NULL, filename, MAX_PATH); uint64_t ts_start = bxfi_timestamp(); uint64_t mts_start = bxfi_timestamp_monotonic(); TCHAR map_name[sizeof ("Local\\bxfi_") + 21]; _sntprintf(map_name, sizeof (map_name), TEXT("Local\\bxfi_%lu"), (unsigned long)GetCurrentProcessId()); TCHAR env_map[sizeof ("BXFI_MAP=") + sizeof (map_name) + 2]; memset(env_map, 0, sizeof (env_map)); _sntprintf(env_map, sizeof (env_map), "BXFI_MAP=%s", map_name); if (sandbox->debug.debugger) { TCHAR *dbg = NULL; TCHAR *cmdline = NULL; SIZE_T size; switch (sandbox->debug.debugger) { case BXF_DBG_WINDBG: { dbg = TEXT("windbg"); TCHAR *fmt = TEXT("boxfort-worker -server tcp:port=%d %s %s"); size = _sctprintf(fmt, sandbox->debug.tcp, filename, env_map); cmdline = malloc(sizeof (TCHAR) * (size + 1)); _sntprintf(cmdline, size, fmt, sandbox->debug.tcp, filename, env_map); } break; case BXF_DBG_GDB: { dbg = TEXT("gdbserver"); TCHAR *fmt = TEXT("boxfort-worker :%d %s %s"); size = _sctprintf(fmt, sandbox->debug.tcp, filename, env_map); cmdline = malloc(sizeof (TCHAR) * size); _sntprintf(cmdline, size, fmt, sandbox->debug.tcp, filename, env_map); } break; case BXF_DBG_LLDB: { dbg = TEXT("lldb-server"); TCHAR *fmt = TEXT("boxfort-worker gdbserver *:%d %s %s"); size = _sctprintf(fmt, sandbox->debug.tcp, filename, env_map); cmdline = malloc(sizeof (TCHAR) * size); _sntprintf(cmdline, size, fmt, sandbox->debug.tcp, filename, env_map); } break; default: errnum = -EINVAL; goto error; } /* _sntprinf does not null-terminate its output */ cmdline[size] = '\0'; DWORD pathsz = GetEnvironmentVariable(TEXT("PATH"), NULL, 0); TCHAR *path = malloc(pathsz * sizeof (TCHAR)); TCHAR *dbg_full = NULL; GetEnvironmentVariable(TEXT("PATH"), path, pathsz); pathsz = SearchPath(path, dbg, TEXT(".exe"), 0, NULL, NULL); if (!pathsz) goto file_not_found; dbg_full = malloc(pathsz * sizeof (TCHAR)); pathsz = SearchPath(path, dbg, TEXT(".exe"), pathsz, dbg_full, NULL); if (!pathsz) { file_not_found: free(dbg_full); free(path); free(cmdline); errnum = -ENOENT; goto error; } success = CreateProcess(dbg_full, cmdline, NULL, NULL, TRUE, CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &info); free(dbg_full); free(path); free(cmdline); } else { TCHAR *fmt = TEXT("boxfort-worker %s"); SIZE_T size = _sctprintf(fmt, filename, env_map); TCHAR *cmdline = malloc(sizeof (TCHAR) * size); _sntprintf(cmdline, size, fmt, env_map); success = CreateProcess(filename, cmdline, NULL, NULL, TRUE, CREATE_SUSPENDED | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &si.StartupInfo, &info); free(cmdline); } errnum = -EPROTO; if (!success) goto error; if (si.lpAttributeList) DeleteProcThreadAttributeList(si.lpAttributeList); instance->props = (struct bxf_instance_s) { .sandbox = sandbox, .pid = info.dwProcessId, .status.alive = 1, .time.start = ts_start, .user = instance->user, }; instance->start_monotonic = mts_start; if (sandbox->quotas.runtime > 0) if (bxfi_push_timeout(instance, sandbox->quotas.runtime) < 0) goto error; if (sandbox->iquotas.runtime > 0) if (bxfi_push_timeout(instance, sandbox->iquotas.runtime) < 0) goto error; if (preexec && preexec(&instance->props) < 0) goto error; if (prep.capacity) prepare_ctx_term(&prep); instance->proc = info.hProcess; size_t len = strlen(addr.soname); struct bxfi_map map; if ((errnum = bxfi_create_local_ctx(&map, map_name, len + 1)) < 0) goto error; map.ctx->sync = sync; map.ctx->suspend = sandbox->suspended; map.ctx->fn = addr.addr; map.ctx->seg = addr.seg; if (ictx) map.ctx->context.handle = bxfi_context_gethandle(ictx); memcpy(map.ctx + 1, addr.soname, len + 1); map.ctx->fn_soname_sz = len + 1; errnum = -ECHILD; if (ResumeThread(info.hThread) == (DWORD) -1) goto error; /* wait until the child has initialized itself */ HANDLE handles[] = { info.hProcess, sync }; DWORD wres = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (wres == WAIT_OBJECT_0) goto error; instance->mainthread = info.hThread; CloseHandle(sync); struct callback_ctx *wctx = malloc(sizeof (*wctx)); *wctx = (struct callback_ctx) { .instance = instance, .callback = callback, }; RegisterWaitForSingleObject( &wctx->whandle, info.hProcess, handle_child_terminated, wctx, INFINITE, WT_EXECUTELONGFUNCTION | WT_EXECUTEONLYONCE); bxfi_unmap_local_ctx(&map); bxfi_addr_term(&addr); if (sandbox->suspended) instance->props.status.stopped = 1; *out = &instance->props; return 0; error: if (prep.capacity) prepare_ctx_term(&prep); if (si.lpAttributeList) DeleteProcThreadAttributeList(si.lpAttributeList); if (sync) CloseHandle(sync); if (success) { CloseHandle(info.hThread); TerminateProcess(info.hProcess, 3); CloseHandle(info.hProcess); } bxfi_addr_term(&addr); return errnum; } int bxf_term(bxf_instance *instance) { struct bxfi_sandbox *sb = bxfi_cont(instance, struct bxfi_sandbox, props); if (sb->user && sb->user_dtor) sb->user_dtor(instance, sb->user); if (sb->mantled) free((void *) instance->sandbox); CloseHandle(sb->proc); CloseHandle(sb->mainthread); CloseHandle(sb->waited); free(sb); return 0; } int bxf_wait(bxf_instance *instance, double timeout) { DWORD dwtimeout; if (timeout == BXF_FOREVER || !isfinite(timeout)) dwtimeout = INFINITE; else dwtimeout = timeout * 1000; struct bxfi_sandbox *sb = bxfi_cont(instance, struct bxfi_sandbox, props); if (WaitForSingleObject(sb->waited, dwtimeout) != WAIT_OBJECT_0) return -ECHILD; return 0; } void bxf_suspend(bxf_instance *instance) { struct bxfi_sandbox *sb = bxfi_cont(instance, struct bxfi_sandbox, props); SuspendThread(sb->mainthread); } void bxf_resume(bxf_instance *instance) { struct bxfi_sandbox *sb = bxfi_cont(instance, struct bxfi_sandbox, props); ResumeThread(sb->mainthread); } BoxFort-master/src/sandbox-windows.h0000644000175000017500000000377413603450524016475 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef SANDBOX_WINDOWS_H_ #define SANDBOX_WINDOWS_H_ #include #include "context.h" struct bxfi_context { size_t total_sz; const void *fn; size_t seg; struct bxfi_ctx_arena context; size_t fn_soname_sz; HANDLE sync; int suspend; }; struct bxfi_map { struct bxfi_context *ctx; HANDLE handle; TCHAR map_name[sizeof ("bxfi_") + 21]; }; struct bxfi_sandbox { struct bxf_instance_s props; HANDLE proc; HANDLE mainthread; /* A sandbox is said to be mantled if there is an unique instance managing its memory. */ int mantled; /* The monotonic timestamp representing the start of the sandbox instance. * Only used to calculate more accurate run times */ uint64_t start_monotonic; void *user; bxf_dtor *user_dtor; HANDLE waited; }; #endif /* !SANDBOX_WINDOWS_H_ */ BoxFort-master/src/sandbox.c0000644000175000017500000000606513603450524014774 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include "addr.h" #include "context.h" #include "exe.h" #include "sandbox.h" static int bxfi_main(void) { struct bxfi_map local_ctx; if (bxfi_init_sandbox_ctx(&local_ctx) < 0) abort(); struct bxfi_addr addr = { .soname = (char *) (local_ctx.ctx + 1), .addr = local_ctx.ctx->fn, .seg = local_ctx.ctx->seg, }; bxf_fn *fn = bxfi_denormalize_fnaddr(&addr); if (!fn) abort(); if (bxfi_context_inherit(&local_ctx.ctx->context) < 0) abort(); if (bxfi_term_sandbox_ctx(&local_ctx) < 0) abort(); return fn(); } BXFI_INITIALIZER(patch_main) static void patch_main(void) { if (!bxfi_check_sandbox_ctx()) return; if (bxfi_exe_patch_main((bxfi_exe_fn *) bxfi_main) < 0) abort(); } int bxf_spawn_struct(bxf_instance **out, bxf_spawn_params params) { if (!params->fn) return -EINVAL; struct bxf_sandbox_s *sandbox = calloc(1, sizeof (*sandbox)); if (!sandbox) return -ENOMEM; /* 2nd parameter must be the start of the BXFI_SANDBOX_FIELDS in the parameter structure */ memcpy(sandbox, ¶ms->callback + 1, sizeof (*sandbox)); int rc; if ((rc = bxfi_exec(out, sandbox, 1, params->fn, params->preexec, params->callback, params->user, params->user_dtor))) free(sandbox); return rc; } int bxf_run_struct(bxf_spawn_params params) { bxf_instance *box; int rc; if ((rc = bxf_spawn_struct(&box, params))) return rc; rc = bxf_wait(box, BXF_FOREVER); bxf_term(box); return rc; } int bxf_start_struct(bxf_instance **out, bxf_sandbox *sandbox, bxf_start_params params) { return bxfi_exec(out, sandbox, 0, params->fn, params->preexec, params->callback, params->user, params->user_dtor); } BoxFort-master/src/sandbox.h0000644000175000017500000000445313603450524015000 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef SANDBOX_H_ #define SANDBOX_H_ #include "boxfort.h" #include "config.h" /* *INDENT-OFF* - formatters try to add spaces here */ #include BXFI_STR(sandbox-BXF_OS_FAMILY.h) /* *INDENT-ON* */ int bxfi_exec(bxf_instance **out, bxf_sandbox *sandbox, int mantled, bxf_fn *fn, bxf_preexec *preexec, bxf_callback *callback, void *user, bxf_dtor user_dtor); int bxfi_check_sandbox_ctx(void); int bxfi_init_sandbox_ctx(struct bxfi_map *map); int bxfi_term_sandbox_ctx(struct bxfi_map *map); #if defined (_MSC_VER) # define BXFI_INITIALIZER_(Fn, Prefix) \ static void Fn(void); \ __pragma(section(".CRT$XCU", read)) \ __declspec(allocate(".CRT$XCU")) void(*Fn ## _init)(void) = Fn; \ __pragma(comment(linker, "/include:" Prefix #Fn "_init")) # ifdef _WIN64 # define BXFI_INITIALIZER(Fn) BXFI_INITIALIZER_(Fn, "") # else # define BXFI_INITIALIZER(Fn) BXFI_INITIALIZER_(Fn, "_") # endif #elif defined (__GNUC__) # define BXFI_INITIALIZER(...) __attribute__((constructor)) #else # error Compiler not supported #endif #endif /* !SANDBOX_H_ */ BoxFort-master/src/timeout-posix.c0000644000175000017500000001423113603450524016156 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include "config.h" #include "sandbox.h" struct bxfi_timeout_request { struct timespec timeout; pid_t pid; struct bxfi_sandbox *sb; int cancelled; struct bxfi_timeout_request *next; }; static struct { struct bxfi_timeout_request *volatile requests; struct bxfi_timeout_request *volatile cancelled; pthread_t thread; int thread_active; pthread_mutex_t sync; pthread_cond_t cond; pthread_cond_t termcond; } self = { .sync = PTHREAD_MUTEX_INITIALIZER, .cond = PTHREAD_COND_INITIALIZER, .termcond = PTHREAD_COND_INITIALIZER, }; static int timespec_cmp(struct timespec *a, struct timespec *b) { if (a->tv_sec < b->tv_sec) return -1; if (a->tv_sec > b->tv_sec) return 1; if (a->tv_nsec < b->tv_nsec) return -1; if (a->tv_nsec > b->tv_nsec) return 1; return 0; } static void to_timespec(double timeout, struct timespec *timeo) { static const uint64_t nanosecs = 1000000000; uint64_t to_ns = (timeout - (uint64_t) timeout) * nanosecs; uint64_t to_s = timeout; #if defined (HAVE_CLOCK_GETTIME) clock_gettime(CLOCK_REALTIME, timeo); uint64_t new_nsec = (timeo->tv_nsec + to_ns) % nanosecs; timeo->tv_sec += to_s + (timeo->tv_nsec + to_ns) / nanosecs; timeo->tv_nsec = new_nsec; #elif defined (HAVE_GETTIMEOFDAY) struct timeval tv; gettimeofday(&tv, NULL); *timeo = (struct timespec) { .tv_sec = tv.tv_sec + to_s + (tv.tv_usec * 1000 + to_ns) / nanosecs, .tv_nsec = (tv.tv_usec * 1000 + to_ns) % nanosecs, }; #else # error No way to get a viable timespec. #endif } static void *timeout_killer_fn(void *nil) { pthread_mutex_lock(&self.sync); while (!self.requests) pthread_cond_wait(&self.cond, &self.sync); struct bxfi_timeout_request *req; for (;;) { while (self.cancelled) { req = self.cancelled; self.cancelled = req->next; free(req); } req = self.requests; if (!req) goto end; int rc = pthread_cond_timedwait(&self.cond, &self.sync, &req->timeout); if (!rc || req->cancelled) continue; assert(rc == ETIMEDOUT); kill(req->pid, SIGPROF); pthread_mutex_lock(&req->sb->sync); req->sb->props.status.timed_out = 1; pthread_mutex_unlock(&req->sb->sync); self.requests = req->next; free(req); } end: pthread_cond_broadcast(&self.termcond); pthread_mutex_unlock(&self.sync); return nil; } void bxfi_reset_timeout_killer(void) { pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; memcpy(&self.sync, &mutex, sizeof (mutex)); memcpy(&self.cond, &cond, sizeof (cond)); memcpy(&self.termcond, &cond, sizeof (cond)); if (self.requests) pthread_join(self.thread, NULL); } int bxfi_push_timeout(struct bxfi_sandbox *instance, double timeout) { int rc; struct bxfi_timeout_request *req = calloc(1, sizeof (*req)); if (!req) return -ENOMEM; to_timespec(timeout, &req->timeout); req->sb = instance; req->pid = instance->props.pid; pthread_mutex_lock(&self.sync); if (!self.requests) { if (self.thread_active) pthread_join(self.thread, NULL); self.thread_active = 1; rc = -pthread_create(&self.thread, NULL, timeout_killer_fn, NULL); if (rc) goto error; } struct bxfi_timeout_request *volatile *nptr = &self.requests; for (struct bxfi_timeout_request *r = self.requests; r; r = r->next) { if (timespec_cmp(&r->timeout, &req->timeout) > 0) break; nptr = &r->next; } *nptr = req; pthread_cond_broadcast(&self.cond); pthread_cond_broadcast(&self.termcond); pthread_mutex_unlock(&self.sync); return 0; error: pthread_mutex_unlock(&self.sync); free(req); return rc; } void bxfi_cancel_timeout(struct bxfi_sandbox *instance) { pthread_mutex_lock(&self.sync); int cancelled = 0; struct bxfi_timeout_request *volatile *nptr = &self.requests; for (struct bxfi_timeout_request *r = self.requests; r; r = r->next) { if (r->pid == (pid_t) instance->props.pid) { *nptr = r->next; r->next = self.cancelled; self.cancelled = r; r->cancelled = cancelled = 1; } nptr = &r->next; } if (cancelled) { pthread_cond_broadcast(&self.cond); if (!self.requests) { while (self.cancelled && !self.requests) pthread_cond_wait(&self.termcond, &self.sync); if (self.requests) goto end; if (self.thread_active) { pthread_join(self.thread, NULL); self.thread_active = 0; } } } end: pthread_mutex_unlock(&self.sync); } BoxFort-master/src/timeout-windows.c0000644000175000017500000000373713603450524016517 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include "config.h" #include "sandbox.h" #define BXFI_TIMEOUT_STATUS 0xEFFFFFFF void CALLBACK timeout_killer_fn(void *lpParameter, BOOLEAN TimerOrWaitFired) { (void) TimerOrWaitFired; struct bxfi_sandbox *sb = lpParameter; if (WaitForSingleObject(sb->proc, 0) == WAIT_OBJECT_0) return; TerminateProcess(sb->proc, BXFI_TIMEOUT_STATUS); sb->props.status.timed_out = 1; } int bxfi_push_timeout(struct bxfi_sandbox_s *instance, double timeout) { HANDLE timer; BOOL ok = CreateTimerQueueTimer(&timer, NULL, timeout_killer_fn, instance, timeout * 1000, 0, WT_EXECUTEDEFAULT); if (!ok) return -1; return 0; } void bxfi_cancel_timeout(struct bxfi_sandbox_s *instance) { (void) instance; } void bxfi_reset_timeout_killer(void) { } BoxFort-master/src/timeout.h0000644000175000017500000000257513603450524015033 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef TIMEOUT_H_ #define TIMEOUT_H_ int bxfi_push_timeout(struct bxfi_sandbox *instance, double timeout); void bxfi_cancel_timeout(struct bxfi_sandbox *instance); void bxfi_reset_timeout_killer(void); #endif /* !TIMEOUT_H_ */ BoxFort-master/src/timestamp.c0000644000175000017500000000656713603450524015350 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include "config.h" #include "timestamp.h" #define KILO 1000ull #define MEGA (KILO * 1000ull) #define GIGA (MEGA * 1000ull) #if defined (HAVE_GETTIMEOFDAY) # include #endif #if defined (HAVE_CLOCK_GETTIME) # include #endif #if defined (__APPLE__) # include # include # include #endif #if defined (_WIN32) || defined (__CYGWIN__) # include #endif #if defined (HAVE_CLOCK_GETTIME) # if defined (HAVE_CLOCK_MONOTONIC_RAW) # define CLOCK CLOCK_MONOTONIC_RAW # else # define CLOCK CLOCK_MONOTONIC # endif #endif uint64_t bxfi_timestamp(void) { #if defined (HAVE_CLOCK_GETTIME) struct timespec now; clock_gettime(CLOCK_REALTIME, &now); return now.tv_sec * GIGA + now.tv_nsec; #elif defined (HAVE_GETTIMEOFDAY) struct timeval now; gettimeofday(&now, NULL); return now.tv_sec * GIGA + now.tv_usec * KILO; #elif defined (_WIN32) || defined (__CYGWIN__) FILETIME ftime; SYSTEMTIME systime; GetSystemTime(&systime); SystemTimeToFileTime(&systime, &ftime); ULARGE_INTEGER ts = { .LowPart = ftime.dwLowDateTime, .HighPart = ftime.dwHighDateTime, }; static const uint64_t epoch = 116444736000000000ull; return (ts.QuadPart - epoch) / (10 * MEGA) + systime.wMilliseconds * KILO; #else errno = ENOTSUP; return (uint64_t) -1; #endif } uint64_t bxfi_timestamp_monotonic(void) { #if defined (HAVE_CLOCK_GETTIME) struct timespec now; clock_gettime(CLOCK, &now); return now.tv_sec * GIGA + now.tv_nsec; #elif defined (__APPLE__) clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); int res = clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); return mts.tv_sec * GIGA + mts.tv_nsec; #elif defined (_WIN32) || defined (__CYGWIN__) LARGE_INTEGER freq, count; if (!QueryPerformanceFrequency(&freq) || !QueryPerformanceCounter(&count)) return -1; uint64_t sec = count.QuadPart / freq.QuadPart; uint64_t nano = ((count.QuadPart * GIGA) / freq.QuadPart) % GIGA; return sec * GIGA + nano; #else errno = ENOTSUP; return (uint64_t) -1; #endif } BoxFort-master/src/timestamp.h0000644000175000017500000000247313603450524015345 0ustar sasasasa/* * The MIT License (MIT) * * Copyright © 2016 Franklin "Snaipe" Mathieu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef TIMESTAMP_H_ #define TIMESTAMP_H_ #include uint64_t bxfi_timestamp(void); uint64_t bxfi_timestamp_monotonic(void); #endif /* !TIMESTAMP_H_ */ BoxFort-master/test/0002755000175000017500000000000013603450524013355 5ustar sasasasaBoxFort-master/test/cram/0002755000175000017500000000000013603450524014277 5ustar sasasasaBoxFort-master/test/cram/core.t0000644000175000017500000000041513603450524015412 0ustar sasasasaTesting basic samples $ nested.c.bin I am a worker! I am a nested worker! Testing whether the callbacks are working $ callback.c.bin Child exited with code 5 Testing if the context sample behave as expected $ context.c.bin my_int = 42 my_long = 24 BoxFort-master/test/meson.build0000644000175000017500000000074513603450524015523 0ustar sasasasash = find_program('sh', required: false) cram = find_program('cram', required: false) if sh.found() and cram.found() env = environment() env.prepend('PATH', join_paths(meson.current_build_dir(), '..', 'sample'), join_paths(meson.current_build_dir(), '..', 'sample')) env.set('LC_ALL', 'en_US.utf8') env.set('MSYS2_ARG_CONV_EXCL', '--filter=') env.set('TERM', 'dumb') test('cram tests', cram, args: [join_paths(meson.current_source_dir(), 'cram')], env: env) endif