summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /security/sandbox/chromium
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/sandbox/chromium')
-rw-r--r--security/sandbox/chromium/LICENSE27
-rw-r--r--security/sandbox/chromium/base/at_exit.cc114
-rw-r--r--security/sandbox/chromium/base/at_exit.h87
-rw-r--r--security/sandbox/chromium/base/atomic_ref_count.h69
-rw-r--r--security/sandbox/chromium/base/atomic_sequence_num.h33
-rw-r--r--security/sandbox/chromium/base/atomicops.h150
-rw-r--r--security/sandbox/chromium/base/atomicops_internals_portable.h219
-rw-r--r--security/sandbox/chromium/base/atomicops_internals_x86_msvc.h179
-rw-r--r--security/sandbox/chromium/base/base_export.h29
-rw-r--r--security/sandbox/chromium/base/base_paths.h55
-rw-r--r--security/sandbox/chromium/base/base_paths_win.h53
-rw-r--r--security/sandbox/chromium/base/base_switches.cc149
-rw-r--r--security/sandbox/chromium/base/base_switches.h60
-rw-r--r--security/sandbox/chromium/base/bind.h470
-rw-r--r--security/sandbox/chromium/base/bind_helpers.h69
-rw-r--r--security/sandbox/chromium/base/bind_internal.h1050
-rw-r--r--security/sandbox/chromium/base/bit_cast.h77
-rw-r--r--security/sandbox/chromium/base/bits.h209
-rw-r--r--security/sandbox/chromium/base/callback.h149
-rw-r--r--security/sandbox/chromium/base/callback_forward.h28
-rw-r--r--security/sandbox/chromium/base/callback_internal.cc101
-rw-r--r--security/sandbox/chromium/base/callback_internal.h194
-rw-r--r--security/sandbox/chromium/base/compiler_specific.h298
-rw-r--r--security/sandbox/chromium/base/containers/adapters.h55
-rw-r--r--security/sandbox/chromium/base/containers/buffer_iterator.h145
-rw-r--r--security/sandbox/chromium/base/containers/checked_iterators.h205
-rw-r--r--security/sandbox/chromium/base/containers/circular_deque.h1112
-rw-r--r--security/sandbox/chromium/base/containers/span.h530
-rw-r--r--security/sandbox/chromium/base/containers/stack.h23
-rw-r--r--security/sandbox/chromium/base/containers/util.h21
-rw-r--r--security/sandbox/chromium/base/containers/vector_buffer.h188
-rw-r--r--security/sandbox/chromium/base/cpu.cc312
-rw-r--r--security/sandbox/chromium/base/cpu.h104
-rw-r--r--security/sandbox/chromium/base/debug/alias.cc16
-rw-r--r--security/sandbox/chromium/base/debug/alias.h44
-rw-r--r--security/sandbox/chromium/base/debug/crash_logging.h104
-rw-r--r--security/sandbox/chromium/base/debug/debugger.h50
-rw-r--r--security/sandbox/chromium/base/debug/leak_annotations.h46
-rw-r--r--security/sandbox/chromium/base/debug/profiler.cc180
-rw-r--r--security/sandbox/chromium/base/debug/profiler.h76
-rw-r--r--security/sandbox/chromium/base/environment.cc123
-rw-r--r--security/sandbox/chromium/base/environment.h61
-rw-r--r--security/sandbox/chromium/base/file_descriptor_posix.h61
-rw-r--r--security/sandbox/chromium/base/files/file_path.h484
-rw-r--r--security/sandbox/chromium/base/files/file_path_constants.cc25
-rw-r--r--security/sandbox/chromium/base/format_macros.h97
-rw-r--r--security/sandbox/chromium/base/guid.h46
-rw-r--r--security/sandbox/chromium/base/hash/hash.cc167
-rw-r--r--security/sandbox/chromium/base/hash/hash.h86
-rw-r--r--security/sandbox/chromium/base/immediate_crash.h168
-rw-r--r--security/sandbox/chromium/base/lazy_instance.h210
-rw-r--r--security/sandbox/chromium/base/lazy_instance_helpers.cc64
-rw-r--r--security/sandbox/chromium/base/lazy_instance_helpers.h101
-rw-r--r--security/sandbox/chromium/base/location.cc96
-rw-r--r--security/sandbox/chromium/base/location.h142
-rw-r--r--security/sandbox/chromium/base/logging.h1077
-rw-r--r--security/sandbox/chromium/base/macros.h48
-rw-r--r--security/sandbox/chromium/base/memory/aligned_memory.h60
-rw-r--r--security/sandbox/chromium/base/memory/free_deleter.h25
-rw-r--r--security/sandbox/chromium/base/memory/platform_shared_memory_region.cc62
-rw-r--r--security/sandbox/chromium/base/memory/platform_shared_memory_region.h301
-rw-r--r--security/sandbox/chromium/base/memory/platform_shared_memory_region_win.cc343
-rw-r--r--security/sandbox/chromium/base/memory/ptr_util.h23
-rw-r--r--security/sandbox/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h52
-rw-r--r--security/sandbox/chromium/base/memory/ref_counted.cc105
-rw-r--r--security/sandbox/chromium/base/memory/ref_counted.h463
-rw-r--r--security/sandbox/chromium/base/memory/scoped_refptr.h375
-rw-r--r--security/sandbox/chromium/base/memory/shared_memory_mapping.cc115
-rw-r--r--security/sandbox/chromium/base/memory/shared_memory_mapping.h252
-rw-r--r--security/sandbox/chromium/base/memory/singleton.h279
-rw-r--r--security/sandbox/chromium/base/memory/unsafe_shared_memory_region.cc80
-rw-r--r--security/sandbox/chromium/base/memory/unsafe_shared_memory_region.h127
-rw-r--r--security/sandbox/chromium/base/memory/weak_ptr.h395
-rw-r--r--security/sandbox/chromium/base/no_destructor.h98
-rw-r--r--security/sandbox/chromium/base/numerics/checked_math.h393
-rw-r--r--security/sandbox/chromium/base/numerics/checked_math_impl.h567
-rw-r--r--security/sandbox/chromium/base/numerics/clamped_math.h264
-rw-r--r--security/sandbox/chromium/base/numerics/clamped_math_impl.h341
-rw-r--r--security/sandbox/chromium/base/numerics/safe_conversions.h358
-rw-r--r--security/sandbox/chromium/base/numerics/safe_conversions_arm_impl.h51
-rw-r--r--security/sandbox/chromium/base/numerics/safe_conversions_impl.h851
-rw-r--r--security/sandbox/chromium/base/numerics/safe_math.h12
-rw-r--r--security/sandbox/chromium/base/numerics/safe_math_arm_impl.h122
-rw-r--r--security/sandbox/chromium/base/numerics/safe_math_clang_gcc_impl.h157
-rw-r--r--security/sandbox/chromium/base/numerics/safe_math_shared_impl.h240
-rw-r--r--security/sandbox/chromium/base/optional.h937
-rw-r--r--security/sandbox/chromium/base/os_compat_android.h21
-rw-r--r--security/sandbox/chromium/base/path_service.h94
-rw-r--r--security/sandbox/chromium/base/posix/can_lower_nice_to.cc60
-rw-r--r--security/sandbox/chromium/base/posix/can_lower_nice_to.h19
-rw-r--r--security/sandbox/chromium/base/posix/eintr_wrapper.h68
-rw-r--r--security/sandbox/chromium/base/posix/safe_strerror.cc128
-rw-r--r--security/sandbox/chromium/base/posix/safe_strerror.h44
-rw-r--r--security/sandbox/chromium/base/process/environment_internal.cc128
-rw-r--r--security/sandbox/chromium/base/process/environment_internal.h52
-rw-r--r--security/sandbox/chromium/base/process/kill.h162
-rw-r--r--security/sandbox/chromium/base/process/memory.h89
-rw-r--r--security/sandbox/chromium/base/process/process.h223
-rw-r--r--security/sandbox/chromium/base/process/process_handle.h142
-rw-r--r--security/sandbox/chromium/base/process/process_handle_win.cc52
-rw-r--r--security/sandbox/chromium/base/rand_util.h78
-rw-r--r--security/sandbox/chromium/base/rand_util_win.cc38
-rw-r--r--security/sandbox/chromium/base/scoped_clear_last_error.h58
-rw-r--r--security/sandbox/chromium/base/scoped_clear_last_error_win.cc22
-rw-r--r--security/sandbox/chromium/base/sequence_checker.h143
-rw-r--r--security/sandbox/chromium/base/sequence_checker_impl.h63
-rw-r--r--security/sandbox/chromium/base/sequence_token.h115
-rw-r--r--security/sandbox/chromium/base/sequenced_task_runner.h201
-rw-r--r--security/sandbox/chromium/base/sequenced_task_runner_helpers.h42
-rw-r--r--security/sandbox/chromium/base/single_thread_task_runner.h36
-rw-r--r--security/sandbox/chromium/base/stl_util.h681
-rw-r--r--security/sandbox/chromium/base/strings/char_traits.h92
-rw-r--r--security/sandbox/chromium/base/strings/nullable_string16.cc33
-rw-r--r--security/sandbox/chromium/base/strings/nullable_string16.h55
-rw-r--r--security/sandbox/chromium/base/strings/safe_sprintf.cc682
-rw-r--r--security/sandbox/chromium/base/strings/safe_sprintf.h246
-rw-r--r--security/sandbox/chromium/base/strings/safe_sprintf_unittest.cc765
-rw-r--r--security/sandbox/chromium/base/strings/string16.cc87
-rw-r--r--security/sandbox/chromium/base/strings/string16.h229
-rw-r--r--security/sandbox/chromium/base/strings/string_number_conversions.cc545
-rw-r--r--security/sandbox/chromium/base/strings/string_number_conversions.h157
-rw-r--r--security/sandbox/chromium/base/strings/string_piece.cc426
-rw-r--r--security/sandbox/chromium/base/strings/string_piece.h513
-rw-r--r--security/sandbox/chromium/base/strings/string_piece_forward.h24
-rw-r--r--security/sandbox/chromium/base/strings/string_split.cc254
-rw-r--r--security/sandbox/chromium/base/strings/string_split.h169
-rw-r--r--security/sandbox/chromium/base/strings/string_util.cc1057
-rw-r--r--security/sandbox/chromium/base/strings/string_util.h549
-rw-r--r--security/sandbox/chromium/base/strings/string_util_constants.cc54
-rw-r--r--security/sandbox/chromium/base/strings/string_util_posix.h37
-rw-r--r--security/sandbox/chromium/base/strings/string_util_win.h44
-rw-r--r--security/sandbox/chromium/base/strings/stringprintf.cc225
-rw-r--r--security/sandbox/chromium/base/strings/stringprintf.h74
-rw-r--r--security/sandbox/chromium/base/strings/utf_string_conversion_utils.cc155
-rw-r--r--security/sandbox/chromium/base/strings/utf_string_conversion_utils.h103
-rw-r--r--security/sandbox/chromium/base/strings/utf_string_conversions.cc342
-rw-r--r--security/sandbox/chromium/base/strings/utf_string_conversions.h54
-rw-r--r--security/sandbox/chromium/base/synchronization/atomic_flag.h50
-rw-r--r--security/sandbox/chromium/base/synchronization/condition_variable.h135
-rw-r--r--security/sandbox/chromium/base/synchronization/condition_variable_posix.cc149
-rw-r--r--security/sandbox/chromium/base/synchronization/lock.cc38
-rw-r--r--security/sandbox/chromium/base/synchronization/lock.h133
-rw-r--r--security/sandbox/chromium/base/synchronization/lock_impl.h175
-rw-r--r--security/sandbox/chromium/base/synchronization/lock_impl_posix.cc133
-rw-r--r--security/sandbox/chromium/base/synchronization/lock_impl_win.cc40
-rw-r--r--security/sandbox/chromium/base/synchronization/waitable_event.h291
-rw-r--r--security/sandbox/chromium/base/synchronization/waitable_event_posix.cc445
-rw-r--r--security/sandbox/chromium/base/task_runner.h136
-rw-r--r--security/sandbox/chromium/base/template_util.h188
-rw-r--r--security/sandbox/chromium/base/third_party/cityhash/COPYING19
-rw-r--r--security/sandbox/chromium/base/third_party/cityhash/city.cc532
-rw-r--r--security/sandbox/chromium/base/third_party/cityhash/city.h129
-rw-r--r--security/sandbox/chromium/base/third_party/dynamic_annotations/LICENSE28
-rw-r--r--security/sandbox/chromium/base/third_party/dynamic_annotations/dynamic_annotations.h595
-rw-r--r--security/sandbox/chromium/base/third_party/icu/LICENSE76
-rw-r--r--security/sandbox/chromium/base/third_party/icu/icu_utf.cc131
-rw-r--r--security/sandbox/chromium/base/third_party/icu/icu_utf.h442
-rw-r--r--security/sandbox/chromium/base/third_party/superfasthash/LICENSE27
-rw-r--r--security/sandbox/chromium/base/third_party/superfasthash/README.chromium29
-rw-r--r--security/sandbox/chromium/base/third_party/superfasthash/superfasthash.c84
-rw-r--r--security/sandbox/chromium/base/third_party/valgrind/LICENSE39
-rw-r--r--security/sandbox/chromium/base/third_party/valgrind/valgrind.h4792
-rw-r--r--security/sandbox/chromium/base/thread_annotations.h264
-rw-r--r--security/sandbox/chromium/base/threading/platform_thread.cc51
-rw-r--r--security/sandbox/chromium/base/threading/platform_thread.h259
-rw-r--r--security/sandbox/chromium/base/threading/platform_thread_internal_posix.cc39
-rw-r--r--security/sandbox/chromium/base/threading/platform_thread_internal_posix.h62
-rw-r--r--security/sandbox/chromium/base/threading/platform_thread_posix.cc361
-rw-r--r--security/sandbox/chromium/base/threading/platform_thread_win.cc463
-rw-r--r--security/sandbox/chromium/base/threading/platform_thread_win.h23
-rw-r--r--security/sandbox/chromium/base/threading/thread_checker_impl.h74
-rw-r--r--security/sandbox/chromium/base/threading/thread_collision_warner.cc64
-rw-r--r--security/sandbox/chromium/base/threading/thread_collision_warner.h252
-rw-r--r--security/sandbox/chromium/base/threading/thread_id_name_manager.cc147
-rw-r--r--security/sandbox/chromium/base/threading/thread_id_name_manager.h94
-rw-r--r--security/sandbox/chromium/base/threading/thread_local.h136
-rw-r--r--security/sandbox/chromium/base/threading/thread_local_internal.h80
-rw-r--r--security/sandbox/chromium/base/threading/thread_local_storage.cc461
-rw-r--r--security/sandbox/chromium/base/threading/thread_local_storage.h175
-rw-r--r--security/sandbox/chromium/base/threading/thread_local_storage_posix.cc30
-rw-r--r--security/sandbox/chromium/base/threading/thread_local_storage_win.cc107
-rw-r--r--security/sandbox/chromium/base/threading/thread_restrictions.cc258
-rw-r--r--security/sandbox/chromium/base/threading/thread_restrictions.h680
-rw-r--r--security/sandbox/chromium/base/time/time.cc433
-rw-r--r--security/sandbox/chromium/base/time/time.h1077
-rw-r--r--security/sandbox/chromium/base/time/time_exploded_posix.cc287
-rw-r--r--security/sandbox/chromium/base/time/time_now_posix.cc122
-rw-r--r--security/sandbox/chromium/base/time/time_override.h74
-rw-r--r--security/sandbox/chromium/base/time/time_win.cc810
-rw-r--r--security/sandbox/chromium/base/time/time_win_features.cc14
-rw-r--r--security/sandbox/chromium/base/time/time_win_features.h20
-rw-r--r--security/sandbox/chromium/base/token.cc28
-rw-r--r--security/sandbox/chromium/base/token.h72
-rw-r--r--security/sandbox/chromium/base/tuple.h112
-rw-r--r--security/sandbox/chromium/base/unguessable_token.cc39
-rw-r--r--security/sandbox/chromium/base/unguessable_token.h120
-rw-r--r--security/sandbox/chromium/base/version.cc194
-rw-r--r--security/sandbox/chromium/base/version.h77
-rw-r--r--security/sandbox/chromium/base/win/current_module.h17
-rw-r--r--security/sandbox/chromium/base/win/pe_image.cc652
-rw-r--r--security/sandbox/chromium/base/win/pe_image.h308
-rw-r--r--security/sandbox/chromium/base/win/scoped_handle.cc44
-rw-r--r--security/sandbox/chromium/base/win/scoped_handle.h184
-rw-r--r--security/sandbox/chromium/base/win/scoped_handle_verifier.cc238
-rw-r--r--security/sandbox/chromium/base/win/scoped_handle_verifier.h88
-rw-r--r--security/sandbox/chromium/base/win/scoped_process_information.cc107
-rw-r--r--security/sandbox/chromium/base/win/scoped_process_information.h75
-rw-r--r--security/sandbox/chromium/base/win/startup_information.cc59
-rw-r--r--security/sandbox/chromium/base/win/startup_information.h53
-rw-r--r--security/sandbox/chromium/base/win/static_constants.cc13
-rw-r--r--security/sandbox/chromium/base/win/static_constants.h21
-rw-r--r--security/sandbox/chromium/base/win/windows_types.h278
-rw-r--r--security/sandbox/chromium/base/win/windows_version.cc313
-rw-r--r--security/sandbox/chromium/base/win/windows_version.h187
-rw-r--r--security/sandbox/chromium/build/build_config.h215
-rw-r--r--security/sandbox/chromium/build/buildflag.h47
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc343
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h338
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_forward.h37
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_impl.h67
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.cc147
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.h119
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/cons.h137
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.cc159
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.h29
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/errorcode.h37
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h63
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.cc19
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.h37
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc481
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.h155
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h354
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.cc150
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.h103
-rw-r--r--security/sandbox/chromium/sandbox/linux/bpf_dsl/trap_registry.h73
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h56
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h124
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc155
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.cc93
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.h68
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc259
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h113
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc66
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h62
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.cc481
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.h166
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc249
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc394
-rw-r--r--security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.h86
-rw-r--r--security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.cc264
-rw-r--r--security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.h89
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h1197
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h1623
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_ucontext.h60
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/capability.h42
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/i386_linux_ucontext.h85
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/linux_filter.h140
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/linux_futex.h84
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/linux_seccomp.h110
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/linux_signal.h150
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/linux_syscalls.h39
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/linux_ucontext.h22
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h1731
-rw-r--r--security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h1418
-rw-r--r--security/sandbox/chromium/sandbox/sandbox_export.h26
-rw-r--r--security/sandbox/chromium/sandbox/win/src/acl.cc171
-rw-r--r--security/sandbox/chromium/sandbox/win/src/acl.h64
-rw-r--r--security/sandbox/chromium/sandbox/win/src/app_container_profile.h74
-rw-r--r--security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc337
-rw-r--r--security/sandbox/chromium/sandbox/win/src/app_container_profile_base.h94
-rw-r--r--security/sandbox/chromium/sandbox/win/src/app_container_test.cc342
-rw-r--r--security/sandbox/chromium/sandbox/win/src/broker_services.cc748
-rw-r--r--security/sandbox/chromium/sandbox/win/src/broker_services.h105
-rw-r--r--security/sandbox/chromium/sandbox/win/src/crosscall_client.h509
-rw-r--r--security/sandbox/chromium/sandbox/win/src/crosscall_params.h315
-rw-r--r--security/sandbox/chromium/sandbox/win/src/crosscall_server.cc345
-rw-r--r--security/sandbox/chromium/sandbox/win/src/crosscall_server.h261
-rw-r--r--security/sandbox/chromium/sandbox/win/src/eat_resolver.cc88
-rw-r--r--security/sandbox/chromium/sandbox/win/src/eat_resolver.h49
-rw-r--r--security/sandbox/chromium/sandbox/win/src/file_policy_test.cc705
-rw-r--r--security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc302
-rw-r--r--security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.h76
-rw-r--r--security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc412
-rw-r--r--security/sandbox/chromium/sandbox/win/src/filesystem_interception.h67
-rw-r--r--security/sandbox/chromium/sandbox/win/src/filesystem_policy.cc443
-rw-r--r--security/sandbox/chromium/sandbox/win/src/filesystem_policy.h112
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_closer.cc185
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_closer.h76
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_closer_agent.cc239
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_closer_agent.h46
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_closer_test.cc297
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc93
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_dispatcher.h41
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_inheritance_test.cc49
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_interception.cc48
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_interception.h24
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_policy.cc93
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_policy.h39
-rw-r--r--security/sandbox/chromium/sandbox/win/src/handle_policy_test.cc114
-rw-r--r--security/sandbox/chromium/sandbox/win/src/heap_helper.cc124
-rw-r--r--security/sandbox/chromium/sandbox/win/src/heap_helper.h26
-rw-r--r--security/sandbox/chromium/sandbox/win/src/integrity_level_test.cc118
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interception.cc512
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interception.h290
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interception_agent.cc234
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interception_agent.h87
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interception_internal.h77
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interception_unittest.cc263
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interceptors.h74
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interceptors_64.cc539
-rw-r--r--security/sandbox/chromium/sandbox/win/src/interceptors_64.h334
-rw-r--r--security/sandbox/chromium/sandbox/win/src/internal_types.h68
-rw-r--r--security/sandbox/chromium/sandbox/win/src/ipc_args.cc96
-rw-r--r--security/sandbox/chromium/sandbox/win/src/ipc_args.h24
-rw-r--r--security/sandbox/chromium/sandbox/win/src/ipc_ping_test.cc58
-rw-r--r--security/sandbox/chromium/sandbox/win/src/ipc_tags.h59
-rw-r--r--security/sandbox/chromium/sandbox/win/src/ipc_unittest.cc632
-rw-r--r--security/sandbox/chromium/sandbox/win/src/job.cc117
-rw-r--r--security/sandbox/chromium/sandbox/win/src/job.h66
-rw-r--r--security/sandbox/chromium/sandbox/win/src/job_unittest.cc197
-rw-r--r--security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.cc95
-rw-r--r--security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.h46
-rw-r--r--security/sandbox/chromium/sandbox/win/src/named_pipe_interception.cc80
-rw-r--r--security/sandbox/chromium/sandbox/win/src/named_pipe_interception.h41
-rw-r--r--security/sandbox/chromium/sandbox/win/src/named_pipe_policy.cc89
-rw-r--r--security/sandbox/chromium/sandbox/win/src/named_pipe_policy.h43
-rw-r--r--security/sandbox/chromium/sandbox/win/src/named_pipe_policy_test.cc121
-rw-r--r--security/sandbox/chromium/sandbox/win/src/nt_internals.h986
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_broker.cc125
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_broker.h27
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.cc450
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.h379
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_engine_params.h190
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_engine_processor.cc103
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_engine_processor.h143
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_engine_unittest.cc103
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_low_level.cc355
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_low_level.h189
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_low_level_unittest.cc684
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_opcodes_unittest.cc364
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_params.h70
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_target.cc142
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_target.h52
-rw-r--r--security/sandbox/chromium/sandbox/win/src/policy_target_test.cc486
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations.cc622
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations.h56
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.cc592
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.h89
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.cc523
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.h151
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.cc410
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.h91
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_policy_test.cc548
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.cc275
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.h69
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_thread_interception.cc520
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_thread_interception.h101
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_thread_policy.cc269
-rw-r--r--security/sandbox/chromium/sandbox/win/src/process_thread_policy.h91
-rw-r--r--security/sandbox/chromium/sandbox/win/src/registry_dispatcher.cc167
-rw-r--r--security/sandbox/chromium/sandbox/win/src/registry_dispatcher.h51
-rw-r--r--security/sandbox/chromium/sandbox/win/src/registry_interception.cc261
-rw-r--r--security/sandbox/chromium/sandbox/win/src/registry_interception.h38
-rw-r--r--security/sandbox/chromium/sandbox/win/src/registry_policy.cc230
-rw-r--r--security/sandbox/chromium/sandbox/win/src/registry_policy.h56
-rw-r--r--security/sandbox/chromium/sandbox/win/src/registry_policy_test.cc322
-rw-r--r--security/sandbox/chromium/sandbox/win/src/resolver.cc63
-rw-r--r--security/sandbox/chromium/sandbox/win/src/resolver.h107
-rw-r--r--security/sandbox/chromium/sandbox/win/src/resolver_32.cc95
-rw-r--r--security/sandbox/chromium/sandbox/win/src/resolver_64.cc95
-rw-r--r--security/sandbox/chromium/sandbox/win/src/restricted_token.cc432
-rw-r--r--security/sandbox/chromium/sandbox/win/src/restricted_token.h207
-rw-r--r--security/sandbox/chromium/sandbox/win/src/restricted_token_unittest.cc829
-rw-r--r--security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc482
-rw-r--r--security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h105
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox.cc47
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox.h228
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox.vcproj648
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_factory.h52
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_globals.cc18
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_nt_types.h47
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.cc755
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.h220
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_policy.h296
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc832
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h198
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_rand.cc22
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_rand.h15
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_types.h199
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_utils.cc32
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sandbox_utils.h24
-rw-r--r--security/sandbox/chromium/sandbox/win/src/security_capabilities.cc33
-rw-r--r--security/sandbox/chromium/sandbox/win/src/security_capabilities.h34
-rw-r--r--security/sandbox/chromium/sandbox/win/src/security_level.h300
-rw-r--r--security/sandbox/chromium/sandbox/win/src/service_resolver.cc47
-rw-r--r--security/sandbox/chromium/sandbox/win/src/service_resolver.h158
-rw-r--r--security/sandbox/chromium/sandbox/win/src/service_resolver_32.cc476
-rw-r--r--security/sandbox/chromium/sandbox/win/src/service_resolver_64.cc290
-rw-r--r--security/sandbox/chromium/sandbox/win/src/service_resolver_unittest.cc278
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.cc193
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.h140
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.cc346
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.h143
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sid.cc163
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sid.h74
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sid_unittest.cc182
-rw-r--r--security/sandbox/chromium/sandbox/win/src/signed_dispatcher.cc68
-rw-r--r--security/sandbox/chromium/sandbox/win/src/signed_dispatcher.h37
-rw-r--r--security/sandbox/chromium/sandbox/win/src/signed_interception.cc97
-rw-r--r--security/sandbox/chromium/sandbox/win/src/signed_interception.h30
-rw-r--r--security/sandbox/chromium/sandbox/win/src/signed_policy.cc102
-rw-r--r--security/sandbox/chromium/sandbox/win/src/signed_policy.h39
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_dispatcher.cc82
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_dispatcher.h44
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_interception.cc177
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_interception.h46
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_policy.cc243
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_policy.h49
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_policy_test.cc145
-rw-r--r--security/sandbox/chromium/sandbox/win/src/sync_policy_test.h18
-rw-r--r--security/sandbox/chromium/sandbox/win/src/target_interceptions.cc136
-rw-r--r--security/sandbox/chromium/sandbox/win/src/target_interceptions.h43
-rw-r--r--security/sandbox/chromium/sandbox/win/src/target_process.cc393
-rw-r--r--security/sandbox/chromium/sandbox/win/src/target_process.h143
-rw-r--r--security/sandbox/chromium/sandbox/win/src/target_services.cc264
-rw-r--r--security/sandbox/chromium/sandbox/win/src/target_services.h73
-rw-r--r--security/sandbox/chromium/sandbox/win/src/threadpool_unittest.cc97
-rw-r--r--security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc178
-rw-r--r--security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.h54
-rw-r--r--security/sandbox/chromium/sandbox/win/src/unload_dll_test.cc100
-rw-r--r--security/sandbox/chromium/sandbox/win/src/win2k_threadpool.cc67
-rw-r--r--security/sandbox/chromium/sandbox/win/src/win2k_threadpool.h61
-rw-r--r--security/sandbox/chromium/sandbox/win/src/win_utils.cc619
-rw-r--r--security/sandbox/chromium/sandbox/win/src/win_utils.h156
-rw-r--r--security/sandbox/chromium/sandbox/win/src/win_utils_unittest.cc258
-rw-r--r--security/sandbox/chromium/sandbox/win/src/window.cc147
-rw-r--r--security/sandbox/chromium/sandbox/win/src/window.h37
437 files changed, 93669 insertions, 0 deletions
diff --git a/security/sandbox/chromium/LICENSE b/security/sandbox/chromium/LICENSE
new file mode 100644
index 0000000000..a32e00ce6b
--- /dev/null
+++ b/security/sandbox/chromium/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/security/sandbox/chromium/base/at_exit.cc b/security/sandbox/chromium/base/at_exit.cc
new file mode 100644
index 0000000000..eb7d26cdc7
--- /dev/null
+++ b/security/sandbox/chromium/base/at_exit.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+
+#include <stddef.h>
+#include <ostream>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+
+namespace base {
+
+// Keep a stack of registered AtExitManagers. We always operate on the most
+// recent, and we should never have more than one outside of testing (for a
+// statically linked version of this library). Testing may use the shadow
+// version of the constructor, and if we are building a dynamic library we may
+// end up with multiple AtExitManagers on the same process. We don't protect
+// this for thread-safe access, since it will only be modified in testing.
+static AtExitManager* g_top_manager = nullptr;
+
+static bool g_disable_managers = false;
+
+AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
+// If multiple modules instantiate AtExitManagers they'll end up living in this
+// module... they have to coexist.
+#if !defined(COMPONENT_BUILD)
+ DCHECK(!g_top_manager);
+#endif
+ g_top_manager = this;
+}
+
+AtExitManager::~AtExitManager() {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
+ return;
+ }
+ DCHECK_EQ(this, g_top_manager);
+
+ if (!g_disable_managers)
+ ProcessCallbacksNow();
+ g_top_manager = next_manager_;
+}
+
+// static
+void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
+ DCHECK(func);
+ RegisterTask(base::BindOnce(func, param));
+}
+
+// static
+void AtExitManager::RegisterTask(base::OnceClosure task) {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
+ return;
+ }
+
+ AutoLock lock(g_top_manager->lock_);
+#if DCHECK_IS_ON()
+ DCHECK(!g_top_manager->processing_callbacks_);
+#endif
+ g_top_manager->stack_.push(std::move(task));
+}
+
+// static
+void AtExitManager::ProcessCallbacksNow() {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
+ return;
+ }
+
+ // Callbacks may try to add new callbacks, so run them without holding
+ // |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but
+ // handle it gracefully in release builds so we don't deadlock.
+ base::stack<base::OnceClosure> tasks;
+ {
+ AutoLock lock(g_top_manager->lock_);
+ tasks.swap(g_top_manager->stack_);
+#if DCHECK_IS_ON()
+ g_top_manager->processing_callbacks_ = true;
+#endif
+ }
+
+ // Relax the cross-thread access restriction to non-thread-safe RefCount.
+ // It's safe since all other threads should be terminated at this point.
+ ScopedAllowCrossThreadRefCountAccess allow_cross_thread_ref_count_access;
+
+ while (!tasks.empty()) {
+ std::move(tasks.top()).Run();
+ tasks.pop();
+ }
+
+#if DCHECK_IS_ON()
+ AutoLock lock(g_top_manager->lock_);
+ // Expect that all callbacks have been run.
+ DCHECK(g_top_manager->stack_.empty());
+ g_top_manager->processing_callbacks_ = false;
+#endif
+}
+
+void AtExitManager::DisableAllAtExitManagers() {
+ AutoLock lock(g_top_manager->lock_);
+ g_disable_managers = true;
+}
+
+AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
+ DCHECK(shadow || !g_top_manager);
+ g_top_manager = this;
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/at_exit.h b/security/sandbox/chromium/base/at_exit.h
new file mode 100644
index 0000000000..fa652ac0c9
--- /dev/null
+++ b/security/sandbox/chromium/base/at_exit.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_AT_EXIT_H_
+#define BASE_AT_EXIT_H_
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/containers/stack.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+
+namespace base {
+
+// This class provides a facility similar to the CRT atexit(), except that
+// we control when the callbacks are executed. Under Windows for a DLL they
+// happen at a really bad time and under the loader lock. This facility is
+// mostly used by base::Singleton.
+//
+// The usage is simple. Early in the main() or WinMain() scope create an
+// AtExitManager object on the stack:
+// int main(...) {
+// base::AtExitManager exit_manager;
+//
+// }
+// When the exit_manager object goes out of scope, all the registered
+// callbacks and singleton destructors will be called.
+
+class BASE_EXPORT AtExitManager {
+ public:
+ typedef void (*AtExitCallbackType)(void*);
+
+ AtExitManager();
+
+ // The dtor calls all the registered callbacks. Do not try to register more
+ // callbacks after this point.
+ ~AtExitManager();
+
+ // Registers the specified function to be called at exit. The prototype of
+ // the callback function is void func(void*).
+ static void RegisterCallback(AtExitCallbackType func, void* param);
+
+ // Registers the specified task to be called at exit.
+ static void RegisterTask(base::OnceClosure task);
+
+ // Calls the functions registered with RegisterCallback in LIFO order. It
+ // is possible to register new callbacks after calling this function.
+ static void ProcessCallbacksNow();
+
+ // Disable all registered at-exit callbacks. This is used only in a single-
+ // process mode.
+ static void DisableAllAtExitManagers();
+
+ protected:
+ // This constructor will allow this instance of AtExitManager to be created
+ // even if one already exists. This should only be used for testing!
+ // AtExitManagers are kept on a global stack, and it will be removed during
+ // destruction. This allows you to shadow another AtExitManager.
+ explicit AtExitManager(bool shadow);
+
+ private:
+ base::Lock lock_;
+
+ base::stack<base::OnceClosure> stack_ GUARDED_BY(lock_);
+
+#if DCHECK_IS_ON()
+ bool processing_callbacks_ GUARDED_BY(lock_) = false;
+#endif
+
+ // Stack of managers to allow shadowing.
+ AtExitManager* const next_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(AtExitManager);
+};
+
+#if defined(UNIT_TEST)
+class ShadowingAtExitManager : public AtExitManager {
+ public:
+ ShadowingAtExitManager() : AtExitManager(true) {}
+};
+#endif // defined(UNIT_TEST)
+
+} // namespace base
+
+#endif // BASE_AT_EXIT_H_
diff --git a/security/sandbox/chromium/base/atomic_ref_count.h b/security/sandbox/chromium/base/atomic_ref_count.h
new file mode 100644
index 0000000000..5e48c82380
--- /dev/null
+++ b/security/sandbox/chromium/base/atomic_ref_count.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a low level implementation of atomic semantics for reference
+// counting. Please use base/memory/ref_counted.h directly instead.
+
+#ifndef BASE_ATOMIC_REF_COUNT_H_
+#define BASE_ATOMIC_REF_COUNT_H_
+
+#include <atomic>
+
+namespace base {
+
+class AtomicRefCount {
+ public:
+ constexpr AtomicRefCount() : ref_count_(0) {}
+ explicit constexpr AtomicRefCount(int initial_value)
+ : ref_count_(initial_value) {}
+
+ // Increment a reference count.
+ // Returns the previous value of the count.
+ int Increment() { return Increment(1); }
+
+ // Increment a reference count by "increment", which must exceed 0.
+ // Returns the previous value of the count.
+ int Increment(int increment) {
+ return ref_count_.fetch_add(increment, std::memory_order_relaxed);
+ }
+
+ // Decrement a reference count, and return whether the result is non-zero.
+ // Insert barriers to ensure that state written before the reference count
+ // became zero will be visible to a thread that has just made the count zero.
+ bool Decrement() {
+ // TODO(jbroman): Technically this doesn't need to be an acquire operation
+ // unless the result is 1 (i.e., the ref count did indeed reach zero).
+ // However, there are toolchain issues that make that not work as well at
+ // present (notably TSAN doesn't like it).
+ return ref_count_.fetch_sub(1, std::memory_order_acq_rel) != 1;
+ }
+
+ // Return whether the reference count is one. If the reference count is used
+ // in the conventional way, a refrerence count of 1 implies that the current
+ // thread owns the reference and no other thread shares it. This call
+ // performs the test for a reference count of one, and performs the memory
+ // barrier needed for the owning thread to act on the object, knowing that it
+ // has exclusive access to the object.
+ bool IsOne() const { return ref_count_.load(std::memory_order_acquire) == 1; }
+
+ // Return whether the reference count is zero. With conventional object
+ // referencing counting, the object will be destroyed, so the reference count
+ // should never be zero. Hence this is generally used for a debug check.
+ bool IsZero() const {
+ return ref_count_.load(std::memory_order_acquire) == 0;
+ }
+
+ // Returns the current reference count (with no barriers). This is subtle, and
+ // should be used only for debugging.
+ int SubtleRefCountForDebug() const {
+ return ref_count_.load(std::memory_order_relaxed);
+ }
+
+ private:
+ std::atomic_int ref_count_;
+};
+
+} // namespace base
+
+#endif // BASE_ATOMIC_REF_COUNT_H_
diff --git a/security/sandbox/chromium/base/atomic_sequence_num.h b/security/sandbox/chromium/base/atomic_sequence_num.h
new file mode 100644
index 0000000000..717e37a60b
--- /dev/null
+++ b/security/sandbox/chromium/base/atomic_sequence_num.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_
+#define BASE_ATOMIC_SEQUENCE_NUM_H_
+
+#include <atomic>
+
+#include "base/macros.h"
+
+namespace base {
+
+// AtomicSequenceNumber is a thread safe increasing sequence number generator.
+// Its constructor doesn't emit a static initializer, so it's safe to use as a
+// global variable or static member.
+class AtomicSequenceNumber {
+ public:
+ constexpr AtomicSequenceNumber() = default;
+
+ // Returns an increasing sequence number starts from 0 for each call.
+ // This function can be called from any thread without data race.
+ inline int GetNext() { return seq_.fetch_add(1, std::memory_order_relaxed); }
+
+ private:
+ std::atomic_int seq_{0};
+
+ DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
+};
+
+} // namespace base
+
+#endif // BASE_ATOMIC_SEQUENCE_NUM_H_
diff --git a/security/sandbox/chromium/base/atomicops.h b/security/sandbox/chromium/base/atomicops.h
new file mode 100644
index 0000000000..429e2457fc
--- /dev/null
+++ b/security/sandbox/chromium/base/atomicops.h
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// For atomic operations on reference counts, see atomic_refcount.h.
+// For atomic operations on sequence numbers, see atomic_sequence_num.h.
+
+// The routines exported by this module are subtle. If you use them, even if
+// you get the code right, it will depend on careful reasoning about atomicity
+// and memory ordering; it will be less readable, and harder to maintain. If
+// you plan to use these routines, you should have a good reason, such as solid
+// evidence that performance would otherwise suffer, or there being no
+// alternative. You should assume only properties explicitly guaranteed by the
+// specifications in this file. You are almost certainly _not_ writing code
+// just for the x86; if you assume x86 semantics, x86 hardware bugs and
+// implementations on other archtectures will cause your code to break. If you
+// do not know what you are doing, avoid these routines, and use a Mutex.
+//
+// It is incorrect to make direct assignments to/from an atomic variable.
+// You should use one of the Load or Store routines. The NoBarrier
+// versions are provided when no barriers are needed:
+// NoBarrier_Store()
+// NoBarrier_Load()
+// Although there are currently no compiler enforcement, you are encouraged
+// to use these.
+//
+
+#ifndef BASE_ATOMICOPS_H_
+#define BASE_ATOMICOPS_H_
+
+#include <stdint.h>
+
+// Small C++ header which defines implementation specific macros used to
+// identify the STL implementation.
+// - libc++: captures __config for _LIBCPP_VERSION
+// - libstdc++: captures bits/c++config.h for __GLIBCXX__
+#include <cstddef>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace subtle {
+
+typedef int32_t Atomic32;
+#ifdef ARCH_CPU_64_BITS
+// We need to be able to go between Atomic64 and AtomicWord implicitly. This
+// means Atomic64 and AtomicWord should be the same type on 64-bit.
+#if defined(__ILP32__) || defined(OS_NACL)
+// NaCl's intptr_t is not actually 64-bits on 64-bit!
+// http://code.google.com/p/nativeclient/issues/detail?id=1162
+typedef int64_t Atomic64;
+#else
+typedef intptr_t Atomic64;
+#endif
+#endif
+
+// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
+// Atomic64 routines below, depending on your architecture.
+typedef intptr_t AtomicWord;
+
+// Atomically execute:
+// result = *ptr;
+// if (*ptr == old_value)
+// *ptr = new_value;
+// return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
+
+Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment);
+
+// These following lower-level operations are typically useful only to people
+// implementing higher-level synchronization operations like spinlocks,
+// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or
+// a store with appropriate memory-ordering instructions. "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics.
+Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
+void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
+void Release_Store(volatile Atomic32* ptr, Atomic32 value);
+
+Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
+Atomic32 Acquire_Load(volatile const Atomic32* ptr);
+Atomic32 Release_Load(volatile const Atomic32* ptr);
+
+// 64-bit atomic operations (only available on 64-bit processors).
+#ifdef ARCH_CPU_64_BITS
+Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
+Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+
+Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
+void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
+void Release_Store(volatile Atomic64* ptr, Atomic64 value);
+Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
+Atomic64 Acquire_Load(volatile const Atomic64* ptr);
+Atomic64 Release_Load(volatile const Atomic64* ptr);
+#endif // ARCH_CPU_64_BITS
+
+} // namespace subtle
+} // namespace base
+
+#if defined(OS_WIN) && defined(ARCH_CPU_X86_FAMILY)
+// TODO(jfb): Try to use base/atomicops_internals_portable.h everywhere.
+// https://crbug.com/559247.
+# include "base/atomicops_internals_x86_msvc.h"
+#else
+# include "base/atomicops_internals_portable.h"
+#endif
+
+// On some platforms we need additional declarations to make
+// AtomicWord compatible with our other Atomic* types.
+#if defined(OS_MACOSX) || defined(OS_OPENBSD)
+#include "base/atomicops_internals_atomicword_compat.h"
+#endif
+
+#endif // BASE_ATOMICOPS_H_
diff --git a/security/sandbox/chromium/base/atomicops_internals_portable.h b/security/sandbox/chromium/base/atomicops_internals_portable.h
new file mode 100644
index 0000000000..3b75be32c4
--- /dev/null
+++ b/security/sandbox/chromium/base/atomicops_internals_portable.h
@@ -0,0 +1,219 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use atomicops.h instead.
+//
+// This implementation uses C++11 atomics' member functions. The code base is
+// currently written assuming atomicity revolves around accesses instead of
+// C++11's memory locations. The burden is on the programmer to ensure that all
+// memory locations accessed atomically are never accessed non-atomically (tsan
+// should help with this).
+//
+// TODO(jfb) Modify the atomicops.h API and user code to declare atomic
+// locations as truly atomic. See the static_assert below.
+//
+// Of note in this implementation:
+// * All NoBarrier variants are implemented as relaxed.
+// * All Barrier variants are implemented as sequentially-consistent.
+// * Compare exchange's failure ordering is always the same as the success one
+// (except for release, which fails as relaxed): using a weaker ordering is
+// only valid under certain uses of compare exchange.
+// * Acquire store doesn't exist in the C11 memory model, it is instead
+// implemented as a relaxed store followed by a sequentially consistent
+// fence.
+// * Release load doesn't exist in the C11 memory model, it is instead
+// implemented as sequentially consistent fence followed by a relaxed load.
+// * Atomic increment is expected to return the post-incremented value, whereas
+// C11 fetch add returns the previous value. The implementation therefore
+// needs to increment twice (which the compiler should be able to detect and
+// optimize).
+
+#ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+#define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+
+#include <atomic>
+
+#include "build/build_config.h"
+
+namespace base {
+namespace subtle {
+
+// This implementation is transitional and maintains the original API for
+// atomicops.h. This requires casting memory locations to the atomic types, and
+// assumes that the API and the C++11 implementation are layout-compatible,
+// which isn't true for all implementations or hardware platforms. The static
+// assertion should detect this issue, were it to fire then this header
+// shouldn't be used.
+//
+// TODO(jfb) If this header manages to stay committed then the API should be
+// modified, and all call sites updated.
+typedef volatile std::atomic<Atomic32>* AtomicLocation32;
+static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
+ "incompatible 32-bit atomic layout");
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ((AtomicLocation32)ptr)
+ ->compare_exchange_strong(old_value,
+ new_value,
+ std::memory_order_relaxed,
+ std::memory_order_relaxed);
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ return ((AtomicLocation32)ptr)
+ ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return increment +
+ ((AtomicLocation32)ptr)
+ ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ((AtomicLocation32)ptr)
+ ->compare_exchange_strong(old_value,
+ new_value,
+ std::memory_order_acquire,
+ std::memory_order_acquire);
+ return old_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ ((AtomicLocation32)ptr)
+ ->compare_exchange_strong(old_value,
+ new_value,
+ std::memory_order_release,
+ std::memory_order_relaxed);
+ return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
+}
+
+#if defined(ARCH_CPU_64_BITS)
+
+typedef volatile std::atomic<Atomic64>* AtomicLocation64;
+static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
+ "incompatible 64-bit atomic layout");
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ ((AtomicLocation64)ptr)
+ ->compare_exchange_strong(old_value,
+ new_value,
+ std::memory_order_relaxed,
+ std::memory_order_relaxed);
+ return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ return ((AtomicLocation64)ptr)
+ ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return increment +
+ ((AtomicLocation64)ptr)
+ ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ ((AtomicLocation64)ptr)
+ ->compare_exchange_strong(old_value,
+ new_value,
+ std::memory_order_acquire,
+ std::memory_order_acquire);
+ return old_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ ((AtomicLocation64)ptr)
+ ->compare_exchange_strong(old_value,
+ new_value,
+ std::memory_order_release,
+ std::memory_order_relaxed);
+ return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+#endif // defined(ARCH_CPU_64_BITS)
+} // namespace subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
diff --git a/security/sandbox/chromium/base/atomicops_internals_x86_msvc.h b/security/sandbox/chromium/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 0000000000..d9846f64b8
--- /dev/null
+++ b/security/sandbox/chromium/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,179 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+
+#include "base/win/windows_types.h"
+
+#include <intrin.h>
+
+#include <atomic>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ LONG result = _InterlockedCompareExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value),
+ static_cast<LONG>(old_value));
+ return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ LONG result = _InterlockedExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value));
+ return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return _InterlockedExchangeAdd(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(increment)) + increment;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+ // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ PVOID result = _InterlockedCompareExchangePointer(
+ reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ PVOID result =
+ _InterlockedExchangePointer(reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return _InterlockedExchangeAdd64(reinterpret_cast<volatile LONGLONG*>(ptr),
+ static_cast<LONGLONG>(increment)) +
+ increment;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+ // When new chips come out, check:
+ // IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ // System Programming Guide, Chatper 7: Multiple-processor management,
+ // Section 7.2, Memory Ordering.
+ // Last seen at:
+ // http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr;
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+
+#endif // defined(_WIN64)
+
+} // namespace subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/security/sandbox/chromium/base/base_export.h b/security/sandbox/chromium/base/base_export.h
new file mode 100644
index 0000000000..cf7ebd7816
--- /dev/null
+++ b/security/sandbox/chromium/base/base_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_EXPORT_H_
+#define BASE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __declspec(dllexport)
+#else
+#define BASE_EXPORT __declspec(dllimport)
+#endif // defined(BASE_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_EXPORT
+#endif // defined(BASE_IMPLEMENTATION)
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define BASE_EXPORT
+#endif
+
+#endif // BASE_BASE_EXPORT_H_
diff --git a/security/sandbox/chromium/base/base_paths.h b/security/sandbox/chromium/base/base_paths.h
new file mode 100644
index 0000000000..2a163f48d4
--- /dev/null
+++ b/security/sandbox/chromium/base/base_paths.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_H_
+#define BASE_BASE_PATHS_H_
+
+// This file declares path keys for the base module. These can be used with
+// the PathService to access various special directories and files.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#elif defined(OS_ANDROID)
+#include "base/base_paths_android.h"
+#endif
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include "base/base_paths_posix.h"
+#endif
+
+namespace base {
+
+enum BasePathKey {
+ PATH_START = 0,
+
+ DIR_CURRENT, // Current directory.
+ DIR_EXE, // Directory containing FILE_EXE.
+ DIR_MODULE, // Directory containing FILE_MODULE.
+ DIR_ASSETS, // Directory that contains application assets.
+ DIR_TEMP, // Temporary directory.
+ DIR_HOME, // User's root home directory. On Windows this will look
+ // like "C:\Users\<user>" which isn't necessarily a great
+ // place to put files.
+ FILE_EXE, // Path and filename of the current executable.
+ FILE_MODULE, // Path and filename of the module containing the code for
+ // the PathService (which could differ from FILE_EXE if the
+ // PathService were compiled into a shared object, for
+ // example).
+ DIR_SOURCE_ROOT, // Returns the root of the source tree. This key is useful
+ // for tests that need to locate various resources. It
+ // should not be used outside of test code.
+ DIR_USER_DESKTOP, // The current user's Desktop.
+
+ DIR_TEST_DATA, // Used only for testing.
+
+ PATH_END
+};
+
+} // namespace base
+
+#endif // BASE_BASE_PATHS_H_
diff --git a/security/sandbox/chromium/base/base_paths_win.h b/security/sandbox/chromium/base/base_paths_win.h
new file mode 100644
index 0000000000..2db16a6271
--- /dev/null
+++ b/security/sandbox/chromium/base/base_paths_win.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_PATHS_WIN_H_
+#define BASE_BASE_PATHS_WIN_H_
+
+// This file declares windows-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+ PATH_WIN_START = 100,
+
+ DIR_WINDOWS, // Windows directory, usually "c:\windows"
+ DIR_SYSTEM, // Usually c:\windows\system32"
+ // 32-bit 32-bit on 64-bit 64-bit on 64-bit
+ // DIR_PROGRAM_FILES 1 2 1
+ // DIR_PROGRAM_FILESX86 1 2 2
+ // DIR_PROGRAM_FILES6432 1 1 1
+ // 1 - C:\Program Files 2 - C:\Program Files (x86)
+ DIR_PROGRAM_FILES, // See table above.
+ DIR_PROGRAM_FILESX86, // See table above.
+ DIR_PROGRAM_FILES6432, // See table above.
+
+ DIR_IE_INTERNET_CACHE, // Temporary Internet Files directory.
+ DIR_COMMON_START_MENU, // Usually "C:\ProgramData\Microsoft\Windows\
+ // Start Menu\Programs"
+ DIR_START_MENU, // Usually "C:\Users\<user>\AppData\Roaming\
+ // Microsoft\Windows\Start Menu\Programs"
+ DIR_APP_DATA, // Application Data directory under the user
+ // profile.
+ DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory
+ // under the user profile.
+ DIR_COMMON_APP_DATA, // Usually "C:\ProgramData".
+ DIR_APP_SHORTCUTS, // Where tiles on the start screen are stored,
+ // only for Windows 8. Maps to "Local\AppData\
+ // Microsoft\Windows\Application Shortcuts\".
+ DIR_COMMON_DESKTOP, // Directory for the common desktop (visible
+ // on all user's Desktop).
+ DIR_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts.
+ DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar.
+ DIR_IMPLICIT_APP_SHORTCUTS, // The implicit user pinned shortcut directory.
+ DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
+
+ PATH_WIN_END
+};
+
+} // namespace base
+
+#endif // BASE_BASE_PATHS_WIN_H_
diff --git a/security/sandbox/chromium/base/base_switches.cc b/security/sandbox/chromium/base/base_switches.cc
new file mode 100644
index 0000000000..6a47487961
--- /dev/null
+++ b/security/sandbox/chromium/base/base_switches.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/base_switches.h"
+#include "build/build_config.h"
+
+namespace switches {
+
+// Delays execution of TaskPriority::BEST_EFFORT tasks until shutdown.
+const char kDisableBestEffortTasks[] = "disable-best-effort-tasks";
+
+// Disables the crash reporting.
+const char kDisableBreakpad[] = "disable-breakpad";
+
+// Comma-separated list of feature names to disable. See also kEnableFeatures.
+const char kDisableFeatures[] = "disable-features";
+
+// Force disabling of low-end device mode when set.
+const char kDisableLowEndDeviceMode[] = "disable-low-end-device-mode";
+
+// Indicates that crash reporting should be enabled. On platforms where helper
+// processes cannot access to files needed to make this decision, this flag is
+// generated internally.
+const char kEnableCrashReporter[] = "enable-crash-reporter";
+
+// Comma-separated list of feature names to enable. See also kDisableFeatures.
+const char kEnableFeatures[] = "enable-features";
+
+// Force low-end device mode when set.
+const char kEnableLowEndDeviceMode[] = "enable-low-end-device-mode";
+
+// This option can be used to force field trials when testing changes locally.
+// The argument is a list of name and value pairs, separated by slashes. If a
+// trial name is prefixed with an asterisk, that trial will start activated.
+// For example, the following argument defines two trials, with the second one
+// activated: "GoogleNow/Enable/*MaterialDesignNTP/Default/" This option can
+// also be used by the browser process to send the list of trials to a
+// non-browser process, using the same format. See
+// FieldTrialList::CreateTrialsFromString() in field_trial.h for details.
+const char kForceFieldTrials[] = "force-fieldtrials";
+
+// Generates full memory crash dump.
+const char kFullMemoryCrashReport[] = "full-memory-crash-report";
+
+// Logs information about all tasks posted with TaskPriority::BEST_EFFORT. Use
+// this to diagnose issues that are thought to be caused by
+// TaskPriority::BEST_EFFORT execution fences. Note: Tasks posted to a
+// non-BEST_EFFORT UpdateableSequencedTaskRunner whose priority is later lowered
+// to BEST_EFFORT are not logged.
+const char kLogBestEffortTasks[] = "log-best-effort-tasks";
+
+// Suppresses all error dialogs when present.
+const char kNoErrorDialogs[] = "noerrdialogs";
+
+// Starts the sampling based profiler for the browser process at startup. This
+// will only work if chrome has been built with the gn arg enable_profiling =
+// true. The output will go to the value of kProfilingFile.
+const char kProfilingAtStart[] = "profiling-at-start";
+
+// Specifies a location for profiling output. This will only work if chrome has
+// been built with the gyp variable profiling=1 or gn arg enable_profiling=true.
+//
+// {pid} if present will be replaced by the pid of the process.
+// {count} if present will be incremented each time a profile is generated
+// for this process.
+// The default is chrome-profile-{pid} for the browser and test-profile-{pid}
+// for tests.
+const char kProfilingFile[] = "profiling-file";
+
+// Controls whether profile data is periodically flushed to a file. Normally
+// the data gets written on exit but cases exist where chromium doesn't exit
+// cleanly (especially when using single-process). A time in seconds can be
+// specified.
+const char kProfilingFlush[] = "profiling-flush";
+
+// When running certain tests that spawn child processes, this switch indicates
+// to the test framework that the current process is a child process.
+const char kTestChildProcess[] = "test-child-process";
+
+// When running certain tests that spawn child processes, this switch indicates
+// to the test framework that the current process should not initialize ICU to
+// avoid creating any scoped handles too early in startup.
+const char kTestDoNotInitializeIcu[] = "test-do-not-initialize-icu";
+
+// Sends trace events from these categories to a file.
+// --trace-to-file on its own sends to default categories.
+const char kTraceToFile[] = "trace-to-file";
+
+// Specifies the file name for --trace-to-file. If unspecified, it will
+// go to a default file name.
+const char kTraceToFileName[] = "trace-to-file-name";
+
+// Gives the default maximal active V-logging level; 0 is the default.
+// Normally positive values are used for V-logging levels.
+const char kV[] = "v";
+
+// Gives the per-module maximal V-logging levels to override the value
+// given by --v. E.g. "my_module=2,foo*=3" would change the logging
+// level for all code in source files "my_module.*" and "foo*.*"
+// ("-inl" suffixes are also disregarded for this matching).
+//
+// Any pattern containing a forward or backward slash will be tested
+// against the whole pathname and not just the module. E.g.,
+// "*/foo/bar/*=2" would change the logging level for all code in
+// source files under a "foo/bar" directory.
+const char kVModule[] = "vmodule";
+
+// Will wait for 60 seconds for a debugger to come to attach to the process.
+const char kWaitForDebugger[] = "wait-for-debugger";
+
+#if defined(OS_WIN)
+// Disable high-resolution timer on Windows.
+const char kDisableHighResTimer[] = "disable-highres-timer";
+
+// Disables the USB keyboard detection for blocking the OSK on Win8+.
+const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// The /dev/shm partition is too small in certain VM environments, causing
+// Chrome to fail or crash (see http://crbug.com/715363). Use this flag to
+// work-around this issue (a temporary directory will always be used to create
+// anonymous shared memory files).
+const char kDisableDevShmUsage[] = "disable-dev-shm-usage";
+#endif
+
+#if defined(OS_POSIX)
+// Used for turning on Breakpad crash reporting in a debug environment where
+// crash reporting is typically compiled but disabled.
+const char kEnableCrashReporterForTesting[] =
+ "enable-crash-reporter-for-testing";
+#endif
+
+#if defined(OS_ANDROID)
+// Enables the reached code profiler that samples all threads in all processes
+// to determine which functions are almost never executed.
+const char kEnableReachedCodeProfiler[] = "enable-reached-code-profiler";
+#endif
+
+#if defined(OS_LINUX)
+// Controls whether or not retired instruction counts are surfaced for threads
+// in trace events on Linux.
+//
+// This flag requires the BPF sandbox to be disabled.
+const char kEnableThreadInstructionCount[] = "enable-thread-instruction-count";
+#endif
+
+} // namespace switches
diff --git a/security/sandbox/chromium/base/base_switches.h b/security/sandbox/chromium/base/base_switches.h
new file mode 100644
index 0000000000..b1923efc1e
--- /dev/null
+++ b/security/sandbox/chromium/base/base_switches.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines all the "base" command-line switches.
+
+#ifndef BASE_BASE_SWITCHES_H_
+#define BASE_BASE_SWITCHES_H_
+
+#include "build/build_config.h"
+
+namespace switches {
+
+extern const char kDisableBestEffortTasks[];
+extern const char kDisableBreakpad[];
+extern const char kDisableFeatures[];
+extern const char kDisableLowEndDeviceMode[];
+extern const char kEnableCrashReporter[];
+extern const char kEnableFeatures[];
+extern const char kEnableLowEndDeviceMode[];
+extern const char kForceFieldTrials[];
+extern const char kFullMemoryCrashReport[];
+extern const char kLogBestEffortTasks[];
+extern const char kNoErrorDialogs[];
+extern const char kProfilingAtStart[];
+extern const char kProfilingFile[];
+extern const char kProfilingFlush[];
+extern const char kTestChildProcess[];
+extern const char kTestDoNotInitializeIcu[];
+extern const char kTraceToFile[];
+extern const char kTraceToFileName[];
+extern const char kV[];
+extern const char kVModule[];
+extern const char kWaitForDebugger[];
+
+#if defined(OS_WIN)
+extern const char kDisableHighResTimer[];
+extern const char kDisableUsbKeyboardDetect[];
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+extern const char kDisableDevShmUsage[];
+#endif
+
+#if defined(OS_POSIX)
+extern const char kEnableCrashReporterForTesting[];
+#endif
+
+#if defined(OS_ANDROID)
+extern const char kEnableReachedCodeProfiler[];
+extern const char kOrderfileMemoryOptimization[];
+#endif
+
+#if defined(OS_LINUX)
+extern const char kEnableThreadInstructionCount[];
+#endif
+
+} // namespace switches
+
+#endif // BASE_BASE_SWITCHES_H_
diff --git a/security/sandbox/chromium/base/bind.h b/security/sandbox/chromium/base/bind.h
new file mode 100644
index 0000000000..0bbc2aceb1
--- /dev/null
+++ b/security/sandbox/chromium/base/bind.h
@@ -0,0 +1,470 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_H_
+#define BASE_BIND_H_
+
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "base/bind_internal.h"
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX) && !HAS_FEATURE(objc_arc)
+#include "base/mac/scoped_block.h"
+#endif
+
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
+//
+// Overview:
+// base::BindOnce() and base::BindRepeating() are helpers for creating
+// base::OnceCallback and base::RepeatingCallback objects respectively.
+//
+// For a runnable object of n-arity, the base::Bind*() family allows partial
+// application of the first m arguments. The remaining n - m arguments must be
+// passed when invoking the callback with Run().
+//
+// // The first argument is bound at callback creation; the remaining
+// // two must be passed when calling Run() on the callback object.
+// base::OnceCallback<long(int, long)> cb = base::BindOnce(
+// [](short x, int y, long z) { return x * y * z; }, 42);
+//
+// When binding to a method, the receiver object must also be specified at
+// callback creation time. When Run() is invoked, the method will be invoked on
+// the specified receiver object.
+//
+// class C : public base::RefCounted<C> { void F(); };
+// auto instance = base::MakeRefCounted<C>();
+// auto cb = base::BindOnce(&C::F, instance);
+// std::move(cb).Run(); // Identical to instance->F()
+//
+// base::Bind is currently a type alias for base::BindRepeating(). In the
+// future, we expect to flip this to default to base::BindOnce().
+//
+// See //docs/callback.md for the full documentation.
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// If you're reading the implementation, before proceeding further, you should
+// read the top comment of base/bind_internal.h for a definition of common
+// terms and concepts.
+
+namespace base {
+
+namespace internal {
+
+// IsOnceCallback<T> is a std::true_type if |T| is a OnceCallback.
+template <typename T>
+struct IsOnceCallback : std::false_type {};
+
+template <typename Signature>
+struct IsOnceCallback<OnceCallback<Signature>> : std::true_type {};
+
+// Helper to assert that parameter |i| of type |Arg| can be bound, which means:
+// - |Arg| can be retained internally as |Storage|.
+// - |Arg| can be forwarded as |Unwrapped| to |Param|.
+template <size_t i,
+ typename Arg,
+ typename Storage,
+ typename Unwrapped,
+ typename Param>
+struct AssertConstructible {
+ private:
+ static constexpr bool param_is_forwardable =
+ std::is_constructible<Param, Unwrapped>::value;
+ // Unlike the check for binding into storage below, the check for
+ // forwardability drops the const qualifier for repeating callbacks. This is
+ // to try to catch instances where std::move()--which forwards as a const
+ // reference with repeating callbacks--is used instead of base::Passed().
+ static_assert(
+ param_is_forwardable ||
+ !std::is_constructible<Param, std::decay_t<Unwrapped>&&>::value,
+ "Bound argument |i| is move-only but will be forwarded by copy. "
+ "Ensure |Arg| is bound using base::Passed(), not std::move().");
+ static_assert(
+ param_is_forwardable,
+ "Bound argument |i| of type |Arg| cannot be forwarded as "
+ "|Unwrapped| to the bound functor, which declares it as |Param|.");
+
+ static constexpr bool arg_is_storable =
+ std::is_constructible<Storage, Arg>::value;
+ static_assert(arg_is_storable ||
+ !std::is_constructible<Storage, std::decay_t<Arg>&&>::value,
+ "Bound argument |i| is move-only but will be bound by copy. "
+ "Ensure |Arg| is mutable and bound using std::move().");
+ static_assert(arg_is_storable,
+ "Bound argument |i| of type |Arg| cannot be converted and "
+ "bound as |Storage|.");
+};
+
+// Takes three same-length TypeLists, and applies AssertConstructible for each
+// triples.
+template <typename Index,
+ typename Args,
+ typename UnwrappedTypeList,
+ typename ParamsList>
+struct AssertBindArgsValidity;
+
+template <size_t... Ns,
+ typename... Args,
+ typename... Unwrapped,
+ typename... Params>
+struct AssertBindArgsValidity<std::index_sequence<Ns...>,
+ TypeList<Args...>,
+ TypeList<Unwrapped...>,
+ TypeList<Params...>>
+ : AssertConstructible<Ns, Args, std::decay_t<Args>, Unwrapped, Params>... {
+ static constexpr bool ok = true;
+};
+
+// The implementation of TransformToUnwrappedType below.
+template <bool is_once, typename T>
+struct TransformToUnwrappedTypeImpl;
+
+template <typename T>
+struct TransformToUnwrappedTypeImpl<true, T> {
+ using StoredType = std::decay_t<T>;
+ using ForwardType = StoredType&&;
+ using Unwrapped = decltype(Unwrap(std::declval<ForwardType>()));
+};
+
+template <typename T>
+struct TransformToUnwrappedTypeImpl<false, T> {
+ using StoredType = std::decay_t<T>;
+ using ForwardType = const StoredType&;
+ using Unwrapped = decltype(Unwrap(std::declval<ForwardType>()));
+};
+
+// Transform |T| into `Unwrapped` type, which is passed to the target function.
+// Example:
+// In is_once == true case,
+// `int&&` -> `int&&`,
+// `const int&` -> `int&&`,
+// `OwnedWrapper<int>&` -> `int*&&`.
+// In is_once == false case,
+// `int&&` -> `const int&`,
+// `const int&` -> `const int&`,
+// `OwnedWrapper<int>&` -> `int* const &`.
+template <bool is_once, typename T>
+using TransformToUnwrappedType =
+ typename TransformToUnwrappedTypeImpl<is_once, T>::Unwrapped;
+
+// Transforms |Args| into `Unwrapped` types, and packs them into a TypeList.
+// If |is_method| is true, tries to dereference the first argument to support
+// smart pointers.
+template <bool is_once, bool is_method, typename... Args>
+struct MakeUnwrappedTypeListImpl {
+ using Type = TypeList<TransformToUnwrappedType<is_once, Args>...>;
+};
+
+// Performs special handling for this pointers.
+// Example:
+// int* -> int*,
+// std::unique_ptr<int> -> int*.
+template <bool is_once, typename Receiver, typename... Args>
+struct MakeUnwrappedTypeListImpl<is_once, true, Receiver, Args...> {
+ using UnwrappedReceiver = TransformToUnwrappedType<is_once, Receiver>;
+ using Type = TypeList<decltype(&*std::declval<UnwrappedReceiver>()),
+ TransformToUnwrappedType<is_once, Args>...>;
+};
+
+template <bool is_once, bool is_method, typename... Args>
+using MakeUnwrappedTypeList =
+ typename MakeUnwrappedTypeListImpl<is_once, is_method, Args...>::Type;
+
+// Used below in BindImpl to determine whether to use Invoker::Run or
+// Invoker::RunOnce.
+// Note: Simply using `kIsOnce ? &Invoker::RunOnce : &Invoker::Run` does not
+// work, since the compiler needs to check whether both expressions are
+// well-formed. Using `Invoker::Run` with a OnceCallback triggers a
+// static_assert, which is why the ternary expression does not compile.
+// TODO(crbug.com/752720): Remove this indirection once we have `if constexpr`.
+template <typename Invoker>
+constexpr auto GetInvokeFunc(std::true_type) {
+ return Invoker::RunOnce;
+}
+
+template <typename Invoker>
+constexpr auto GetInvokeFunc(std::false_type) {
+ return Invoker::Run;
+}
+
+template <template <typename> class CallbackT,
+ typename Functor,
+ typename... Args>
+decltype(auto) BindImpl(Functor&& functor, Args&&... args) {
+ // This block checks if each |args| matches to the corresponding params of the
+ // target function. This check does not affect the behavior of Bind, but its
+ // error message should be more readable.
+ static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;
+ using Helper = internal::BindTypeHelper<Functor, Args...>;
+ using FunctorTraits = typename Helper::FunctorTraits;
+ using BoundArgsList = typename Helper::BoundArgsList;
+ using UnwrappedArgsList =
+ internal::MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method,
+ Args&&...>;
+ using BoundParamsList = typename Helper::BoundParamsList;
+ static_assert(internal::AssertBindArgsValidity<
+ std::make_index_sequence<Helper::num_bounds>, BoundArgsList,
+ UnwrappedArgsList, BoundParamsList>::ok,
+ "The bound args need to be convertible to the target params.");
+
+ using BindState = internal::MakeBindStateType<Functor, Args...>;
+ using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
+ using Invoker = internal::Invoker<BindState, UnboundRunType>;
+ using CallbackType = CallbackT<UnboundRunType>;
+
+ // Store the invoke func into PolymorphicInvoke before casting it to
+ // InvokeFuncStorage, so that we can ensure its type matches to
+ // PolymorphicInvoke, to which CallbackType will cast back.
+ using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
+ PolymorphicInvoke invoke_func =
+ GetInvokeFunc<Invoker>(std::integral_constant<bool, kIsOnce>());
+
+ using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
+ return CallbackType(BindState::Create(
+ reinterpret_cast<InvokeFuncStorage>(invoke_func),
+ std::forward<Functor>(functor), std::forward<Args>(args)...));
+}
+
+} // namespace internal
+
+// Bind as OnceCallback.
+template <typename Functor, typename... Args>
+inline OnceCallback<MakeUnboundRunType<Functor, Args...>> BindOnce(
+ Functor&& functor,
+ Args&&... args) {
+ static_assert(!internal::IsOnceCallback<std::decay_t<Functor>>() ||
+ (std::is_rvalue_reference<Functor&&>() &&
+ !std::is_const<std::remove_reference_t<Functor>>()),
+ "BindOnce requires non-const rvalue for OnceCallback binding."
+ " I.e.: base::BindOnce(std::move(callback)).");
+
+ return internal::BindImpl<OnceCallback>(std::forward<Functor>(functor),
+ std::forward<Args>(args)...);
+}
+
+// Bind as RepeatingCallback.
+template <typename Functor, typename... Args>
+inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>>
+BindRepeating(Functor&& functor, Args&&... args) {
+ static_assert(
+ !internal::IsOnceCallback<std::decay_t<Functor>>(),
+ "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move().");
+
+ return internal::BindImpl<RepeatingCallback>(std::forward<Functor>(functor),
+ std::forward<Args>(args)...);
+}
+
+// Unannotated Bind.
+// TODO(tzik): Deprecate this and migrate to OnceCallback and
+// RepeatingCallback, once they get ready.
+template <typename Functor, typename... Args>
+inline Callback<MakeUnboundRunType<Functor, Args...>>
+Bind(Functor&& functor, Args&&... args) {
+ return base::BindRepeating(std::forward<Functor>(functor),
+ std::forward<Args>(args)...);
+}
+
+// Special cases for binding to a base::Callback without extra bound arguments.
+template <typename Signature>
+OnceCallback<Signature> BindOnce(OnceCallback<Signature> callback) {
+ return callback;
+}
+
+template <typename Signature>
+OnceCallback<Signature> BindOnce(RepeatingCallback<Signature> callback) {
+ return callback;
+}
+
+template <typename Signature>
+RepeatingCallback<Signature> BindRepeating(
+ RepeatingCallback<Signature> callback) {
+ return callback;
+}
+
+template <typename Signature>
+Callback<Signature> Bind(Callback<Signature> callback) {
+ return callback;
+}
+
+// Unretained() allows binding a non-refcounted class, and to disable
+// refcounting on arguments that are refcounted objects.
+//
+// EXAMPLE OF Unretained():
+//
+// class Foo {
+// public:
+// void func() { cout << "Foo:f" << endl; }
+// };
+//
+// // In some function somewhere.
+// Foo foo;
+// OnceClosure foo_callback =
+// BindOnce(&Foo::func, Unretained(&foo));
+// std::move(foo_callback).Run(); // Prints "Foo:f".
+//
+// Without the Unretained() wrapper on |&foo|, the above call would fail
+// to compile because Foo does not support the AddRef() and Release() methods.
+template <typename T>
+static inline internal::UnretainedWrapper<T> Unretained(T* o) {
+ return internal::UnretainedWrapper<T>(o);
+}
+
+// RetainedRef() accepts a ref counted object and retains a reference to it.
+// When the callback is called, the object is passed as a raw pointer.
+//
+// EXAMPLE OF RetainedRef():
+//
+// void foo(RefCountedBytes* bytes) {}
+//
+// scoped_refptr<RefCountedBytes> bytes = ...;
+// OnceClosure callback = BindOnce(&foo, base::RetainedRef(bytes));
+// std::move(callback).Run();
+//
+// Without RetainedRef, the scoped_refptr would try to implicitly convert to
+// a raw pointer and fail compilation:
+//
+// OnceClosure callback = BindOnce(&foo, bytes); // ERROR!
+template <typename T>
+static inline internal::RetainedRefWrapper<T> RetainedRef(T* o) {
+ return internal::RetainedRefWrapper<T>(o);
+}
+template <typename T>
+static inline internal::RetainedRefWrapper<T> RetainedRef(scoped_refptr<T> o) {
+ return internal::RetainedRefWrapper<T>(std::move(o));
+}
+
+// Owned() transfers ownership of an object to the callback resulting from
+// bind; the object will be deleted when the callback is deleted.
+//
+// EXAMPLE OF Owned():
+//
+// void foo(int* arg) { cout << *arg << endl }
+//
+// int* pn = new int(1);
+// RepeatingClosure foo_callback = BindRepeating(&foo, Owned(pn));
+//
+// foo_callback.Run(); // Prints "1"
+// foo_callback.Run(); // Prints "1"
+// *pn = 2;
+// foo_callback.Run(); // Prints "2"
+//
+// foo_callback.Reset(); // |pn| is deleted. Also will happen when
+// // |foo_callback| goes out of scope.
+//
+// Without Owned(), someone would have to know to delete |pn| when the last
+// reference to the callback is deleted.
+template <typename T>
+static inline internal::OwnedWrapper<T> Owned(T* o) {
+ return internal::OwnedWrapper<T>(o);
+}
+
+template <typename T, typename Deleter>
+static inline internal::OwnedWrapper<T, Deleter> Owned(
+ std::unique_ptr<T, Deleter>&& ptr) {
+ return internal::OwnedWrapper<T, Deleter>(std::move(ptr));
+}
+
+// Passed() is for transferring movable-but-not-copyable types (eg. unique_ptr)
+// through a RepeatingCallback. Logically, this signifies a destructive transfer
+// of the state of the argument into the target function. Invoking
+// RepeatingCallback::Run() twice on a callback that was created with a Passed()
+// argument will CHECK() because the first invocation would have already
+// transferred ownership to the target function.
+//
+// Note that Passed() is not necessary with BindOnce(), as std::move() does the
+// same thing. Avoid Passed() in favor of std::move() with BindOnce().
+//
+// EXAMPLE OF Passed():
+//
+// void TakesOwnership(std::unique_ptr<Foo> arg) { }
+// std::unique_ptr<Foo> CreateFoo() { return std::make_unique<Foo>();
+// }
+//
+// auto f = std::make_unique<Foo>();
+//
+// // |cb| is given ownership of Foo(). |f| is now NULL.
+// // You can use std::move(f) in place of &f, but it's more verbose.
+// RepeatingClosure cb = BindRepeating(&TakesOwnership, Passed(&f));
+//
+// // Run was never called so |cb| still owns Foo() and deletes
+// // it on Reset().
+// cb.Reset();
+//
+// // |cb| is given a new Foo created by CreateFoo().
+// cb = BindRepeating(&TakesOwnership, Passed(CreateFoo()));
+//
+// // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
+// // no longer owns Foo() and, if reset, would not delete Foo().
+// cb.Run(); // Foo() is now transferred to |arg| and deleted.
+// cb.Run(); // This CHECK()s since Foo() already been used once.
+//
+// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and is
+// best suited for use with the return value of a function or other temporary
+// rvalues. The second takes a pointer to the scoper and is just syntactic sugar
+// to avoid having to write Passed(std::move(scoper)).
+//
+// Both versions of Passed() prevent T from being an lvalue reference. The first
+// via use of enable_if, and the second takes a T* which will not bind to T&.
+template <typename T,
+ std::enable_if_t<!std::is_lvalue_reference<T>::value>* = nullptr>
+static inline internal::PassedWrapper<T> Passed(T&& scoper) {
+ return internal::PassedWrapper<T>(std::move(scoper));
+}
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T* scoper) {
+ return internal::PassedWrapper<T>(std::move(*scoper));
+}
+
+// IgnoreResult() is used to adapt a function or callback with a return type to
+// one with a void return. This is most useful if you have a function with,
+// say, a pesky ignorable bool return that you want to use with PostTask or
+// something else that expect a callback with a void return.
+//
+// EXAMPLE OF IgnoreResult():
+//
+// int DoSomething(int arg) { cout << arg << endl; }
+//
+// // Assign to a callback with a void return type.
+// OnceCallback<void(int)> cb = BindOnce(IgnoreResult(&DoSomething));
+// std::move(cb).Run(1); // Prints "1".
+//
+// // Prints "2" on |ml|.
+// ml->PostTask(FROM_HERE, BindOnce(IgnoreResult(&DoSomething), 2);
+template <typename T>
+static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
+ return internal::IgnoreResultHelper<T>(std::move(data));
+}
+
+#if defined(OS_MACOSX) && !HAS_FEATURE(objc_arc)
+
+// RetainBlock() is used to adapt an Objective-C block when Automated Reference
+// Counting (ARC) is disabled. This is unnecessary when ARC is enabled, as the
+// BindOnce and BindRepeating already support blocks then.
+//
+// EXAMPLE OF RetainBlock():
+//
+// // Wrap the block and bind it to a callback.
+// OnceCallback<void(int)> cb =
+// BindOnce(RetainBlock(^(int n) { NSLog(@"%d", n); }));
+// std::move(cb).Run(1); // Logs "1".
+template <typename R, typename... Args>
+base::mac::ScopedBlock<R (^)(Args...)> RetainBlock(R (^block)(Args...)) {
+ return base::mac::ScopedBlock<R (^)(Args...)>(block,
+ base::scoped_policy::RETAIN);
+}
+
+#endif // defined(OS_MACOSX) && !HAS_FEATURE(objc_arc)
+
+} // namespace base
+
+#endif // BASE_BIND_H_
diff --git a/security/sandbox/chromium/base/bind_helpers.h b/security/sandbox/chromium/base/bind_helpers.h
new file mode 100644
index 0000000000..37065a07ab
--- /dev/null
+++ b/security/sandbox/chromium/base/bind_helpers.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_HELPERS_H_
+#define BASE_BIND_HELPERS_H_
+
+#include <stddef.h>
+
+#include <type_traits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
+
+// This defines a set of simple functions and utilities that people want when
+// using {Once,Repeating}Callback<> and Bind{Once,Repeating}().
+
+namespace base {
+
+// Creates a null callback.
+class BASE_EXPORT NullCallback {
+ public:
+ template <typename R, typename... Args>
+ operator RepeatingCallback<R(Args...)>() const {
+ return RepeatingCallback<R(Args...)>();
+ }
+ template <typename R, typename... Args>
+ operator OnceCallback<R(Args...)>() const {
+ return OnceCallback<R(Args...)>();
+ }
+};
+
+// Creates a callback that does nothing when called.
+class BASE_EXPORT DoNothing {
+ public:
+ template <typename... Args>
+ operator RepeatingCallback<void(Args...)>() const {
+ return Repeatedly<Args...>();
+ }
+ template <typename... Args>
+ operator OnceCallback<void(Args...)>() const {
+ return Once<Args...>();
+ }
+ // Explicit way of specifying a specific callback type when the compiler can't
+ // deduce it.
+ template <typename... Args>
+ static RepeatingCallback<void(Args...)> Repeatedly() {
+ return BindRepeating([](Args... args) {});
+ }
+ template <typename... Args>
+ static OnceCallback<void(Args...)> Once() {
+ return BindOnce([](Args... args) {});
+ }
+};
+
+// Useful for creating a Closure that will delete a pointer when invoked. Only
+// use this when necessary. In most cases MessageLoop::DeleteSoon() is a better
+// fit.
+template <typename T>
+void DeletePointer(T* obj) {
+ delete obj;
+}
+
+} // namespace base
+
+#endif // BASE_BIND_HELPERS_H_
diff --git a/security/sandbox/chromium/base/bind_internal.h b/security/sandbox/chromium/base/bind_internal.h
new file mode 100644
index 0000000000..bed151a8dc
--- /dev/null
+++ b/security/sandbox/chromium/base/bind_internal.h
@@ -0,0 +1,1050 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIND_INTERNAL_H_
+#define BASE_BIND_INTERNAL_H_
+
+#include <stddef.h>
+
+#include <functional>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_internal.h"
+#include "base/compiler_specific.h"
+#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX) && !HAS_FEATURE(objc_arc)
+#include "base/mac/scoped_block.h"
+#endif
+
+// See base/callback.h for user documentation.
+//
+//
+// CONCEPTS:
+// Functor -- A movable type representing something that should be called.
+// All function pointers and Callback<> are functors even if the
+// invocation syntax differs.
+// RunType -- A function type (as opposed to function _pointer_ type) for
+// a Callback<>::Run(). Usually just a convenience typedef.
+// (Bound)Args -- A set of types that stores the arguments.
+//
+// Types:
+// ForceVoidReturn<> -- Helper class for translating function signatures to
+// equivalent forms with a "void" return type.
+// FunctorTraits<> -- Type traits used to determine the correct RunType and
+// invocation manner for a Functor. This is where function
+// signature adapters are applied.
+// InvokeHelper<> -- Take a Functor + arguments and actully invokes it.
+// Handle the differing syntaxes needed for WeakPtr<>
+// support. This is separate from Invoker to avoid creating
+// multiple version of Invoker<>.
+// Invoker<> -- Unwraps the curried parameters and executes the Functor.
+// BindState<> -- Stores the curried parameters, and is the main entry point
+// into the Bind() system.
+
+#if defined(OS_WIN)
+namespace Microsoft {
+namespace WRL {
+template <typename>
+class ComPtr;
+} // namespace WRL
+} // namespace Microsoft
+#endif
+
+namespace base {
+
+template <typename T>
+struct IsWeakReceiver;
+
+template <typename>
+struct BindUnwrapTraits;
+
+template <typename Functor, typename BoundArgsTuple, typename SFINAE = void>
+struct CallbackCancellationTraits;
+
+namespace internal {
+
+template <typename Functor, typename SFINAE = void>
+struct FunctorTraits;
+
+template <typename T>
+class UnretainedWrapper {
+ public:
+ explicit UnretainedWrapper(T* o) : ptr_(o) {}
+ T* get() const { return ptr_; }
+
+ private:
+ T* ptr_;
+};
+
+template <typename T>
+class RetainedRefWrapper {
+ public:
+ explicit RetainedRefWrapper(T* o) : ptr_(o) {}
+ explicit RetainedRefWrapper(scoped_refptr<T> o) : ptr_(std::move(o)) {}
+ T* get() const { return ptr_.get(); }
+
+ private:
+ scoped_refptr<T> ptr_;
+};
+
+template <typename T>
+struct IgnoreResultHelper {
+ explicit IgnoreResultHelper(T functor) : functor_(std::move(functor)) {}
+ explicit operator bool() const { return !!functor_; }
+
+ T functor_;
+};
+
+template <typename T, typename Deleter = std::default_delete<T>>
+class OwnedWrapper {
+ public:
+ explicit OwnedWrapper(T* o) : ptr_(o) {}
+ explicit OwnedWrapper(std::unique_ptr<T, Deleter>&& ptr)
+ : ptr_(std::move(ptr)) {}
+ T* get() const { return ptr_.get(); }
+
+ private:
+ std::unique_ptr<T, Deleter> ptr_;
+};
+
+// PassedWrapper is a copyable adapter for a scoper that ignores const.
+//
+// It is needed to get around the fact that Bind() takes a const reference to
+// all its arguments. Because Bind() takes a const reference to avoid
+// unnecessary copies, it is incompatible with movable-but-not-copyable
+// types; doing a destructive "move" of the type into Bind() would violate
+// the const correctness.
+//
+// This conundrum cannot be solved without either C++11 rvalue references or
+// a O(2^n) blowup of Bind() templates to handle each combination of regular
+// types and movable-but-not-copyable types. Thus we introduce a wrapper type
+// that is copyable to transmit the correct type information down into
+// BindState<>. Ignoring const in this type makes sense because it is only
+// created when we are explicitly trying to do a destructive move.
+//
+// Two notes:
+// 1) PassedWrapper supports any type that has a move constructor, however
+// the type will need to be specifically whitelisted in order for it to be
+// bound to a Callback. We guard this explicitly at the call of Passed()
+// to make for clear errors. Things not given to Passed() will be forwarded
+// and stored by value which will not work for general move-only types.
+// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
+// scoper to a Callback and allow the Callback to execute once.
+template <typename T>
+class PassedWrapper {
+ public:
+ explicit PassedWrapper(T&& scoper)
+ : is_valid_(true), scoper_(std::move(scoper)) {}
+ PassedWrapper(PassedWrapper&& other)
+ : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
+ T Take() const {
+ CHECK(is_valid_);
+ is_valid_ = false;
+ return std::move(scoper_);
+ }
+
+ private:
+ mutable bool is_valid_;
+ mutable T scoper_;
+};
+
+template <typename T>
+using Unwrapper = BindUnwrapTraits<std::decay_t<T>>;
+
+template <typename T>
+decltype(auto) Unwrap(T&& o) {
+ return Unwrapper<T>::Unwrap(std::forward<T>(o));
+}
+
+// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
+// method. It is used internally by Bind() to select the correct
+// InvokeHelper that will no-op itself in the event the WeakPtr<> for
+// the target object is invalidated.
+//
+// The first argument should be the type of the object that will be received by
+// the method.
+template <bool is_method, typename... Args>
+struct IsWeakMethod : std::false_type {};
+
+template <typename T, typename... Args>
+struct IsWeakMethod<true, T, Args...> : IsWeakReceiver<T> {};
+
+// Packs a list of types to hold them in a single type.
+template <typename... Types>
+struct TypeList {};
+
+// Used for DropTypeListItem implementation.
+template <size_t n, typename List>
+struct DropTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List>
+struct DropTypeListItemImpl<n, TypeList<T, List...>>
+ : DropTypeListItemImpl<n - 1, TypeList<List...>> {};
+
+template <typename T, typename... List>
+struct DropTypeListItemImpl<0, TypeList<T, List...>> {
+ using Type = TypeList<T, List...>;
+};
+
+template <>
+struct DropTypeListItemImpl<0, TypeList<>> {
+ using Type = TypeList<>;
+};
+
+// A type-level function that drops |n| list item from given TypeList.
+template <size_t n, typename List>
+using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
+
+// Used for TakeTypeListItem implementation.
+template <size_t n, typename List, typename... Accum>
+struct TakeTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
+ : TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
+
+template <typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+template <typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+// A type-level function that takes first |n| list item from given TypeList.
+// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
+// TypeList<A, B, C>.
+template <size_t n, typename List>
+using TakeTypeListItem = typename TakeTypeListItemImpl<n, List>::Type;
+
+// Used for ConcatTypeLists implementation.
+template <typename List1, typename List2>
+struct ConcatTypeListsImpl;
+
+template <typename... Types1, typename... Types2>
+struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
+ using Type = TypeList<Types1..., Types2...>;
+};
+
+// A type-level function that concats two TypeLists.
+template <typename List1, typename List2>
+using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type;
+
+// Used for MakeFunctionType implementation.
+template <typename R, typename ArgList>
+struct MakeFunctionTypeImpl;
+
+template <typename R, typename... Args>
+struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R Type(Args...);
+};
+
+// A type-level function that constructs a function type that has |R| as its
+// return type and has TypeLists items as its arguments.
+template <typename R, typename ArgList>
+using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
+
+// Used for ExtractArgs and ExtractReturnType.
+template <typename Signature>
+struct ExtractArgsImpl;
+
+template <typename R, typename... Args>
+struct ExtractArgsImpl<R(Args...)> {
+ using ReturnType = R;
+ using ArgsList = TypeList<Args...>;
+};
+
+// A type-level function that extracts function arguments into a TypeList.
+// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
+template <typename Signature>
+using ExtractArgs = typename ExtractArgsImpl<Signature>::ArgsList;
+
+// A type-level function that extracts the return type of a function.
+// E.g. ExtractReturnType<R(A, B, C)> is evaluated to R.
+template <typename Signature>
+using ExtractReturnType = typename ExtractArgsImpl<Signature>::ReturnType;
+
+template <typename Callable,
+ typename Signature = decltype(&Callable::operator())>
+struct ExtractCallableRunTypeImpl;
+
+template <typename Callable, typename R, typename... Args>
+struct ExtractCallableRunTypeImpl<Callable, R (Callable::*)(Args...)> {
+ using Type = R(Args...);
+};
+
+template <typename Callable, typename R, typename... Args>
+struct ExtractCallableRunTypeImpl<Callable, R (Callable::*)(Args...) const> {
+ using Type = R(Args...);
+};
+
+// Evaluated to RunType of the given callable type.
+// Example:
+// auto f = [](int, char*) { return 0.1; };
+// ExtractCallableRunType<decltype(f)>
+// is evaluated to
+// double(int, char*);
+template <typename Callable>
+using ExtractCallableRunType =
+ typename ExtractCallableRunTypeImpl<Callable>::Type;
+
+// IsCallableObject<Functor> is std::true_type if |Functor| has operator().
+// Otherwise, it's std::false_type.
+// Example:
+// IsCallableObject<void(*)()>::value is false.
+//
+// struct Foo {};
+// IsCallableObject<void(Foo::*)()>::value is false.
+//
+// int i = 0;
+// auto f = [i]() {};
+// IsCallableObject<decltype(f)>::value is false.
+template <typename Functor, typename SFINAE = void>
+struct IsCallableObject : std::false_type {};
+
+template <typename Callable>
+struct IsCallableObject<Callable, void_t<decltype(&Callable::operator())>>
+ : std::true_type {};
+
+// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
+// pointer to a RefCounted type.
+// Implementation note: This non-specialized case handles zero-arity case only.
+// Non-zero-arity cases should be handled by the specialization below.
+template <typename... Args>
+struct HasRefCountedTypeAsRawPtr : std::false_type {};
+
+// Implementation note: Select true_type if the first parameter is a raw pointer
+// to a RefCounted type. Otherwise, skip the first parameter and check rest of
+// parameters recursively.
+template <typename T, typename... Args>
+struct HasRefCountedTypeAsRawPtr<T, Args...>
+ : std::conditional_t<NeedsScopedRefptrButGetsRawPtr<T>::value,
+ std::true_type,
+ HasRefCountedTypeAsRawPtr<Args...>> {};
+
+// ForceVoidReturn<>
+//
+// Set of templates that support forcing the function return type to void.
+template <typename Sig>
+struct ForceVoidReturn;
+
+template <typename R, typename... Args>
+struct ForceVoidReturn<R(Args...)> {
+ using RunType = void(Args...);
+};
+
+// FunctorTraits<>
+//
+// See description at top of file.
+template <typename Functor, typename SFINAE>
+struct FunctorTraits;
+
+// For empty callable types.
+// This specialization is intended to allow binding captureless lambdas, based
+// on the fact that captureless lambdas are empty while capturing lambdas are
+// not. This also allows any functors as far as it's an empty class.
+// Example:
+//
+// // Captureless lambdas are allowed.
+// []() {return 42;};
+//
+// // Capturing lambdas are *not* allowed.
+// int x;
+// [x]() {return x;};
+//
+// // Any empty class with operator() is allowed.
+// struct Foo {
+// void operator()() const {}
+// // No non-static member variable and no virtual functions.
+// };
+template <typename Functor>
+struct FunctorTraits<Functor,
+ std::enable_if_t<IsCallableObject<Functor>::value &&
+ std::is_empty<Functor>::value>> {
+ using RunType = ExtractCallableRunType<Functor>;
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = false;
+
+ template <typename RunFunctor, typename... RunArgs>
+ static ExtractReturnType<RunType> Invoke(RunFunctor&& functor,
+ RunArgs&&... args) {
+ return std::forward<RunFunctor>(functor)(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R (*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+
+ template <typename Function, typename... RunArgs>
+ static R Invoke(Function&& function, RunArgs&&... args) {
+ return std::forward<Function>(function)(std::forward<RunArgs>(args)...);
+ }
+};
+
+#if defined(OS_WIN) && !defined(ARCH_CPU_64_BITS)
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__stdcall*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+
+ template <typename... RunArgs>
+ static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) {
+ return function(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__fastcall*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+
+ template <typename... RunArgs>
+ static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) {
+ return function(std::forward<RunArgs>(args)...);
+ }
+};
+
+#endif // defined(OS_WIN) && !defined(ARCH_CPU_64_BITS)
+
+#if defined(OS_MACOSX)
+
+// Support for Objective-C blocks. There are two implementation depending
+// on whether Automated Reference Counting (ARC) is enabled. When ARC is
+// enabled, then the block itself can be bound as the compiler will ensure
+// its lifetime will be correctly managed. Otherwise, require the block to
+// be wrapped in a base::mac::ScopedBlock (via base::RetainBlock) that will
+// correctly manage the block lifetime.
+//
+// The two implementation ensure that the One Definition Rule (ODR) is not
+// broken (it is not possible to write a template base::RetainBlock that would
+// work correctly both with ARC enabled and disabled).
+
+#if HAS_FEATURE(objc_arc)
+
+template <typename R, typename... Args>
+struct FunctorTraits<R (^)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+
+ template <typename BlockType, typename... RunArgs>
+ static R Invoke(BlockType&& block, RunArgs&&... args) {
+ // According to LLVM documentation (§ 6.3), "local variables of automatic
+ // storage duration do not have precise lifetime." Use objc_precise_lifetime
+ // to ensure that the Objective-C block is not deallocated until it has
+ // finished executing even if the Callback<> is destroyed during the block
+ // execution.
+ // https://clang.llvm.org/docs/AutomaticReferenceCounting.html#precise-lifetime-semantics
+ __attribute__((objc_precise_lifetime)) R (^scoped_block)(Args...) = block;
+ return scoped_block(std::forward<RunArgs>(args)...);
+ }
+};
+
+#else // HAS_FEATURE(objc_arc)
+
+template <typename R, typename... Args>
+struct FunctorTraits<base::mac::ScopedBlock<R (^)(Args...)>> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+
+ template <typename BlockType, typename... RunArgs>
+ static R Invoke(BlockType&& block, RunArgs&&... args) {
+ // Copy the block to ensure that the Objective-C block is not deallocated
+ // until it has finished executing even if the Callback<> is destroyed
+ // during the block execution.
+ base::mac::ScopedBlock<R (^)(Args...)> scoped_block(block);
+ return scoped_block.get()(std::forward<RunArgs>(args)...);
+ }
+};
+
+#endif // HAS_FEATURE(objc_arc)
+#endif // defined(OS_MACOSX)
+
+// For methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...)> {
+ using RunType = R(Receiver*, Args...);
+ static constexpr bool is_method = true;
+ static constexpr bool is_nullable = true;
+
+ template <typename Method, typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(Method method,
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For const methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) const> {
+ using RunType = R(const Receiver*, Args...);
+ static constexpr bool is_method = true;
+ static constexpr bool is_nullable = true;
+
+ template <typename Method, typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(Method method,
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+#ifdef __cpp_noexcept_function_type
+// noexcept makes a distinct function type in C++17.
+// I.e. `void(*)()` and `void(*)() noexcept` are same in pre-C++17, and
+// different in C++17.
+template <typename R, typename... Args>
+struct FunctorTraits<R (*)(Args...) noexcept> : FunctorTraits<R (*)(Args...)> {
+};
+
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) noexcept>
+ : FunctorTraits<R (Receiver::*)(Args...)> {};
+
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) const noexcept>
+ : FunctorTraits<R (Receiver::*)(Args...) const> {};
+#endif
+
+// For IgnoreResults.
+template <typename T>
+struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
+ using RunType =
+ typename ForceVoidReturn<typename FunctorTraits<T>::RunType>::RunType;
+
+ template <typename IgnoreResultType, typename... RunArgs>
+ static void Invoke(IgnoreResultType&& ignore_result_helper,
+ RunArgs&&... args) {
+ FunctorTraits<T>::Invoke(
+ std::forward<IgnoreResultType>(ignore_result_helper).functor_,
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+// For OnceCallbacks.
+template <typename R, typename... Args>
+struct FunctorTraits<OnceCallback<R(Args...)>> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+
+ template <typename CallbackType, typename... RunArgs>
+ static R Invoke(CallbackType&& callback, RunArgs&&... args) {
+ DCHECK(!callback.is_null());
+ return std::forward<CallbackType>(callback).Run(
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+// For RepeatingCallbacks.
+template <typename R, typename... Args>
+struct FunctorTraits<RepeatingCallback<R(Args...)>> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+
+ template <typename CallbackType, typename... RunArgs>
+ static R Invoke(CallbackType&& callback, RunArgs&&... args) {
+ DCHECK(!callback.is_null());
+ return std::forward<CallbackType>(callback).Run(
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+template <typename Functor>
+using MakeFunctorTraits = FunctorTraits<std::decay_t<Functor>>;
+
+// InvokeHelper<>
+//
+// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// WeakCalls need special syntax that is applied to the first argument to check
+// if they should no-op themselves.
+template <bool is_weak_call, typename ReturnType>
+struct InvokeHelper;
+
+template <typename ReturnType>
+struct InvokeHelper<false, ReturnType> {
+ template <typename Functor, typename... RunArgs>
+ static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) {
+ using Traits = MakeFunctorTraits<Functor>;
+ return Traits::Invoke(std::forward<Functor>(functor),
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+template <typename ReturnType>
+struct InvokeHelper<true, ReturnType> {
+ // WeakCalls are only supported for functions with a void return type.
+ // Otherwise, the function result would be undefined if the the WeakPtr<>
+ // is invalidated.
+ static_assert(std::is_void<ReturnType>::value,
+ "weak_ptrs can only bind to methods without return values");
+
+ template <typename Functor, typename BoundWeakPtr, typename... RunArgs>
+ static inline void MakeItSo(Functor&& functor,
+ BoundWeakPtr&& weak_ptr,
+ RunArgs&&... args) {
+ if (!weak_ptr)
+ return;
+ using Traits = MakeFunctorTraits<Functor>;
+ Traits::Invoke(std::forward<Functor>(functor),
+ std::forward<BoundWeakPtr>(weak_ptr),
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+// Invoker<>
+//
+// See description at the top of the file.
+template <typename StorageType, typename UnboundRunType>
+struct Invoker;
+
+template <typename StorageType, typename R, typename... UnboundArgs>
+struct Invoker<StorageType, R(UnboundArgs...)> {
+ static R RunOnce(BindStateBase* base,
+ PassingType<UnboundArgs>... unbound_args) {
+ // Local references to make debugger stepping easier. If in a debugger,
+ // you really want to warp ahead and step through the
+ // InvokeHelper<>::MakeItSo() call below.
+ StorageType* storage = static_cast<StorageType*>(base);
+ static constexpr size_t num_bound_args =
+ std::tuple_size<decltype(storage->bound_args_)>::value;
+ return RunImpl(std::move(storage->functor_),
+ std::move(storage->bound_args_),
+ std::make_index_sequence<num_bound_args>(),
+ std::forward<UnboundArgs>(unbound_args)...);
+ }
+
+ static R Run(BindStateBase* base, PassingType<UnboundArgs>... unbound_args) {
+ // Local references to make debugger stepping easier. If in a debugger,
+ // you really want to warp ahead and step through the
+ // InvokeHelper<>::MakeItSo() call below.
+ const StorageType* storage = static_cast<StorageType*>(base);
+ static constexpr size_t num_bound_args =
+ std::tuple_size<decltype(storage->bound_args_)>::value;
+ return RunImpl(storage->functor_, storage->bound_args_,
+ std::make_index_sequence<num_bound_args>(),
+ std::forward<UnboundArgs>(unbound_args)...);
+ }
+
+ private:
+ template <typename Functor, typename BoundArgsTuple, size_t... indices>
+ static inline R RunImpl(Functor&& functor,
+ BoundArgsTuple&& bound,
+ std::index_sequence<indices...>,
+ UnboundArgs&&... unbound_args) {
+ static constexpr bool is_method = MakeFunctorTraits<Functor>::is_method;
+
+ using DecayedArgsTuple = std::decay_t<BoundArgsTuple>;
+ static constexpr bool is_weak_call =
+ IsWeakMethod<is_method,
+ std::tuple_element_t<indices, DecayedArgsTuple>...>();
+
+ return InvokeHelper<is_weak_call, R>::MakeItSo(
+ std::forward<Functor>(functor),
+ Unwrap(std::get<indices>(std::forward<BoundArgsTuple>(bound)))...,
+ std::forward<UnboundArgs>(unbound_args)...);
+ }
+};
+
+// Extracts necessary type info from Functor and BoundArgs.
+// Used to implement MakeUnboundRunType, BindOnce and BindRepeating.
+template <typename Functor, typename... BoundArgs>
+struct BindTypeHelper {
+ static constexpr size_t num_bounds = sizeof...(BoundArgs);
+ using FunctorTraits = MakeFunctorTraits<Functor>;
+
+ // Example:
+ // When Functor is `double (Foo::*)(int, const std::string&)`, and BoundArgs
+ // is a template pack of `Foo*` and `int16_t`:
+ // - RunType is `double(Foo*, int, const std::string&)`,
+ // - ReturnType is `double`,
+ // - RunParamsList is `TypeList<Foo*, int, const std::string&>`,
+ // - BoundParamsList is `TypeList<Foo*, int>`,
+ // - UnboundParamsList is `TypeList<const std::string&>`,
+ // - BoundArgsList is `TypeList<Foo*, int16_t>`,
+ // - UnboundRunType is `double(const std::string&)`.
+ using RunType = typename FunctorTraits::RunType;
+ using ReturnType = ExtractReturnType<RunType>;
+
+ using RunParamsList = ExtractArgs<RunType>;
+ using BoundParamsList = TakeTypeListItem<num_bounds, RunParamsList>;
+ using UnboundParamsList = DropTypeListItem<num_bounds, RunParamsList>;
+
+ using BoundArgsList = TypeList<BoundArgs...>;
+
+ using UnboundRunType = MakeFunctionType<ReturnType, UnboundParamsList>;
+};
+
+template <typename Functor>
+std::enable_if_t<FunctorTraits<Functor>::is_nullable, bool> IsNull(
+ const Functor& functor) {
+ return !functor;
+}
+
+template <typename Functor>
+std::enable_if_t<!FunctorTraits<Functor>::is_nullable, bool> IsNull(
+ const Functor&) {
+ return false;
+}
+
+// Used by QueryCancellationTraits below.
+template <typename Functor, typename BoundArgsTuple, size_t... indices>
+bool QueryCancellationTraitsImpl(BindStateBase::CancellationQueryMode mode,
+ const Functor& functor,
+ const BoundArgsTuple& bound_args,
+ std::index_sequence<indices...>) {
+ switch (mode) {
+ case BindStateBase::IS_CANCELLED:
+ return CallbackCancellationTraits<Functor, BoundArgsTuple>::IsCancelled(
+ functor, std::get<indices>(bound_args)...);
+ case BindStateBase::MAYBE_VALID:
+ return CallbackCancellationTraits<Functor, BoundArgsTuple>::MaybeValid(
+ functor, std::get<indices>(bound_args)...);
+ }
+ NOTREACHED();
+}
+
+// Relays |base| to corresponding CallbackCancellationTraits<>::Run(). Returns
+// true if the callback |base| represents is canceled.
+template <typename BindStateType>
+bool QueryCancellationTraits(const BindStateBase* base,
+ BindStateBase::CancellationQueryMode mode) {
+ const BindStateType* storage = static_cast<const BindStateType*>(base);
+ static constexpr size_t num_bound_args =
+ std::tuple_size<decltype(storage->bound_args_)>::value;
+ return QueryCancellationTraitsImpl(
+ mode, storage->functor_, storage->bound_args_,
+ std::make_index_sequence<num_bound_args>());
+}
+
+// The base case of BanUnconstructedRefCountedReceiver that checks nothing.
+template <typename Functor, typename Receiver, typename... Unused>
+std::enable_if_t<
+ !(MakeFunctorTraits<Functor>::is_method &&
+ std::is_pointer<std::decay_t<Receiver>>::value &&
+ IsRefCountedType<std::remove_pointer_t<std::decay_t<Receiver>>>::value)>
+BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {}
+
+template <typename Functor>
+void BanUnconstructedRefCountedReceiver() {}
+
+// Asserts that Callback is not the first owner of a ref-counted receiver.
+template <typename Functor, typename Receiver, typename... Unused>
+std::enable_if_t<
+ MakeFunctorTraits<Functor>::is_method &&
+ std::is_pointer<std::decay_t<Receiver>>::value &&
+ IsRefCountedType<std::remove_pointer_t<std::decay_t<Receiver>>>::value>
+BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {
+ DCHECK(receiver);
+
+ // It's error prone to make the implicit first reference to ref-counted types.
+ // In the example below, base::BindOnce() makes the implicit first reference
+ // to the ref-counted Foo. If PostTask() failed or the posted task ran fast
+ // enough, the newly created instance can be destroyed before |oo| makes
+ // another reference.
+ // Foo::Foo() {
+ // base::PostTask(FROM_HERE, base::BindOnce(&Foo::Bar, this));
+ // }
+ //
+ // scoped_refptr<Foo> oo = new Foo();
+ //
+ // Instead of doing like above, please consider adding a static constructor,
+ // and keep the first reference alive explicitly.
+ // // static
+ // scoped_refptr<Foo> Foo::Create() {
+ // auto foo = base::WrapRefCounted(new Foo());
+ // base::PostTask(FROM_HERE, base::BindOnce(&Foo::Bar, foo));
+ // return foo;
+ // }
+ //
+ // Foo::Foo() {}
+ //
+ // scoped_refptr<Foo> oo = Foo::Create();
+ DCHECK(receiver->HasAtLeastOneRef())
+ << "base::Bind{Once,Repeating}() refuses to create the first reference "
+ "to ref-counted objects. That typically happens around PostTask() in "
+ "their constructor, and such objects can be destroyed before `new` "
+ "returns if the task resolves fast enough.";
+}
+
+// BindState<>
+//
+// This stores all the state passed into Bind().
+template <typename Functor, typename... BoundArgs>
+struct BindState final : BindStateBase {
+ using IsCancellable = std::integral_constant<
+ bool,
+ CallbackCancellationTraits<Functor,
+ std::tuple<BoundArgs...>>::is_cancellable>;
+
+ template <typename ForwardFunctor, typename... ForwardBoundArgs>
+ static BindState* Create(BindStateBase::InvokeFuncStorage invoke_func,
+ ForwardFunctor&& functor,
+ ForwardBoundArgs&&... bound_args) {
+ // Ban ref counted receivers that were not yet fully constructed to avoid
+ // a common pattern of racy situation.
+ BanUnconstructedRefCountedReceiver<ForwardFunctor>(bound_args...);
+
+ // IsCancellable is std::false_type if
+ // CallbackCancellationTraits<>::IsCancelled returns always false.
+ // Otherwise, it's std::true_type.
+ return new BindState(IsCancellable{}, invoke_func,
+ std::forward<ForwardFunctor>(functor),
+ std::forward<ForwardBoundArgs>(bound_args)...);
+ }
+
+ Functor functor_;
+ std::tuple<BoundArgs...> bound_args_;
+
+ private:
+ template <typename ForwardFunctor, typename... ForwardBoundArgs>
+ explicit BindState(std::true_type,
+ BindStateBase::InvokeFuncStorage invoke_func,
+ ForwardFunctor&& functor,
+ ForwardBoundArgs&&... bound_args)
+ : BindStateBase(invoke_func,
+ &Destroy,
+ &QueryCancellationTraits<BindState>),
+ functor_(std::forward<ForwardFunctor>(functor)),
+ bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
+ DCHECK(!IsNull(functor_));
+ }
+
+ template <typename ForwardFunctor, typename... ForwardBoundArgs>
+ explicit BindState(std::false_type,
+ BindStateBase::InvokeFuncStorage invoke_func,
+ ForwardFunctor&& functor,
+ ForwardBoundArgs&&... bound_args)
+ : BindStateBase(invoke_func, &Destroy),
+ functor_(std::forward<ForwardFunctor>(functor)),
+ bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
+ DCHECK(!IsNull(functor_));
+ }
+
+ ~BindState() = default;
+
+ static void Destroy(const BindStateBase* self) {
+ delete static_cast<const BindState*>(self);
+ }
+};
+
+// Used to implement MakeBindStateType.
+template <bool is_method, typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl;
+
+template <typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> {
+ static_assert(!HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>::value,
+ "A parameter is a refcounted type and needs scoped_refptr.");
+ using Type = BindState<std::decay_t<Functor>, std::decay_t<BoundArgs>...>;
+};
+
+template <typename Functor>
+struct MakeBindStateTypeImpl<true, Functor> {
+ using Type = BindState<std::decay_t<Functor>>;
+};
+
+template <typename Functor, typename Receiver, typename... BoundArgs>
+struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
+ private:
+ using DecayedReceiver = std::decay_t<Receiver>;
+
+ static_assert(!std::is_array<std::remove_reference_t<Receiver>>::value,
+ "First bound argument to a method cannot be an array.");
+ static_assert(
+ !std::is_pointer<DecayedReceiver>::value ||
+ IsRefCountedType<std::remove_pointer_t<DecayedReceiver>>::value,
+ "Receivers may not be raw pointers. If using a raw pointer here is safe"
+ " and has no lifetime concerns, use base::Unretained() and document why"
+ " it's safe.");
+ static_assert(!HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>::value,
+ "A parameter is a refcounted type and needs scoped_refptr.");
+
+ public:
+ using Type = BindState<
+ std::decay_t<Functor>,
+ std::conditional_t<std::is_pointer<DecayedReceiver>::value,
+ scoped_refptr<std::remove_pointer_t<DecayedReceiver>>,
+ DecayedReceiver>,
+ std::decay_t<BoundArgs>...>;
+};
+
+template <typename Functor, typename... BoundArgs>
+using MakeBindStateType =
+ typename MakeBindStateTypeImpl<MakeFunctorTraits<Functor>::is_method,
+ Functor,
+ BoundArgs...>::Type;
+
+} // namespace internal
+
+// An injection point to control |this| pointer behavior on a method invocation.
+// If IsWeakReceiver<> is true_type for |T| and |T| is used for a receiver of a
+// method, base::Bind cancels the method invocation if the receiver is tested as
+// false.
+// E.g. Foo::bar() is not called:
+// struct Foo : base::SupportsWeakPtr<Foo> {
+// void bar() {}
+// };
+//
+// WeakPtr<Foo> oo = nullptr;
+// base::BindOnce(&Foo::bar, oo).Run();
+template <typename T>
+struct IsWeakReceiver : std::false_type {};
+
+template <typename T>
+struct IsWeakReceiver<std::reference_wrapper<T>> : IsWeakReceiver<T> {};
+
+template <typename T>
+struct IsWeakReceiver<WeakPtr<T>> : std::true_type {};
+
+// An injection point to control how bound objects passed to the target
+// function. BindUnwrapTraits<>::Unwrap() is called for each bound objects right
+// before the target function is invoked.
+template <typename>
+struct BindUnwrapTraits {
+ template <typename T>
+ static T&& Unwrap(T&& o) {
+ return std::forward<T>(o);
+ }
+};
+
+template <typename T>
+struct BindUnwrapTraits<internal::UnretainedWrapper<T>> {
+ static T* Unwrap(const internal::UnretainedWrapper<T>& o) { return o.get(); }
+};
+
+template <typename T>
+struct BindUnwrapTraits<std::reference_wrapper<T>> {
+ static T& Unwrap(std::reference_wrapper<T> o) { return o.get(); }
+};
+
+template <typename T>
+struct BindUnwrapTraits<internal::RetainedRefWrapper<T>> {
+ static T* Unwrap(const internal::RetainedRefWrapper<T>& o) { return o.get(); }
+};
+
+template <typename T, typename Deleter>
+struct BindUnwrapTraits<internal::OwnedWrapper<T, Deleter>> {
+ static T* Unwrap(const internal::OwnedWrapper<T, Deleter>& o) {
+ return o.get();
+ }
+};
+
+template <typename T>
+struct BindUnwrapTraits<internal::PassedWrapper<T>> {
+ static T Unwrap(const internal::PassedWrapper<T>& o) { return o.Take(); }
+};
+
+#if defined(OS_WIN)
+template <typename T>
+struct BindUnwrapTraits<Microsoft::WRL::ComPtr<T>> {
+ static T* Unwrap(const Microsoft::WRL::ComPtr<T>& ptr) { return ptr.Get(); }
+};
+#endif
+
+// CallbackCancellationTraits allows customization of Callback's cancellation
+// semantics. By default, callbacks are not cancellable. A specialization should
+// set is_cancellable = true and implement an IsCancelled() that returns if the
+// callback should be cancelled.
+template <typename Functor, typename BoundArgsTuple, typename SFINAE>
+struct CallbackCancellationTraits {
+ static constexpr bool is_cancellable = false;
+};
+
+// Specialization for method bound to weak pointer receiver.
+template <typename Functor, typename... BoundArgs>
+struct CallbackCancellationTraits<
+ Functor,
+ std::tuple<BoundArgs...>,
+ std::enable_if_t<
+ internal::IsWeakMethod<internal::FunctorTraits<Functor>::is_method,
+ BoundArgs...>::value>> {
+ static constexpr bool is_cancellable = true;
+
+ template <typename Receiver, typename... Args>
+ static bool IsCancelled(const Functor&,
+ const Receiver& receiver,
+ const Args&...) {
+ return !receiver;
+ }
+
+ template <typename Receiver, typename... Args>
+ static bool MaybeValid(const Functor&,
+ const Receiver& receiver,
+ const Args&...) {
+ return receiver.MaybeValid();
+ }
+};
+
+// Specialization for a nested bind.
+template <typename Signature, typename... BoundArgs>
+struct CallbackCancellationTraits<OnceCallback<Signature>,
+ std::tuple<BoundArgs...>> {
+ static constexpr bool is_cancellable = true;
+
+ template <typename Functor>
+ static bool IsCancelled(const Functor& functor, const BoundArgs&...) {
+ return functor.IsCancelled();
+ }
+
+ template <typename Functor>
+ static bool MaybeValid(const Functor& functor, const BoundArgs&...) {
+ return functor.MaybeValid();
+ }
+};
+
+template <typename Signature, typename... BoundArgs>
+struct CallbackCancellationTraits<RepeatingCallback<Signature>,
+ std::tuple<BoundArgs...>> {
+ static constexpr bool is_cancellable = true;
+
+ template <typename Functor>
+ static bool IsCancelled(const Functor& functor, const BoundArgs&...) {
+ return functor.IsCancelled();
+ }
+
+ template <typename Functor>
+ static bool MaybeValid(const Functor& functor, const BoundArgs&...) {
+ return functor.MaybeValid();
+ }
+};
+
+// Returns a RunType of bound functor.
+// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C).
+template <typename Functor, typename... BoundArgs>
+using MakeUnboundRunType =
+ typename internal::BindTypeHelper<Functor, BoundArgs...>::UnboundRunType;
+
+} // namespace base
+
+#endif // BASE_BIND_INTERNAL_H_
diff --git a/security/sandbox/chromium/base/bit_cast.h b/security/sandbox/chromium/base/bit_cast.h
new file mode 100644
index 0000000000..90dd925e86
--- /dev/null
+++ b/security/sandbox/chromium/base/bit_cast.h
@@ -0,0 +1,77 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BIT_CAST_H_
+#define BASE_BIT_CAST_H_
+
+#include <string.h>
+#include <type_traits>
+
+#include "base/compiler_specific.h"
+#include "base/template_util.h"
+#include "build/build_config.h"
+
+// bit_cast<Dest,Source> is a template function that implements the equivalent
+// of "*reinterpret_cast<Dest*>(&source)". We need this in very low-level
+// functions like the protobuf library and fast math support.
+//
+// float f = 3.14159265358979;
+// int i = bit_cast<int32_t>(f);
+// // i = 0x40490fdb
+//
+// The classical address-casting method is:
+//
+// // WRONG
+// float f = 3.14159265358979; // WRONG
+// int i = * reinterpret_cast<int*>(&f); // WRONG
+//
+// The address-casting method actually produces undefined behavior according to
+// the ISO C++98 specification, section 3.10 ("basic.lval"), paragraph 15.
+// (This did not substantially change in C++11.) Roughly, this section says: if
+// an object in memory has one type, and a program accesses it with a different
+// type, then the result is undefined behavior for most values of "different
+// type".
+//
+// This is true for any cast syntax, either *(int*)&f or
+// *reinterpret_cast<int*>(&f). And it is particularly true for conversions
+// between integral lvalues and floating-point lvalues.
+//
+// The purpose of this paragraph is to allow optimizing compilers to assume that
+// expressions with different types refer to different memory. Compilers are
+// known to take advantage of this. So a non-conforming program quietly
+// produces wildly incorrect output.
+//
+// The problem is not the use of reinterpret_cast. The problem is type punning:
+// holding an object in memory of one type and reading its bits back using a
+// different type.
+//
+// The C++ standard is more subtle and complex than this, but that is the basic
+// idea.
+//
+// Anyways ...
+//
+// bit_cast<> calls memcpy() which is blessed by the standard, especially by the
+// example in section 3.9 . Also, of course, bit_cast<> wraps up the nasty
+// logic in one place.
+//
+// Fortunately memcpy() is very fast. In optimized mode, compilers replace
+// calls to memcpy() with inline object code when the size argument is a
+// compile-time constant. On a 32-bit system, memcpy(d,s,4) compiles to one
+// load and one store, and memcpy(d,s,8) compiles to two loads and two stores.
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+ static_assert(sizeof(Dest) == sizeof(Source),
+ "bit_cast requires source and destination to be the same size");
+ static_assert(base::is_trivially_copyable<Dest>::value,
+ "bit_cast requires the destination type to be copyable");
+ static_assert(base::is_trivially_copyable<Source>::value,
+ "bit_cast requires the source type to be copyable");
+
+ Dest dest;
+ memcpy(&dest, &source, sizeof(dest));
+ return dest;
+}
+
+#endif // BASE_BIT_CAST_H_
diff --git a/security/sandbox/chromium/base/bits.h b/security/sandbox/chromium/base/bits.h
new file mode 100644
index 0000000000..d2c5ac9caa
--- /dev/null
+++ b/security/sandbox/chromium/base/bits.h
@@ -0,0 +1,209 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines some bit utilities.
+
+#ifndef BASE_BITS_H_
+#define BASE_BITS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <type_traits>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#endif
+
+namespace base {
+namespace bits {
+
+// Returns true iff |value| is a power of 2.
+template <typename T,
+ typename = typename std::enable_if<std::is_integral<T>::value>>
+constexpr inline bool IsPowerOfTwo(T value) {
+ // From "Hacker's Delight": Section 2.1 Manipulating Rightmost Bits.
+ //
+ // Only positive integers with a single bit set are powers of two. If only one
+ // bit is set in x (e.g. 0b00000100000000) then |x-1| will have that bit set
+ // to zero and all bits to its right set to 1 (e.g. 0b00000011111111). Hence
+ // |x & (x-1)| is 0 iff x is a power of two.
+ return value > 0 && (value & (value - 1)) == 0;
+}
+
+// Round up |size| to a multiple of alignment, which must be a power of two.
+inline size_t Align(size_t size, size_t alignment) {
+ DCHECK(IsPowerOfTwo(alignment));
+ return (size + alignment - 1) & ~(alignment - 1);
+}
+
+// Round down |size| to a multiple of alignment, which must be a power of two.
+inline size_t AlignDown(size_t size, size_t alignment) {
+ DCHECK(IsPowerOfTwo(alignment));
+ return size & ~(alignment - 1);
+}
+
+// CountLeadingZeroBits(value) returns the number of zero bits following the
+// most significant 1 bit in |value| if |value| is non-zero, otherwise it
+// returns {sizeof(T) * 8}.
+// Example: 00100010 -> 2
+//
+// CountTrailingZeroBits(value) returns the number of zero bits preceding the
+// least significant 1 bit in |value| if |value| is non-zero, otherwise it
+// returns {sizeof(T) * 8}.
+// Example: 00100010 -> 1
+//
+// C does not have an operator to do this, but fortunately the various
+// compilers have built-ins that map to fast underlying processor instructions.
+#if defined(COMPILER_MSVC)
+
+template <typename T, unsigned bits = sizeof(T) * 8>
+ALWAYS_INLINE
+ typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
+ unsigned>::type
+ CountLeadingZeroBits(T x) {
+ static_assert(bits > 0, "invalid instantiation");
+ unsigned long index;
+ return LIKELY(_BitScanReverse(&index, static_cast<uint32_t>(x)))
+ ? (31 - index - (32 - bits))
+ : bits;
+}
+
+template <typename T, unsigned bits = sizeof(T) * 8>
+ALWAYS_INLINE
+ typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
+ unsigned>::type
+ CountLeadingZeroBits(T x) {
+ static_assert(bits > 0, "invalid instantiation");
+ unsigned long index;
+// MSVC only supplies _BitScanReverse64 when building for a 64-bit target.
+#if defined(ARCH_CPU_64_BITS)
+ return LIKELY(_BitScanReverse64(&index, static_cast<uint64_t>(x)))
+ ? (63 - index)
+ : 64;
+#else
+ uint32_t left = static_cast<uint32_t>(x >> 32);
+ if (LIKELY(_BitScanReverse(&index, left)))
+ return 31 - index;
+
+ uint32_t right = static_cast<uint32_t>(x);
+ if (LIKELY(_BitScanReverse(&index, right)))
+ return 63 - index;
+
+ return 64;
+#endif
+}
+
+template <typename T, unsigned bits = sizeof(T) * 8>
+ALWAYS_INLINE
+ typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
+ unsigned>::type
+ CountTrailingZeroBits(T x) {
+ static_assert(bits > 0, "invalid instantiation");
+ unsigned long index;
+ return LIKELY(_BitScanForward(&index, static_cast<uint32_t>(x))) ? index
+ : bits;
+}
+
+template <typename T, unsigned bits = sizeof(T) * 8>
+ALWAYS_INLINE
+ typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
+ unsigned>::type
+ CountTrailingZeroBits(T x) {
+ static_assert(bits > 0, "invalid instantiation");
+ unsigned long index;
+// MSVC only supplies _BitScanForward64 when building for a 64-bit target.
+#if defined(ARCH_CPU_64_BITS)
+ return LIKELY(_BitScanForward64(&index, static_cast<uint64_t>(x))) ? index
+ : 64;
+#else
+ uint32_t right = static_cast<uint32_t>(x);
+ if (LIKELY(_BitScanForward(&index, right)))
+ return index;
+
+ uint32_t left = static_cast<uint32_t>(x >> 32);
+ if (LIKELY(_BitScanForward(&index, left)))
+ return 32 + index;
+
+ return 64;
+#endif
+}
+
+ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
+ return CountLeadingZeroBits(x);
+}
+
+ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
+ return CountLeadingZeroBits(x);
+}
+
+#elif defined(COMPILER_GCC)
+
+// __builtin_clz has undefined behaviour for an input of 0, even though there's
+// clearly a return value that makes sense, and even though some processor clz
+// instructions have defined behaviour for 0. We could drop to raw __asm__ to
+// do better, but we'll avoid doing that unless we see proof that we need to.
+template <typename T, unsigned bits = sizeof(T) * 8>
+ALWAYS_INLINE
+ typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
+ unsigned>::type
+ CountLeadingZeroBits(T value) {
+ static_assert(bits > 0, "invalid instantiation");
+ return LIKELY(value)
+ ? bits == 64
+ ? __builtin_clzll(static_cast<uint64_t>(value))
+ : __builtin_clz(static_cast<uint32_t>(value)) - (32 - bits)
+ : bits;
+}
+
+template <typename T, unsigned bits = sizeof(T) * 8>
+ALWAYS_INLINE
+ typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
+ unsigned>::type
+ CountTrailingZeroBits(T value) {
+ return LIKELY(value) ? bits == 64
+ ? __builtin_ctzll(static_cast<uint64_t>(value))
+ : __builtin_ctz(static_cast<uint32_t>(value))
+ : bits;
+}
+
+ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
+ return CountLeadingZeroBits(x);
+}
+
+ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
+ return CountLeadingZeroBits(x);
+}
+
+#endif
+
+ALWAYS_INLINE size_t CountLeadingZeroBitsSizeT(size_t x) {
+ return CountLeadingZeroBits(x);
+}
+
+ALWAYS_INLINE size_t CountTrailingZeroBitsSizeT(size_t x) {
+ return CountTrailingZeroBits(x);
+}
+
+// Returns the integer i such as 2^i <= n < 2^(i+1)
+inline int Log2Floor(uint32_t n) {
+ return 31 - CountLeadingZeroBits(n);
+}
+
+// Returns the integer i such as 2^(i-1) < n <= 2^i
+inline int Log2Ceiling(uint32_t n) {
+ // When n == 0, we want the function to return -1.
+ // When n == 0, (n - 1) will underflow to 0xFFFFFFFF, which is
+ // why the statement below starts with (n ? 32 : -1).
+ return (n ? 32 : -1) - CountLeadingZeroBits(n - 1);
+}
+
+} // namespace bits
+} // namespace base
+
+#endif // BASE_BITS_H_
diff --git a/security/sandbox/chromium/base/callback.h b/security/sandbox/chromium/base/callback.h
new file mode 100644
index 0000000000..1427faaaea
--- /dev/null
+++ b/security/sandbox/chromium/base/callback.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// NOTE: Header files that do not require the full definition of
+// base::{Once,Repeating}Callback or base::{Once,Repeating}Closure should
+// #include "base/callback_forward.h" instead of this file.
+
+#ifndef BASE_CALLBACK_H_
+#define BASE_CALLBACK_H_
+
+#include <stddef.h>
+
+#include "base/callback_forward.h"
+#include "base/callback_internal.h"
+
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
+//
+// Overview:
+// A callback is similar in concept to a function pointer: it wraps a runnable
+// object such as a function, method, lambda, or even another callback, allowing
+// the runnable object to be invoked later via the callback object.
+//
+// Unlike function pointers, callbacks are created with base::BindOnce() or
+// base::BindRepeating() and support partial function application.
+//
+// A base::OnceCallback may be Run() at most once; a base::RepeatingCallback may
+// be Run() any number of times. |is_null()| is guaranteed to return true for a
+// moved-from callback.
+//
+// // The lambda takes two arguments, but the first argument |x| is bound at
+// // callback creation.
+// base::OnceCallback<int(int)> cb = base::BindOnce([] (int x, int y) {
+// return x + y;
+// }, 1);
+// // Run() only needs the remaining unbound argument |y|.
+// printf("1 + 2 = %d\n", std::move(cb).Run(2)); // Prints 3
+// printf("cb is null? %s\n",
+// cb.is_null() ? "true" : "false"); // Prints true
+// std::move(cb).Run(2); // Crashes since |cb| has already run.
+//
+// Callbacks also support cancellation. A common use is binding the receiver
+// object as a WeakPtr<T>. If that weak pointer is invalidated, calling Run()
+// will be a no-op. Note that |IsCancelled()| and |is_null()| are distinct:
+// simply cancelling a callback will not also make it null.
+//
+// base::Callback is currently a type alias for base::RepeatingCallback. In the
+// future, we expect to flip this to default to base::OnceCallback.
+//
+// See //docs/callback.md for the full documentation.
+
+namespace base {
+
+template <typename R, typename... Args>
+class OnceCallback<R(Args...)> : public internal::CallbackBase {
+ public:
+ using RunType = R(Args...);
+ using PolymorphicInvoke = R (*)(internal::BindStateBase*,
+ internal::PassingType<Args>...);
+
+ constexpr OnceCallback() = default;
+ OnceCallback(std::nullptr_t) = delete;
+
+ explicit OnceCallback(internal::BindStateBase* bind_state)
+ : internal::CallbackBase(bind_state) {}
+
+ OnceCallback(const OnceCallback&) = delete;
+ OnceCallback& operator=(const OnceCallback&) = delete;
+
+ OnceCallback(OnceCallback&&) noexcept = default;
+ OnceCallback& operator=(OnceCallback&&) noexcept = default;
+
+ OnceCallback(RepeatingCallback<RunType> other)
+ : internal::CallbackBase(std::move(other)) {}
+
+ OnceCallback& operator=(RepeatingCallback<RunType> other) {
+ static_cast<internal::CallbackBase&>(*this) = std::move(other);
+ return *this;
+ }
+
+ R Run(Args... args) const & {
+ static_assert(!sizeof(*this),
+ "OnceCallback::Run() may only be invoked on a non-const "
+ "rvalue, i.e. std::move(callback).Run().");
+ NOTREACHED();
+ }
+
+ R Run(Args... args) && {
+ // Move the callback instance into a local variable before the invocation,
+ // that ensures the internal state is cleared after the invocation.
+ // It's not safe to touch |this| after the invocation, since running the
+ // bound function may destroy |this|.
+ OnceCallback cb = std::move(*this);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
+ return f(cb.bind_state_.get(), std::forward<Args>(args)...);
+ }
+};
+
+template <typename R, typename... Args>
+class RepeatingCallback<R(Args...)> : public internal::CallbackBaseCopyable {
+ public:
+ using RunType = R(Args...);
+ using PolymorphicInvoke = R (*)(internal::BindStateBase*,
+ internal::PassingType<Args>...);
+
+ constexpr RepeatingCallback() = default;
+ RepeatingCallback(std::nullptr_t) = delete;
+
+ explicit RepeatingCallback(internal::BindStateBase* bind_state)
+ : internal::CallbackBaseCopyable(bind_state) {}
+
+ // Copyable and movable.
+ RepeatingCallback(const RepeatingCallback&) = default;
+ RepeatingCallback& operator=(const RepeatingCallback&) = default;
+ RepeatingCallback(RepeatingCallback&&) noexcept = default;
+ RepeatingCallback& operator=(RepeatingCallback&&) noexcept = default;
+
+ bool operator==(const RepeatingCallback& other) const {
+ return EqualsInternal(other);
+ }
+
+ bool operator!=(const RepeatingCallback& other) const {
+ return !operator==(other);
+ }
+
+ R Run(Args... args) const & {
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke());
+ return f(this->bind_state_.get(), std::forward<Args>(args)...);
+ }
+
+ R Run(Args... args) && {
+ // Move the callback instance into a local variable before the invocation,
+ // that ensures the internal state is cleared after the invocation.
+ // It's not safe to touch |this| after the invocation, since running the
+ // bound function may destroy |this|.
+ RepeatingCallback cb = std::move(*this);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
+ return f(std::move(cb).bind_state_.get(), std::forward<Args>(args)...);
+ }
+};
+
+} // namespace base
+
+#endif // BASE_CALLBACK_H_
diff --git a/security/sandbox/chromium/base/callback_forward.h b/security/sandbox/chromium/base/callback_forward.h
new file mode 100644
index 0000000000..d0f230cedb
--- /dev/null
+++ b/security/sandbox/chromium/base/callback_forward.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_FORWARD_H_
+#define BASE_CALLBACK_FORWARD_H_
+
+namespace base {
+
+template <typename Signature>
+class OnceCallback;
+
+template <typename Signature>
+class RepeatingCallback;
+
+template <typename Signature>
+using Callback = RepeatingCallback<Signature>;
+
+// Syntactic sugar to make OnceClosure<void()> and RepeatingClosure<void()>
+// easier to declare since they will be used in a lot of APIs with delayed
+// execution.
+using OnceClosure = OnceCallback<void()>;
+using RepeatingClosure = RepeatingCallback<void()>;
+using Closure = Callback<void()>;
+
+} // namespace base
+
+#endif // BASE_CALLBACK_FORWARD_H_
diff --git a/security/sandbox/chromium/base/callback_internal.cc b/security/sandbox/chromium/base/callback_internal.cc
new file mode 100644
index 0000000000..d710682e1f
--- /dev/null
+++ b/security/sandbox/chromium/base/callback_internal.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_internal.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+bool QueryCancellationTraitsForNonCancellables(
+ const BindStateBase*,
+ BindStateBase::CancellationQueryMode mode) {
+ switch (mode) {
+ case BindStateBase::IS_CANCELLED:
+ return false;
+ case BindStateBase::MAYBE_VALID:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace
+
+void BindStateBaseRefCountTraits::Destruct(const BindStateBase* bind_state) {
+ bind_state->destructor_(bind_state);
+}
+
+BindStateBase::BindStateBase(InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*))
+ : BindStateBase(polymorphic_invoke,
+ destructor,
+ &QueryCancellationTraitsForNonCancellables) {}
+
+BindStateBase::BindStateBase(
+ InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*),
+ bool (*query_cancellation_traits)(const BindStateBase*,
+ CancellationQueryMode))
+ : polymorphic_invoke_(polymorphic_invoke),
+ destructor_(destructor),
+ query_cancellation_traits_(query_cancellation_traits) {}
+
+CallbackBase& CallbackBase::operator=(CallbackBase&& c) noexcept = default;
+CallbackBase::CallbackBase(const CallbackBaseCopyable& c)
+ : bind_state_(c.bind_state_) {}
+
+CallbackBase& CallbackBase::operator=(const CallbackBaseCopyable& c) {
+ bind_state_ = c.bind_state_;
+ return *this;
+}
+
+CallbackBase::CallbackBase(CallbackBaseCopyable&& c) noexcept
+ : bind_state_(std::move(c.bind_state_)) {}
+
+CallbackBase& CallbackBase::operator=(CallbackBaseCopyable&& c) noexcept {
+ bind_state_ = std::move(c.bind_state_);
+ return *this;
+}
+
+void CallbackBase::Reset() {
+ // NULL the bind_state_ last, since it may be holding the last ref to whatever
+ // object owns us, and we may be deleted after that.
+ bind_state_ = nullptr;
+}
+
+bool CallbackBase::IsCancelled() const {
+ DCHECK(bind_state_);
+ return bind_state_->IsCancelled();
+}
+
+bool CallbackBase::MaybeValid() const {
+ DCHECK(bind_state_);
+ return bind_state_->MaybeValid();
+}
+
+bool CallbackBase::EqualsInternal(const CallbackBase& other) const {
+ return bind_state_ == other.bind_state_;
+}
+
+CallbackBase::~CallbackBase() = default;
+
+CallbackBaseCopyable::CallbackBaseCopyable(const CallbackBaseCopyable& c) {
+ bind_state_ = c.bind_state_;
+}
+
+CallbackBaseCopyable& CallbackBaseCopyable::operator=(
+ const CallbackBaseCopyable& c) {
+ bind_state_ = c.bind_state_;
+ return *this;
+}
+
+CallbackBaseCopyable& CallbackBaseCopyable::operator=(
+ CallbackBaseCopyable&& c) noexcept = default;
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/callback_internal.h b/security/sandbox/chromium/base/callback_internal.h
new file mode 100644
index 0000000000..fdfdf7f817
--- /dev/null
+++ b/security/sandbox/chromium/base/callback_internal.h
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains utility functions and classes that help the
+// implementation, and management of the Callback objects.
+
+#ifndef BASE_CALLBACK_INTERNAL_H_
+#define BASE_CALLBACK_INTERNAL_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+struct FakeBindState;
+
+namespace internal {
+
+class BindStateBase;
+class FinallyExecutorCommon;
+class ThenAndCatchExecutorCommon;
+
+template <typename ReturnType>
+class PostTaskExecutor;
+
+template <typename Functor, typename... BoundArgs>
+struct BindState;
+
+class CallbackBase;
+class CallbackBaseCopyable;
+
+struct BindStateBaseRefCountTraits {
+ static void Destruct(const BindStateBase*);
+};
+
+template <typename T>
+using PassingType = std::conditional_t<std::is_scalar<T>::value, T, T&&>;
+
+// BindStateBase is used to provide an opaque handle that the Callback
+// class can use to represent a function object with bound arguments. It
+// behaves as an existential type that is used by a corresponding
+// DoInvoke function to perform the function execution. This allows
+// us to shield the Callback class from the types of the bound argument via
+// "type erasure."
+// At the base level, the only task is to add reference counting data. Avoid
+// using or inheriting any virtual functions. Creating a vtable for every
+// BindState template instantiation results in a lot of bloat. Its only task is
+// to call the destructor which can be done with a function pointer.
+class BASE_EXPORT BindStateBase
+ : public RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits> {
+ public:
+ REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
+
+ enum CancellationQueryMode {
+ IS_CANCELLED,
+ MAYBE_VALID,
+ };
+
+ using InvokeFuncStorage = void(*)();
+
+ private:
+ BindStateBase(InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*));
+ BindStateBase(InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*),
+ bool (*query_cancellation_traits)(const BindStateBase*,
+ CancellationQueryMode mode));
+
+ ~BindStateBase() = default;
+
+ friend struct BindStateBaseRefCountTraits;
+ friend class RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits>;
+
+ friend class CallbackBase;
+ friend class CallbackBaseCopyable;
+
+ // Whitelist subclasses that access the destructor of BindStateBase.
+ template <typename Functor, typename... BoundArgs>
+ friend struct BindState;
+ friend struct ::base::FakeBindState;
+
+ bool IsCancelled() const {
+ return query_cancellation_traits_(this, IS_CANCELLED);
+ }
+
+ bool MaybeValid() const {
+ return query_cancellation_traits_(this, MAYBE_VALID);
+ }
+
+ // In C++, it is safe to cast function pointers to function pointers of
+ // another type. It is not okay to use void*. We create a InvokeFuncStorage
+ // that that can store our function pointer, and then cast it back to
+ // the original type on usage.
+ InvokeFuncStorage polymorphic_invoke_;
+
+ // Pointer to a function that will properly destroy |this|.
+ void (*destructor_)(const BindStateBase*);
+ bool (*query_cancellation_traits_)(const BindStateBase*,
+ CancellationQueryMode mode);
+
+ DISALLOW_COPY_AND_ASSIGN(BindStateBase);
+};
+
+// Holds the Callback methods that don't require specialization to reduce
+// template bloat.
+// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
+// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
+class BASE_EXPORT CallbackBase {
+ public:
+ inline CallbackBase(CallbackBase&& c) noexcept;
+ CallbackBase& operator=(CallbackBase&& c) noexcept;
+
+ explicit CallbackBase(const CallbackBaseCopyable& c);
+ CallbackBase& operator=(const CallbackBaseCopyable& c);
+
+ explicit CallbackBase(CallbackBaseCopyable&& c) noexcept;
+ CallbackBase& operator=(CallbackBaseCopyable&& c) noexcept;
+
+ // Returns true if Callback is null (doesn't refer to anything).
+ bool is_null() const { return !bind_state_; }
+ explicit operator bool() const { return !is_null(); }
+
+ // Returns true if the callback invocation will be nop due to an cancellation.
+ // It's invalid to call this on uninitialized callback.
+ //
+ // Must be called on the Callback's destination sequence.
+ bool IsCancelled() const;
+
+ // If this returns false, the callback invocation will be a nop due to a
+ // cancellation. This may(!) still return true, even on a cancelled callback.
+ //
+ // This function is thread-safe.
+ bool MaybeValid() const;
+
+ // Returns the Callback into an uninitialized state.
+ void Reset();
+
+ protected:
+ friend class FinallyExecutorCommon;
+ friend class ThenAndCatchExecutorCommon;
+
+ template <typename ReturnType>
+ friend class PostTaskExecutor;
+
+ using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
+
+ // Returns true if this callback equals |other|. |other| may be null.
+ bool EqualsInternal(const CallbackBase& other) const;
+
+ constexpr inline CallbackBase();
+
+ // Allow initializing of |bind_state_| via the constructor to avoid default
+ // initialization of the scoped_refptr.
+ explicit inline CallbackBase(BindStateBase* bind_state);
+
+ InvokeFuncStorage polymorphic_invoke() const {
+ return bind_state_->polymorphic_invoke_;
+ }
+
+ // Force the destructor to be instantiated inside this translation unit so
+ // that our subclasses will not get inlined versions. Avoids more template
+ // bloat.
+ ~CallbackBase();
+
+ scoped_refptr<BindStateBase> bind_state_;
+};
+
+constexpr CallbackBase::CallbackBase() = default;
+CallbackBase::CallbackBase(CallbackBase&&) noexcept = default;
+CallbackBase::CallbackBase(BindStateBase* bind_state)
+ : bind_state_(AdoptRef(bind_state)) {}
+
+// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
+class BASE_EXPORT CallbackBaseCopyable : public CallbackBase {
+ public:
+ CallbackBaseCopyable(const CallbackBaseCopyable& c);
+ CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept = default;
+ CallbackBaseCopyable& operator=(const CallbackBaseCopyable& c);
+ CallbackBaseCopyable& operator=(CallbackBaseCopyable&& c) noexcept;
+
+ protected:
+ constexpr CallbackBaseCopyable() = default;
+ explicit CallbackBaseCopyable(BindStateBase* bind_state)
+ : CallbackBase(bind_state) {}
+ ~CallbackBaseCopyable() = default;
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_CALLBACK_INTERNAL_H_
diff --git a/security/sandbox/chromium/base/compiler_specific.h b/security/sandbox/chromium/base/compiler_specific.h
new file mode 100644
index 0000000000..5f931c8704
--- /dev/null
+++ b/security/sandbox/chromium/base/compiler_specific.h
@@ -0,0 +1,298 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_COMPILER_SPECIFIC_H_
+#define BASE_COMPILER_SPECIFIC_H_
+
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+
+#if !defined(__clang__)
+#error "Only clang-cl is supported on Windows, see https://crbug.com/988071"
+#endif
+
+// Macros for suppressing and disabling warnings on MSVC.
+//
+// Warning numbers are enumerated at:
+// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx
+//
+// The warning pragma:
+// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx
+//
+// Using __pragma instead of #pragma inside macros:
+// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
+
+// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
+// The warning remains disabled until popped by MSVC_POP_WARNING.
+#define MSVC_PUSH_DISABLE_WARNING(n) \
+ __pragma(warning(push)) __pragma(warning(disable : n))
+
+// Pop effects of innermost MSVC_PUSH_* macro.
+#define MSVC_POP_WARNING() __pragma(warning(pop))
+
+#else // Not MSVC
+
+#define MSVC_PUSH_DISABLE_WARNING(n)
+#define MSVC_POP_WARNING()
+#define MSVC_DISABLE_OPTIMIZE()
+#define MSVC_ENABLE_OPTIMIZE()
+
+#endif // COMPILER_MSVC
+
+// These macros can be helpful when investigating compiler bugs or when
+// investigating issues in local optimized builds, by temporarily disabling
+// optimizations for a single function or file. These macros should never be
+// used to permanently work around compiler bugs or other mysteries, and should
+// not be used in landed changes.
+#if !defined(OFFICIAL_BUILD)
+#if defined(__clang__)
+#define DISABLE_OPTIMIZE() __pragma(clang optimize off)
+#define ENABLE_OPTIMIZE() __pragma(clang optimize on)
+#elif defined(COMPILER_MSVC)
+#define DISABLE_OPTIMIZE() __pragma(optimize("", off))
+#define ENABLE_OPTIMIZE() __pragma(optimize("", on))
+#else
+// These macros are not currently available for other compiler options.
+#endif
+// These macros are not available in official builds.
+#endif // !defined(OFFICIAL_BUILD)
+
+// Annotate a variable indicating it's ok if the variable is not used.
+// (Typically used to silence a compiler warning when the assignment
+// is important for some other reason.)
+// Use like:
+// int x = ...;
+// ALLOW_UNUSED_LOCAL(x);
+#define ALLOW_UNUSED_LOCAL(x) (void)x
+
+// Annotate a typedef or function indicating it's ok if it's not used.
+// Use like:
+// typedef Foo Bar ALLOW_UNUSED_TYPE;
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define ALLOW_UNUSED_TYPE __attribute__((unused))
+#else
+#define ALLOW_UNUSED_TYPE
+#endif
+
+// Annotate a function indicating it should not be inlined.
+// Use like:
+// NOINLINE void DoStuff() { ... }
+#if defined(COMPILER_GCC)
+#define NOINLINE __attribute__((noinline))
+#elif defined(COMPILER_MSVC)
+#define NOINLINE __declspec(noinline)
+#else
+#define NOINLINE
+#endif
+
+#if defined(COMPILER_GCC) && defined(NDEBUG)
+#define ALWAYS_INLINE inline __attribute__((__always_inline__))
+#elif defined(COMPILER_MSVC) && defined(NDEBUG)
+#define ALWAYS_INLINE __forceinline
+#else
+#define ALWAYS_INLINE inline
+#endif
+
+// Specify memory alignment for structs, classes, etc.
+// Use like:
+// class ALIGNAS(16) MyClass { ... }
+// ALIGNAS(16) int array[4];
+//
+// In most places you can use the C++11 keyword "alignas", which is preferred.
+//
+// But compilers have trouble mixing __attribute__((...)) syntax with
+// alignas(...) syntax.
+//
+// Doesn't work in clang or gcc:
+// struct alignas(16) __attribute__((packed)) S { char c; };
+// Works in clang but not gcc:
+// struct __attribute__((packed)) alignas(16) S2 { char c; };
+// Works in clang and gcc:
+// struct alignas(16) S3 { char c; } __attribute__((packed));
+//
+// There are also some attributes that must be specified *before* a class
+// definition: visibility (used for exporting functions/classes) is one of
+// these attributes. This means that it is not possible to use alignas() with a
+// class that is marked as exported.
+#if defined(COMPILER_MSVC)
+#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
+#elif defined(COMPILER_GCC)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#endif
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+// int foo() WARN_UNUSED_RESULT;
+// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
+#undef WARN_UNUSED_RESULT
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+
+// Tell the compiler a function is using a printf-style format string.
+// |format_param| is the one-based index of the format string parameter;
+// |dots_param| is the one-based index of the "..." parameter.
+// For v*printf functions (which take a va_list), pass 0 for dots_param.
+// (This is undocumented but matches what the system C headers do.)
+// For member functions, the implicit this parameter counts as index 1.
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define PRINTF_FORMAT(format_param, dots_param) \
+ __attribute__((format(printf, format_param, dots_param)))
+#else
+#define PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+// WPRINTF_FORMAT is the same, but for wide format strings.
+// This doesn't appear to yet be implemented in any compiler.
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
+#define WPRINTF_FORMAT(format_param, dots_param)
+// If available, it would look like:
+// __attribute__((format(wprintf, format_param, dots_param)))
+
+// Sanitizers annotations.
+#if defined(__has_attribute)
+#if __has_attribute(no_sanitize)
+#define NO_SANITIZE(what) __attribute__((no_sanitize(what)))
+#endif
+#endif
+#if !defined(NO_SANITIZE)
+#define NO_SANITIZE(what)
+#endif
+
+// MemorySanitizer annotations.
+#if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
+#include <sanitizer/msan_interface.h>
+
+// Mark a memory region fully initialized.
+// Use this to annotate code that deliberately reads uninitialized data, for
+// example a GC scavenging root set pointers from the stack.
+#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
+
+// Check a memory region for initializedness, as if it was being used here.
+// If any bits are uninitialized, crash with an MSan report.
+// Use this to sanitize data which MSan won't be able to track, e.g. before
+// passing data to another process via shared memory.
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
+ __msan_check_mem_is_initialized(p, size)
+#else // MEMORY_SANITIZER
+#define MSAN_UNPOISON(p, size)
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
+#endif // MEMORY_SANITIZER
+
+// DISABLE_CFI_PERF -- Disable Control Flow Integrity for perf reasons.
+#if !defined(DISABLE_CFI_PERF)
+#if defined(__clang__) && defined(OFFICIAL_BUILD)
+#define DISABLE_CFI_PERF __attribute__((no_sanitize("cfi")))
+#else
+#define DISABLE_CFI_PERF
+#endif
+#endif
+
+// Macro useful for writing cross-platform function pointers.
+#if !defined(CDECL)
+#if defined(OS_WIN)
+#define CDECL __cdecl
+#else // defined(OS_WIN)
+#define CDECL
+#endif // defined(OS_WIN)
+#endif // !defined(CDECL)
+
+// Macro for hinting that an expression is likely to be false.
+#if !defined(UNLIKELY)
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define UNLIKELY(x) (x)
+#endif // defined(COMPILER_GCC)
+#endif // !defined(UNLIKELY)
+
+#if !defined(LIKELY)
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define LIKELY(x) (x)
+#endif // defined(COMPILER_GCC)
+#endif // !defined(LIKELY)
+
+// Compiler feature-detection.
+// clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
+#if defined(__has_feature)
+#define HAS_FEATURE(FEATURE) __has_feature(FEATURE)
+#else
+#define HAS_FEATURE(FEATURE) 0
+#endif
+
+// Macro for telling -Wimplicit-fallthrough that a fallthrough is intentional.
+#if defined(__clang__)
+#define FALLTHROUGH [[clang::fallthrough]]
+#else
+#define FALLTHROUGH
+#endif
+
+#if defined(COMPILER_GCC)
+#define PRETTY_FUNCTION __PRETTY_FUNCTION__
+#elif defined(COMPILER_MSVC)
+#define PRETTY_FUNCTION __FUNCSIG__
+#else
+// See https://en.cppreference.com/w/c/language/function_definition#func
+#define PRETTY_FUNCTION __func__
+#endif
+
+#if !defined(CPU_ARM_NEON)
+#if defined(__arm__)
+#if !defined(__ARMEB__) && !defined(__ARM_EABI__) && !defined(__EABI__) && \
+ !defined(__VFP_FP__) && !defined(_WIN32_WCE) && !defined(ANDROID)
+#error Chromium does not support middle endian architecture
+#endif
+#if defined(__ARM_NEON__)
+#define CPU_ARM_NEON 1
+#endif
+#endif // defined(__arm__)
+#endif // !defined(CPU_ARM_NEON)
+
+#if !defined(HAVE_MIPS_MSA_INTRINSICS)
+#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
+#define HAVE_MIPS_MSA_INTRINSICS 1
+#endif
+#endif
+
+#if defined(__clang__) && __has_attribute(uninitialized)
+// Attribute "uninitialized" disables -ftrivial-auto-var-init=pattern for
+// the specified variable.
+// Library-wide alternative is
+// 'configs -= [ "//build/config/compiler:default_init_stack_vars" ]' in .gn
+// file.
+//
+// See "init_stack_vars" in build/config/compiler/BUILD.gn and
+// http://crbug.com/977230
+// "init_stack_vars" is enabled for non-official builds and we hope to enable it
+// in official build in 2020 as well. The flag writes fixed pattern into
+// uninitialized parts of all local variables. In rare cases such initialization
+// is undesirable and attribute can be used:
+// 1. Degraded performance
+// In most cases compiler is able to remove additional stores. E.g. if memory is
+// never accessed or properly initialized later. Preserved stores mostly will
+// not affect program performance. However if compiler failed on some
+// performance critical code we can get a visible regression in a benchmark.
+// 2. memset, memcpy calls
+// Compiler may replaces some memory writes with memset or memcpy calls. This is
+// not -ftrivial-auto-var-init specific, but it can happen more likely with the
+// flag. It can be a problem if code is not linked with C run-time library.
+//
+// Note: The flag is security risk mitigation feature. So in future the
+// attribute uses should be avoided when possible. However to enable this
+// mitigation on the most of the code we need to be less strict now and minimize
+// number of exceptions later. So if in doubt feel free to use attribute, but
+// please document the problem for someone who is going to cleanup it later.
+// E.g. platform, bot, benchmark or test name in patch description or next to
+// the attribute.
+#define STACK_UNINITIALIZED __attribute__((uninitialized))
+#else
+#define STACK_UNINITIALIZED
+#endif
+
+#endif // BASE_COMPILER_SPECIFIC_H_
diff --git a/security/sandbox/chromium/base/containers/adapters.h b/security/sandbox/chromium/base/containers/adapters.h
new file mode 100644
index 0000000000..ec33481752
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/adapters.h
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_ADAPTERS_H_
+#define BASE_CONTAINERS_ADAPTERS_H_
+
+#include <stddef.h>
+
+#include <iterator>
+#include <utility>
+
+#include "base/macros.h"
+
+namespace base {
+
+namespace internal {
+
+// Internal adapter class for implementing base::Reversed.
+template <typename T>
+class ReversedAdapter {
+ public:
+ using Iterator = decltype(std::rbegin(std::declval<T&>()));
+
+ explicit ReversedAdapter(T& t) : t_(t) {}
+ ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+ Iterator begin() const { return std::rbegin(t_); }
+ Iterator end() const { return std::rend(t_); }
+
+ private:
+ T& t_;
+
+ DISALLOW_ASSIGN(ReversedAdapter);
+};
+
+} // namespace internal
+
+// Reversed returns a container adapter usable in a range-based "for" statement
+// for iterating a reversible container in reverse order.
+//
+// Example:
+//
+// std::vector<int> v = ...;
+// for (int i : base::Reversed(v)) {
+// // iterates through v from back to front
+// }
+template <typename T>
+internal::ReversedAdapter<T> Reversed(T& t) {
+ return internal::ReversedAdapter<T>(t);
+}
+
+} // namespace base
+
+#endif // BASE_CONTAINERS_ADAPTERS_H_
diff --git a/security/sandbox/chromium/base/containers/buffer_iterator.h b/security/sandbox/chromium/base/containers/buffer_iterator.h
new file mode 100644
index 0000000000..a4fd670190
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/buffer_iterator.h
@@ -0,0 +1,145 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_BUFFER_ITERATOR_H_
+#define BASE_CONTAINERS_BUFFER_ITERATOR_H_
+
+#include <type_traits>
+
+#include "base/bit_cast.h"
+#include "base/containers/span.h"
+#include "base/numerics/checked_math.h"
+
+namespace base {
+
+// BufferIterator is a bounds-checked container utility to access variable-
+// length, heterogeneous structures contained within a buffer. If the data are
+// homogeneous, use base::span<> instead.
+//
+// After being created with a weakly-owned buffer, BufferIterator returns
+// pointers to structured data within the buffer. After each method call that
+// returns data in the buffer, the iterator position is advanced by the byte
+// size of the object (or span of objects) returned. If there are not enough
+// bytes remaining in the buffer to return the requested object(s), a nullptr
+// or empty span is returned.
+//
+// This class is similar to base::Pickle, which should be preferred for
+// serializing to disk. Pickle versions its header and does not support writing
+// structures, which are problematic for serialization due to struct padding and
+// version shear concerns.
+//
+// Example usage:
+//
+// std::vector<uint8_t> buffer(4096);
+// if (!ReadSomeData(&buffer, buffer.size())) {
+// LOG(ERROR) << "Failed to read data.";
+// return false;
+// }
+//
+// BufferIterator<uint8_t> iterator(buffer);
+// uint32_t* num_items = iterator.Object<uint32_t>();
+// if (!num_items) {
+// LOG(ERROR) << "No num_items field."
+// return false;
+// }
+//
+// base::span<const item_struct> items =
+// iterator.Span<item_struct>(*num_items);
+// if (items.size() != *num_items) {
+// LOG(ERROR) << "Not enough items.";
+// return false;
+// }
+//
+// // ... validate the objects in |items|.
+template <typename B>
+class BufferIterator {
+ public:
+ static_assert(std::is_same<std::remove_const_t<B>, char>::value ||
+ std::is_same<std::remove_const_t<B>, unsigned char>::value,
+ "Underlying buffer type must be char-type.");
+
+ BufferIterator() {}
+ BufferIterator(B* data, size_t size)
+ : BufferIterator(make_span(data, size)) {}
+ explicit BufferIterator(span<B> buffer)
+ : buffer_(buffer), remaining_(buffer) {}
+ ~BufferIterator() {}
+
+ // Returns a pointer to a mutable structure T in the buffer at the current
+ // position. On success, the iterator position is advanced by sizeof(T). If
+ // there are not sizeof(T) bytes remaining in the buffer, returns nullptr.
+ template <typename T,
+ typename =
+ typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
+ T* MutableObject() {
+ size_t size = sizeof(T);
+ size_t next_position;
+ if (!CheckAdd(position(), size).AssignIfValid(&next_position))
+ return nullptr;
+ if (next_position > total_size())
+ return nullptr;
+ T* t = bit_cast<T*>(remaining_.data());
+ remaining_ = remaining_.subspan(size);
+ return t;
+ }
+
+ // Returns a const pointer to an object of type T in the buffer at the current
+ // position.
+ template <typename T,
+ typename =
+ typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
+ const T* Object() {
+ return MutableObject<const T>();
+ }
+
+ // Returns a span of |count| T objects in the buffer at the current position.
+ // On success, the iterator position is advanced by |sizeof(T) * count|. If
+ // there are not enough bytes remaining in the buffer to fulfill the request,
+ // returns an empty span.
+ template <typename T,
+ typename =
+ typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
+ span<T> MutableSpan(size_t count) {
+ size_t size;
+ if (!CheckMul(sizeof(T), count).AssignIfValid(&size))
+ return span<T>();
+ size_t next_position;
+ if (!CheckAdd(position(), size).AssignIfValid(&next_position))
+ return span<T>();
+ if (next_position > total_size())
+ return span<T>();
+ auto result = span<T>(bit_cast<T*>(remaining_.data()), count);
+ remaining_ = remaining_.subspan(size);
+ return result;
+ }
+
+ // Returns a span to |count| const objects of type T in the buffer at the
+ // current position.
+ template <typename T,
+ typename =
+ typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
+ span<const T> Span(size_t count) {
+ return MutableSpan<const T>(count);
+ }
+
+ // Resets the iterator position to the absolute offset |to|.
+ void Seek(size_t to) { remaining_ = buffer_.subspan(to); }
+
+ // Returns the total size of the underlying buffer.
+ size_t total_size() { return buffer_.size(); }
+
+ // Returns the current position in the buffer.
+ size_t position() { return buffer_.size_bytes() - remaining_.size_bytes(); }
+
+ private:
+ // The original buffer that the iterator was constructed with.
+ const span<B> buffer_;
+ // A subspan of |buffer_| containing the remaining bytes to iterate over.
+ span<B> remaining_;
+ // Copy and assign allowed.
+};
+
+} // namespace base
+
+#endif // BASE_CONTAINERS_BUFFER_ITERATOR_H_
diff --git a/security/sandbox/chromium/base/containers/checked_iterators.h b/security/sandbox/chromium/base/containers/checked_iterators.h
new file mode 100644
index 0000000000..cdfd2909d4
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/checked_iterators.h
@@ -0,0 +1,205 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_CHECKED_ITERATORS_H_
+#define BASE_CONTAINERS_CHECKED_ITERATORS_H_
+
+#include <iterator>
+#include <memory>
+#include <type_traits>
+
+#include "base/containers/util.h"
+#include "base/logging.h"
+
+namespace base {
+
+template <typename T>
+class CheckedContiguousIterator {
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = std::remove_cv_t<T>;
+ using pointer = T*;
+ using reference = T&;
+ using iterator_category = std::random_access_iterator_tag;
+
+ // Required for converting constructor below.
+ template <typename U>
+ friend class CheckedContiguousIterator;
+
+ constexpr CheckedContiguousIterator() = default;
+ constexpr CheckedContiguousIterator(T* start, const T* end)
+ : CheckedContiguousIterator(start, start, end) {}
+ constexpr CheckedContiguousIterator(const T* start, T* current, const T* end)
+ : start_(start), current_(current), end_(end) {
+ CHECK_LE(start, current);
+ CHECK_LE(current, end);
+ }
+ constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) =
+ default;
+
+ // Converting constructor allowing conversions like CCI<T> to CCI<const T>,
+ // but disallowing CCI<const T> to CCI<T> or CCI<Derived> to CCI<Base>, which
+ // are unsafe. Furthermore, this is the same condition as used by the
+ // converting constructors of std::span<T> and std::unique_ptr<T[]>.
+ // See https://wg21.link/n4042 for details.
+ template <
+ typename U,
+ std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr>
+ constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other)
+ : start_(other.start_), current_(other.current_), end_(other.end_) {
+ // We explicitly don't delegate to the 3-argument constructor here. Its
+ // CHECKs would be redundant, since we expect |other| to maintain its own
+ // invariant. However, DCHECKs never hurt anybody. Presumably.
+ DCHECK_LE(other.start_, other.current_);
+ DCHECK_LE(other.current_, other.end_);
+ }
+
+ ~CheckedContiguousIterator() = default;
+
+ constexpr CheckedContiguousIterator& operator=(
+ const CheckedContiguousIterator& other) = default;
+
+ constexpr bool operator==(const CheckedContiguousIterator& other) const {
+ CheckComparable(other);
+ return current_ == other.current_;
+ }
+
+ constexpr bool operator!=(const CheckedContiguousIterator& other) const {
+ CheckComparable(other);
+ return current_ != other.current_;
+ }
+
+ constexpr bool operator<(const CheckedContiguousIterator& other) const {
+ CheckComparable(other);
+ return current_ < other.current_;
+ }
+
+ constexpr bool operator<=(const CheckedContiguousIterator& other) const {
+ CheckComparable(other);
+ return current_ <= other.current_;
+ }
+
+ constexpr bool operator>(const CheckedContiguousIterator& other) const {
+ CheckComparable(other);
+ return current_ > other.current_;
+ }
+
+ constexpr bool operator>=(const CheckedContiguousIterator& other) const {
+ CheckComparable(other);
+ return current_ >= other.current_;
+ }
+
+ constexpr CheckedContiguousIterator& operator++() {
+ CHECK_NE(current_, end_);
+ ++current_;
+ return *this;
+ }
+
+ constexpr CheckedContiguousIterator operator++(int) {
+ CheckedContiguousIterator old = *this;
+ ++*this;
+ return old;
+ }
+
+ constexpr CheckedContiguousIterator& operator--() {
+ CHECK_NE(current_, start_);
+ --current_;
+ return *this;
+ }
+
+ constexpr CheckedContiguousIterator operator--(int) {
+ CheckedContiguousIterator old = *this;
+ --*this;
+ return old;
+ }
+
+ constexpr CheckedContiguousIterator& operator+=(difference_type rhs) {
+ if (rhs > 0) {
+ CHECK_LE(rhs, end_ - current_);
+ } else {
+ CHECK_LE(-rhs, current_ - start_);
+ }
+ current_ += rhs;
+ return *this;
+ }
+
+ constexpr CheckedContiguousIterator operator+(difference_type rhs) const {
+ CheckedContiguousIterator it = *this;
+ it += rhs;
+ return it;
+ }
+
+ constexpr CheckedContiguousIterator& operator-=(difference_type rhs) {
+ if (rhs < 0) {
+ CHECK_LE(-rhs, end_ - current_);
+ } else {
+ CHECK_LE(rhs, current_ - start_);
+ }
+ current_ -= rhs;
+ return *this;
+ }
+
+ constexpr CheckedContiguousIterator operator-(difference_type rhs) const {
+ CheckedContiguousIterator it = *this;
+ it -= rhs;
+ return it;
+ }
+
+ constexpr friend difference_type operator-(
+ const CheckedContiguousIterator& lhs,
+ const CheckedContiguousIterator& rhs) {
+ CHECK_EQ(lhs.start_, rhs.start_);
+ CHECK_EQ(lhs.end_, rhs.end_);
+ return lhs.current_ - rhs.current_;
+ }
+
+ constexpr reference operator*() const {
+ CHECK_NE(current_, end_);
+ return *current_;
+ }
+
+ constexpr pointer operator->() const {
+ CHECK_NE(current_, end_);
+ return current_;
+ }
+
+ constexpr reference operator[](difference_type rhs) const {
+ CHECK_GE(rhs, 0);
+ CHECK_LT(rhs, end_ - current_);
+ return current_[rhs];
+ }
+
+ static bool IsRangeMoveSafe(const CheckedContiguousIterator& from_begin,
+ const CheckedContiguousIterator& from_end,
+ const CheckedContiguousIterator& to)
+ WARN_UNUSED_RESULT {
+ if (from_end < from_begin)
+ return false;
+ const auto from_begin_uintptr = get_uintptr(from_begin.current_);
+ const auto from_end_uintptr = get_uintptr(from_end.current_);
+ const auto to_begin_uintptr = get_uintptr(to.current_);
+ const auto to_end_uintptr =
+ get_uintptr((to + std::distance(from_begin, from_end)).current_);
+
+ return to_begin_uintptr >= from_end_uintptr ||
+ to_end_uintptr <= from_begin_uintptr;
+ }
+
+ private:
+ constexpr void CheckComparable(const CheckedContiguousIterator& other) const {
+ CHECK_EQ(start_, other.start_);
+ CHECK_EQ(end_, other.end_);
+ }
+
+ const T* start_ = nullptr;
+ T* current_ = nullptr;
+ const T* end_ = nullptr;
+};
+
+template <typename T>
+using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>;
+
+} // namespace base
+
+#endif // BASE_CONTAINERS_CHECKED_ITERATORS_H_
diff --git a/security/sandbox/chromium/base/containers/circular_deque.h b/security/sandbox/chromium/base/containers/circular_deque.h
new file mode 100644
index 0000000000..0d452b56be
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/circular_deque.h
@@ -0,0 +1,1112 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_CIRCULAR_DEQUE_H_
+#define BASE_CONTAINERS_CIRCULAR_DEQUE_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+
+#include "base/containers/vector_buffer.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/template_util.h"
+
+// base::circular_deque is similar to std::deque. Unlike std::deque, the
+// storage is provided in a flat circular buffer conceptually similar to a
+// vector. The beginning and end will wrap around as necessary so that
+// pushes and pops will be constant time as long as a capacity expansion is
+// not required.
+//
+// The API should be identical to std::deque with the following differences:
+//
+// - ITERATORS ARE NOT STABLE. Mutating the container will invalidate all
+// iterators.
+//
+// - Insertions may resize the vector and so are not constant time (std::deque
+// guarantees constant time for insertions at the ends).
+//
+// - Container-wide comparisons are not implemented. If you want to compare
+// two containers, use an algorithm so the expensive iteration is explicit.
+//
+// If you want a similar container with only a queue API, use base::queue in
+// base/containers/queue.h.
+//
+// Constructors:
+// circular_deque();
+// circular_deque(size_t count);
+// circular_deque(size_t count, const T& value);
+// circular_deque(InputIterator first, InputIterator last);
+// circular_deque(const circular_deque&);
+// circular_deque(circular_deque&&);
+// circular_deque(std::initializer_list<value_type>);
+//
+// Assignment functions:
+// circular_deque& operator=(const circular_deque&);
+// circular_deque& operator=(circular_deque&&);
+// circular_deque& operator=(std::initializer_list<T>);
+// void assign(size_t count, const T& value);
+// void assign(InputIterator first, InputIterator last);
+// void assign(std::initializer_list<T> value);
+//
+// Random accessors:
+// T& at(size_t);
+// const T& at(size_t) const;
+// T& operator[](size_t);
+// const T& operator[](size_t) const;
+//
+// End accessors:
+// T& front();
+// const T& front() const;
+// T& back();
+// const T& back() const;
+//
+// Iterator functions:
+// iterator begin();
+// const_iterator begin() const;
+// const_iterator cbegin() const;
+// iterator end();
+// const_iterator end() const;
+// const_iterator cend() const;
+// reverse_iterator rbegin();
+// const_reverse_iterator rbegin() const;
+// const_reverse_iterator crbegin() const;
+// reverse_iterator rend();
+// const_reverse_iterator rend() const;
+// const_reverse_iterator crend() const;
+//
+// Memory management:
+// void reserve(size_t); // SEE IMPLEMENTATION FOR SOME GOTCHAS.
+// size_t capacity() const;
+// void shrink_to_fit();
+//
+// Size management:
+// void clear();
+// bool empty() const;
+// size_t size() const;
+// void resize(size_t);
+// void resize(size_t count, const T& value);
+//
+// Positional insert and erase:
+// void insert(const_iterator pos, size_type count, const T& value);
+// void insert(const_iterator pos,
+// InputIterator first, InputIterator last);
+// iterator insert(const_iterator pos, const T& value);
+// iterator insert(const_iterator pos, T&& value);
+// iterator emplace(const_iterator pos, Args&&... args);
+// iterator erase(const_iterator pos);
+// iterator erase(const_iterator first, const_iterator last);
+//
+// End insert and erase:
+// void push_front(const T&);
+// void push_front(T&&);
+// void push_back(const T&);
+// void push_back(T&&);
+// T& emplace_front(Args&&...);
+// T& emplace_back(Args&&...);
+// void pop_front();
+// void pop_back();
+//
+// General:
+// void swap(circular_deque&);
+
+namespace base {
+
+template <class T>
+class circular_deque;
+
+namespace internal {
+
+// Start allocating nonempty buffers with this many entries. This is the
+// external capacity so the internal buffer will be one larger (= 4) which is
+// more even for the allocator. See the descriptions of internal vs. external
+// capacity on the comment above the buffer_ variable below.
+constexpr size_t kCircularBufferInitialCapacity = 3;
+
+template <typename T>
+class circular_deque_const_iterator {
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = T;
+ using pointer = const T*;
+ using reference = const T&;
+ using iterator_category = std::random_access_iterator_tag;
+
+ circular_deque_const_iterator() : parent_deque_(nullptr), index_(0) {
+#if DCHECK_IS_ON()
+ created_generation_ = 0;
+#endif // DCHECK_IS_ON()
+ }
+
+ // Dereferencing.
+ const T& operator*() const {
+ CheckUnstableUsage();
+ parent_deque_->CheckValidIndex(index_);
+ return parent_deque_->buffer_[index_];
+ }
+ const T* operator->() const {
+ CheckUnstableUsage();
+ parent_deque_->CheckValidIndex(index_);
+ return &parent_deque_->buffer_[index_];
+ }
+ const value_type& operator[](difference_type i) const { return *(*this + i); }
+
+ // Increment and decrement.
+ circular_deque_const_iterator& operator++() {
+ Increment();
+ return *this;
+ }
+ circular_deque_const_iterator operator++(int) {
+ circular_deque_const_iterator ret = *this;
+ Increment();
+ return ret;
+ }
+ circular_deque_const_iterator& operator--() {
+ Decrement();
+ return *this;
+ }
+ circular_deque_const_iterator operator--(int) {
+ circular_deque_const_iterator ret = *this;
+ Decrement();
+ return ret;
+ }
+
+ // Random access mutation.
+ friend circular_deque_const_iterator operator+(
+ const circular_deque_const_iterator& iter,
+ difference_type offset) {
+ circular_deque_const_iterator ret = iter;
+ ret.Add(offset);
+ return ret;
+ }
+ circular_deque_const_iterator& operator+=(difference_type offset) {
+ Add(offset);
+ return *this;
+ }
+ friend circular_deque_const_iterator operator-(
+ const circular_deque_const_iterator& iter,
+ difference_type offset) {
+ circular_deque_const_iterator ret = iter;
+ ret.Add(-offset);
+ return ret;
+ }
+ circular_deque_const_iterator& operator-=(difference_type offset) {
+ Add(-offset);
+ return *this;
+ }
+
+ friend std::ptrdiff_t operator-(const circular_deque_const_iterator& lhs,
+ const circular_deque_const_iterator& rhs) {
+ lhs.CheckComparable(rhs);
+ return lhs.OffsetFromBegin() - rhs.OffsetFromBegin();
+ }
+
+ // Comparisons.
+ friend bool operator==(const circular_deque_const_iterator& lhs,
+ const circular_deque_const_iterator& rhs) {
+ lhs.CheckComparable(rhs);
+ return lhs.index_ == rhs.index_;
+ }
+ friend bool operator!=(const circular_deque_const_iterator& lhs,
+ const circular_deque_const_iterator& rhs) {
+ return !(lhs == rhs);
+ }
+ friend bool operator<(const circular_deque_const_iterator& lhs,
+ const circular_deque_const_iterator& rhs) {
+ lhs.CheckComparable(rhs);
+ return lhs.OffsetFromBegin() < rhs.OffsetFromBegin();
+ }
+ friend bool operator<=(const circular_deque_const_iterator& lhs,
+ const circular_deque_const_iterator& rhs) {
+ return !(lhs > rhs);
+ }
+ friend bool operator>(const circular_deque_const_iterator& lhs,
+ const circular_deque_const_iterator& rhs) {
+ lhs.CheckComparable(rhs);
+ return lhs.OffsetFromBegin() > rhs.OffsetFromBegin();
+ }
+ friend bool operator>=(const circular_deque_const_iterator& lhs,
+ const circular_deque_const_iterator& rhs) {
+ return !(lhs < rhs);
+ }
+
+ protected:
+ friend class circular_deque<T>;
+
+ circular_deque_const_iterator(const circular_deque<T>* parent, size_t index)
+ : parent_deque_(parent), index_(index) {
+#if DCHECK_IS_ON()
+ created_generation_ = parent->generation_;
+#endif // DCHECK_IS_ON()
+ }
+
+ // Returns the offset from the beginning index of the buffer to the current
+ // item.
+ size_t OffsetFromBegin() const {
+ if (index_ >= parent_deque_->begin_)
+ return index_ - parent_deque_->begin_; // On the same side as begin.
+ return parent_deque_->buffer_.capacity() - parent_deque_->begin_ + index_;
+ }
+
+ // Most uses will be ++ and -- so use a simplified implementation.
+ void Increment() {
+ CheckUnstableUsage();
+ parent_deque_->CheckValidIndex(index_);
+ index_++;
+ if (index_ == parent_deque_->buffer_.capacity())
+ index_ = 0;
+ }
+ void Decrement() {
+ CheckUnstableUsage();
+ parent_deque_->CheckValidIndexOrEnd(index_);
+ if (index_ == 0)
+ index_ = parent_deque_->buffer_.capacity() - 1;
+ else
+ index_--;
+ }
+ void Add(difference_type delta) {
+ CheckUnstableUsage();
+#if DCHECK_IS_ON()
+ if (delta <= 0)
+ parent_deque_->CheckValidIndexOrEnd(index_);
+ else
+ parent_deque_->CheckValidIndex(index_);
+#endif
+ // It should be valid to add 0 to any iterator, even if the container is
+ // empty and the iterator points to end(). The modulo below will divide
+ // by 0 if the buffer capacity is empty, so it's important to check for
+ // this case explicitly.
+ if (delta == 0)
+ return;
+
+ difference_type new_offset = OffsetFromBegin() + delta;
+ DCHECK(new_offset >= 0 &&
+ new_offset <= static_cast<difference_type>(parent_deque_->size()));
+ index_ = (new_offset + parent_deque_->begin_) %
+ parent_deque_->buffer_.capacity();
+ }
+
+#if DCHECK_IS_ON()
+ void CheckUnstableUsage() const {
+ DCHECK(parent_deque_);
+ // Since circular_deque doesn't guarantee stability, any attempt to
+ // dereference this iterator after a mutation (i.e. the generation doesn't
+ // match the original) in the container is illegal.
+ DCHECK_EQ(created_generation_, parent_deque_->generation_)
+ << "circular_deque iterator dereferenced after mutation.";
+ }
+ void CheckComparable(const circular_deque_const_iterator& other) const {
+ DCHECK_EQ(parent_deque_, other.parent_deque_);
+ // Since circular_deque doesn't guarantee stability, two iterators that
+ // are compared must have been generated without mutating the container.
+ // If this fires, the container was mutated between generating the two
+ // iterators being compared.
+ DCHECK_EQ(created_generation_, other.created_generation_);
+ }
+#else
+ inline void CheckUnstableUsage() const {}
+ inline void CheckComparable(const circular_deque_const_iterator&) const {}
+#endif // DCHECK_IS_ON()
+
+ const circular_deque<T>* parent_deque_;
+ size_t index_;
+
+#if DCHECK_IS_ON()
+ // The generation of the parent deque when this iterator was created. The
+ // container will update the generation for every modification so we can
+ // test if the container was modified by comparing them.
+ uint64_t created_generation_;
+#endif // DCHECK_IS_ON()
+};
+
+template <typename T>
+class circular_deque_iterator : public circular_deque_const_iterator<T> {
+ using base = circular_deque_const_iterator<T>;
+
+ public:
+ friend class circular_deque<T>;
+
+ using difference_type = std::ptrdiff_t;
+ using value_type = T;
+ using pointer = T*;
+ using reference = T&;
+ using iterator_category = std::random_access_iterator_tag;
+
+ // Expose the base class' constructor.
+ circular_deque_iterator() : circular_deque_const_iterator<T>() {}
+
+ // Dereferencing.
+ T& operator*() const { return const_cast<T&>(base::operator*()); }
+ T* operator->() const { return const_cast<T*>(base::operator->()); }
+ T& operator[](difference_type i) {
+ return const_cast<T&>(base::operator[](i));
+ }
+
+ // Random access mutation.
+ friend circular_deque_iterator operator+(const circular_deque_iterator& iter,
+ difference_type offset) {
+ circular_deque_iterator ret = iter;
+ ret.Add(offset);
+ return ret;
+ }
+ circular_deque_iterator& operator+=(difference_type offset) {
+ base::Add(offset);
+ return *this;
+ }
+ friend circular_deque_iterator operator-(const circular_deque_iterator& iter,
+ difference_type offset) {
+ circular_deque_iterator ret = iter;
+ ret.Add(-offset);
+ return ret;
+ }
+ circular_deque_iterator& operator-=(difference_type offset) {
+ base::Add(-offset);
+ return *this;
+ }
+
+ // Increment and decrement.
+ circular_deque_iterator& operator++() {
+ base::Increment();
+ return *this;
+ }
+ circular_deque_iterator operator++(int) {
+ circular_deque_iterator ret = *this;
+ base::Increment();
+ return ret;
+ }
+ circular_deque_iterator& operator--() {
+ base::Decrement();
+ return *this;
+ }
+ circular_deque_iterator operator--(int) {
+ circular_deque_iterator ret = *this;
+ base::Decrement();
+ return ret;
+ }
+
+ private:
+ circular_deque_iterator(const circular_deque<T>* parent, size_t index)
+ : circular_deque_const_iterator<T>(parent, index) {}
+};
+
+} // namespace internal
+
+template <typename T>
+class circular_deque {
+ private:
+ using VectorBuffer = internal::VectorBuffer<T>;
+
+ public:
+ using value_type = T;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+
+ using iterator = internal::circular_deque_iterator<T>;
+ using const_iterator = internal::circular_deque_const_iterator<T>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // ---------------------------------------------------------------------------
+ // Constructor
+
+ constexpr circular_deque() = default;
+
+ // Constructs with |count| copies of |value| or default constructed version.
+ circular_deque(size_type count) { resize(count); }
+ circular_deque(size_type count, const T& value) { resize(count, value); }
+
+ // Range constructor.
+ template <class InputIterator>
+ circular_deque(InputIterator first, InputIterator last) {
+ assign(first, last);
+ }
+
+ // Copy/move.
+ circular_deque(const circular_deque& other) : buffer_(other.size() + 1) {
+ assign(other.begin(), other.end());
+ }
+ circular_deque(circular_deque&& other) noexcept
+ : buffer_(std::move(other.buffer_)),
+ begin_(other.begin_),
+ end_(other.end_) {
+ other.begin_ = 0;
+ other.end_ = 0;
+ }
+
+ circular_deque(std::initializer_list<value_type> init) { assign(init); }
+
+ ~circular_deque() { DestructRange(begin_, end_); }
+
+ // ---------------------------------------------------------------------------
+ // Assignments.
+ //
+ // All of these may invalidate iterators and references.
+
+ circular_deque& operator=(const circular_deque& other) {
+ if (&other == this)
+ return *this;
+
+ reserve(other.size());
+ assign(other.begin(), other.end());
+ return *this;
+ }
+ circular_deque& operator=(circular_deque&& other) noexcept {
+ if (&other == this)
+ return *this;
+
+ // We're about to overwrite the buffer, so don't free it in clear to
+ // avoid doing it twice.
+ ClearRetainCapacity();
+ buffer_ = std::move(other.buffer_);
+ begin_ = other.begin_;
+ end_ = other.end_;
+
+ other.begin_ = 0;
+ other.end_ = 0;
+
+ IncrementGeneration();
+ return *this;
+ }
+ circular_deque& operator=(std::initializer_list<value_type> ilist) {
+ reserve(ilist.size());
+ assign(std::begin(ilist), std::end(ilist));
+ return *this;
+ }
+
+ void assign(size_type count, const value_type& value) {
+ ClearRetainCapacity();
+ reserve(count);
+ for (size_t i = 0; i < count; i++)
+ emplace_back(value);
+ IncrementGeneration();
+ }
+
+ // This variant should be enabled only when InputIterator is an iterator.
+ template <typename InputIterator>
+ typename std::enable_if<::base::internal::is_iterator<InputIterator>::value,
+ void>::type
+ assign(InputIterator first, InputIterator last) {
+ // Possible future enhancement, dispatch on iterator tag type. For forward
+ // iterators we can use std::difference to preallocate the space required
+ // and only do one copy.
+ ClearRetainCapacity();
+ for (; first != last; ++first)
+ emplace_back(*first);
+ IncrementGeneration();
+ }
+
+ void assign(std::initializer_list<value_type> value) {
+ reserve(std::distance(value.begin(), value.end()));
+ assign(value.begin(), value.end());
+ }
+
+ // ---------------------------------------------------------------------------
+ // Accessors.
+ //
+ // Since this class assumes no exceptions, at() and operator[] are equivalent.
+
+ const value_type& at(size_type i) const {
+ DCHECK(i < size());
+ size_t right_size = buffer_.capacity() - begin_;
+ if (begin_ <= end_ || i < right_size)
+ return buffer_[begin_ + i];
+ return buffer_[i - right_size];
+ }
+ value_type& at(size_type i) {
+ return const_cast<value_type&>(as_const(*this).at(i));
+ }
+
+ value_type& operator[](size_type i) {
+ return const_cast<value_type&>(as_const(*this)[i]);
+ }
+
+ const value_type& operator[](size_type i) const { return at(i); }
+
+ value_type& front() {
+ DCHECK(!empty());
+ return buffer_[begin_];
+ }
+ const value_type& front() const {
+ DCHECK(!empty());
+ return buffer_[begin_];
+ }
+
+ value_type& back() {
+ DCHECK(!empty());
+ return *(--end());
+ }
+ const value_type& back() const {
+ DCHECK(!empty());
+ return *(--end());
+ }
+
+ // ---------------------------------------------------------------------------
+ // Iterators.
+
+ iterator begin() { return iterator(this, begin_); }
+ const_iterator begin() const { return const_iterator(this, begin_); }
+ const_iterator cbegin() const { return const_iterator(this, begin_); }
+
+ iterator end() { return iterator(this, end_); }
+ const_iterator end() const { return const_iterator(this, end_); }
+ const_iterator cend() const { return const_iterator(this, end_); }
+
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(end());
+ }
+ const_reverse_iterator crbegin() const { return rbegin(); }
+
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(begin());
+ }
+ const_reverse_iterator crend() const { return rend(); }
+
+ // ---------------------------------------------------------------------------
+ // Memory management.
+
+ // IMPORTANT NOTE ON reserve(...): This class implements auto-shrinking of
+ // the buffer when elements are deleted and there is "too much" wasted space.
+ // So if you call reserve() with a large size in anticipation of pushing many
+ // elements, but pop an element before the queue is full, the capacity you
+ // reserved may be lost.
+ //
+ // As a result, it's only worthwhile to call reserve() when you're adding
+ // many things at once with no intermediate operations.
+ void reserve(size_type new_capacity) {
+ if (new_capacity > capacity())
+ SetCapacityTo(new_capacity);
+ }
+
+ size_type capacity() const {
+ // One item is wasted to indicate end().
+ return buffer_.capacity() == 0 ? 0 : buffer_.capacity() - 1;
+ }
+
+ void shrink_to_fit() {
+ if (empty()) {
+ // Optimize empty case to really delete everything if there was
+ // something.
+ if (buffer_.capacity())
+ buffer_ = VectorBuffer();
+ } else {
+ SetCapacityTo(size());
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Size management.
+
+ // This will additionally reset the capacity() to 0.
+ void clear() {
+ // This can't resize(0) because that requires a default constructor to
+ // compile, which not all contained classes may implement.
+ ClearRetainCapacity();
+ buffer_ = VectorBuffer();
+ }
+
+ bool empty() const { return begin_ == end_; }
+
+ size_type size() const {
+ if (begin_ <= end_)
+ return end_ - begin_;
+ return buffer_.capacity() - begin_ + end_;
+ }
+
+ // When reducing size, the elements are deleted from the end. When expanding
+ // size, elements are added to the end with |value| or the default
+ // constructed version. Even when using resize(count) to shrink, a default
+ // constructor is required for the code to compile, even though it will not
+ // be called.
+ //
+ // There are two versions rather than using a default value to avoid
+ // creating a temporary when shrinking (when it's not needed). Plus if
+ // the default constructor is desired when expanding usually just calling it
+ // for each element is faster than making a default-constructed temporary and
+ // copying it.
+ void resize(size_type count) {
+ // SEE BELOW VERSION if you change this. The code is mostly the same.
+ if (count > size()) {
+ // This could be slighly more efficient but expanding a queue with
+ // identical elements is unusual and the extra computations of emplacing
+ // one-by-one will typically be small relative to calling the constructor
+ // for every item.
+ ExpandCapacityIfNecessary(count - size());
+ while (size() < count)
+ emplace_back();
+ } else if (count < size()) {
+ size_t new_end = (begin_ + count) % buffer_.capacity();
+ DestructRange(new_end, end_);
+ end_ = new_end;
+
+ ShrinkCapacityIfNecessary();
+ }
+ IncrementGeneration();
+ }
+ void resize(size_type count, const value_type& value) {
+ // SEE ABOVE VERSION if you change this. The code is mostly the same.
+ if (count > size()) {
+ ExpandCapacityIfNecessary(count - size());
+ while (size() < count)
+ emplace_back(value);
+ } else if (count < size()) {
+ size_t new_end = (begin_ + count) % buffer_.capacity();
+ DestructRange(new_end, end_);
+ end_ = new_end;
+
+ ShrinkCapacityIfNecessary();
+ }
+ IncrementGeneration();
+ }
+
+ // ---------------------------------------------------------------------------
+ // Insert and erase.
+ //
+ // Insertion and deletion in the middle is O(n) and invalidates all existing
+ // iterators.
+ //
+ // The implementation of insert isn't optimized as much as it could be. If
+ // the insertion requires that the buffer be grown, it will first be grown
+ // and everything moved, and then the items will be inserted, potentially
+ // moving some items twice. This simplifies the implemntation substantially
+ // and means less generated templatized code. Since this is an uncommon
+ // operation for deques, and already relatively slow, it doesn't seem worth
+ // the benefit to optimize this.
+
+ void insert(const_iterator pos, size_type count, const T& value) {
+ ValidateIterator(pos);
+
+ // Optimize insert at the beginning.
+ if (pos == begin()) {
+ ExpandCapacityIfNecessary(count);
+ for (size_t i = 0; i < count; i++)
+ push_front(value);
+ return;
+ }
+
+ iterator insert_cur(this, pos.index_);
+ iterator insert_end;
+ MakeRoomFor(count, &insert_cur, &insert_end);
+ while (insert_cur < insert_end) {
+ new (&buffer_[insert_cur.index_]) T(value);
+ ++insert_cur;
+ }
+
+ IncrementGeneration();
+ }
+
+ // This enable_if keeps this call from getting confused with the (pos, count,
+ // value) version when value is an integer.
+ template <class InputIterator>
+ typename std::enable_if<::base::internal::is_iterator<InputIterator>::value,
+ void>::type
+ insert(const_iterator pos, InputIterator first, InputIterator last) {
+ ValidateIterator(pos);
+
+ size_t inserted_items = std::distance(first, last);
+ if (inserted_items == 0)
+ return; // Can divide by 0 when doing modulo below, so return early.
+
+ // Make a hole to copy the items into.
+ iterator insert_cur;
+ iterator insert_end;
+ if (pos == begin()) {
+ // Optimize insert at the beginning, nothing needs to be shifted and the
+ // hole is the |inserted_items| block immediately before |begin_|.
+ ExpandCapacityIfNecessary(inserted_items);
+ insert_end = begin();
+ begin_ =
+ (begin_ + buffer_.capacity() - inserted_items) % buffer_.capacity();
+ insert_cur = begin();
+ } else {
+ insert_cur = iterator(this, pos.index_);
+ MakeRoomFor(inserted_items, &insert_cur, &insert_end);
+ }
+
+ // Copy the items.
+ while (insert_cur < insert_end) {
+ new (&buffer_[insert_cur.index_]) T(*first);
+ ++insert_cur;
+ ++first;
+ }
+
+ IncrementGeneration();
+ }
+
+ // These all return an iterator to the inserted item. Existing iterators will
+ // be invalidated.
+ iterator insert(const_iterator pos, const T& value) {
+ return emplace(pos, value);
+ }
+ iterator insert(const_iterator pos, T&& value) {
+ return emplace(pos, std::move(value));
+ }
+ template <class... Args>
+ iterator emplace(const_iterator pos, Args&&... args) {
+ ValidateIterator(pos);
+
+ // Optimize insert at beginning which doesn't require shifting.
+ if (pos == cbegin()) {
+ emplace_front(std::forward<Args>(args)...);
+ return begin();
+ }
+
+ // Do this before we make the new iterators we return.
+ IncrementGeneration();
+
+ iterator insert_begin(this, pos.index_);
+ iterator insert_end;
+ MakeRoomFor(1, &insert_begin, &insert_end);
+ new (&buffer_[insert_begin.index_]) T(std::forward<Args>(args)...);
+
+ return insert_begin;
+ }
+
+ // Calling erase() won't automatically resize the buffer smaller like resize
+ // or the pop functions. Erase is slow and relatively uncommon, and for
+ // normal deque usage a pop will normally be done on a regular basis that
+ // will prevent excessive buffer usage over long periods of time. It's not
+ // worth having the extra code for every template instantiation of erase()
+ // to resize capacity downward to a new buffer.
+ iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
+ iterator erase(const_iterator first, const_iterator last) {
+ ValidateIterator(first);
+ ValidateIterator(last);
+
+ IncrementGeneration();
+
+ // First, call the destructor on the deleted items.
+ if (first.index_ == last.index_) {
+ // Nothing deleted. Need to return early to avoid falling through to
+ // moving items on top of themselves.
+ return iterator(this, first.index_);
+ } else if (first.index_ < last.index_) {
+ // Contiguous range.
+ buffer_.DestructRange(&buffer_[first.index_], &buffer_[last.index_]);
+ } else {
+ // Deleted range wraps around.
+ buffer_.DestructRange(&buffer_[first.index_],
+ &buffer_[buffer_.capacity()]);
+ buffer_.DestructRange(&buffer_[0], &buffer_[last.index_]);
+ }
+
+ if (first.index_ == begin_) {
+ // This deletion is from the beginning. Nothing needs to be copied, only
+ // begin_ needs to be updated.
+ begin_ = last.index_;
+ return iterator(this, last.index_);
+ }
+
+ // In an erase operation, the shifted items all move logically to the left,
+ // so move them from left-to-right.
+ iterator move_src(this, last.index_);
+ iterator move_src_end = end();
+ iterator move_dest(this, first.index_);
+ for (; move_src < move_src_end; move_src++, move_dest++) {
+ buffer_.MoveRange(&buffer_[move_src.index_],
+ &buffer_[move_src.index_ + 1],
+ &buffer_[move_dest.index_]);
+ }
+
+ end_ = move_dest.index_;
+
+ // Since we did not reallocate and only changed things after the erase
+ // element(s), the input iterator's index points to the thing following the
+ // deletion.
+ return iterator(this, first.index_);
+ }
+
+ // ---------------------------------------------------------------------------
+ // Begin/end operations.
+
+ void push_front(const T& value) { emplace_front(value); }
+ void push_front(T&& value) { emplace_front(std::move(value)); }
+
+ void push_back(const T& value) { emplace_back(value); }
+ void push_back(T&& value) { emplace_back(std::move(value)); }
+
+ template <class... Args>
+ reference emplace_front(Args&&... args) {
+ ExpandCapacityIfNecessary(1);
+ if (begin_ == 0)
+ begin_ = buffer_.capacity() - 1;
+ else
+ begin_--;
+ IncrementGeneration();
+ new (&buffer_[begin_]) T(std::forward<Args>(args)...);
+ return front();
+ }
+
+ template <class... Args>
+ reference emplace_back(Args&&... args) {
+ ExpandCapacityIfNecessary(1);
+ new (&buffer_[end_]) T(std::forward<Args>(args)...);
+ if (end_ == buffer_.capacity() - 1)
+ end_ = 0;
+ else
+ end_++;
+ IncrementGeneration();
+ return back();
+ }
+
+ void pop_front() {
+ DCHECK(size());
+ buffer_.DestructRange(&buffer_[begin_], &buffer_[begin_ + 1]);
+ begin_++;
+ if (begin_ == buffer_.capacity())
+ begin_ = 0;
+
+ ShrinkCapacityIfNecessary();
+
+ // Technically popping will not invalidate any iterators since the
+ // underlying buffer will be stable. But in the future we may want to add a
+ // feature that resizes the buffer smaller if there is too much wasted
+ // space. This ensures we can make such a change safely.
+ IncrementGeneration();
+ }
+ void pop_back() {
+ DCHECK(size());
+ if (end_ == 0)
+ end_ = buffer_.capacity() - 1;
+ else
+ end_--;
+ buffer_.DestructRange(&buffer_[end_], &buffer_[end_ + 1]);
+
+ ShrinkCapacityIfNecessary();
+
+ // See pop_front comment about why this is here.
+ IncrementGeneration();
+ }
+
+ // ---------------------------------------------------------------------------
+ // General operations.
+
+ void swap(circular_deque& other) {
+ std::swap(buffer_, other.buffer_);
+ std::swap(begin_, other.begin_);
+ std::swap(end_, other.end_);
+ IncrementGeneration();
+ }
+
+ friend void swap(circular_deque& lhs, circular_deque& rhs) { lhs.swap(rhs); }
+
+ private:
+ friend internal::circular_deque_iterator<T>;
+ friend internal::circular_deque_const_iterator<T>;
+
+ // Moves the items in the given circular buffer to the current one. The
+ // source is moved from so will become invalid. The destination buffer must
+ // have already been allocated with enough size.
+ static void MoveBuffer(VectorBuffer& from_buf,
+ size_t from_begin,
+ size_t from_end,
+ VectorBuffer* to_buf,
+ size_t* to_begin,
+ size_t* to_end) {
+ size_t from_capacity = from_buf.capacity();
+
+ *to_begin = 0;
+ if (from_begin < from_end) {
+ // Contiguous.
+ from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_end],
+ to_buf->begin());
+ *to_end = from_end - from_begin;
+ } else if (from_begin > from_end) {
+ // Discontiguous, copy the right side to the beginning of the new buffer.
+ from_buf.MoveRange(&from_buf[from_begin], &from_buf[from_capacity],
+ to_buf->begin());
+ size_t right_size = from_capacity - from_begin;
+ // Append the left side.
+ from_buf.MoveRange(&from_buf[0], &from_buf[from_end],
+ &(*to_buf)[right_size]);
+ *to_end = right_size + from_end;
+ } else {
+ // No items.
+ *to_end = 0;
+ }
+ }
+
+ // Expands the buffer size. This assumes the size is larger than the
+ // number of elements in the vector (it won't call delete on anything).
+ void SetCapacityTo(size_t new_capacity) {
+ // Use the capacity + 1 as the internal buffer size to differentiate
+ // empty and full (see definition of buffer_ below).
+ VectorBuffer new_buffer(new_capacity + 1);
+ MoveBuffer(buffer_, begin_, end_, &new_buffer, &begin_, &end_);
+ buffer_ = std::move(new_buffer);
+ }
+ void ExpandCapacityIfNecessary(size_t additional_elts) {
+ size_t min_new_capacity = size() + additional_elts;
+ if (capacity() >= min_new_capacity)
+ return; // Already enough room.
+
+ min_new_capacity =
+ std::max(min_new_capacity, internal::kCircularBufferInitialCapacity);
+
+ // std::vector always grows by at least 50%. WTF::Deque grows by at least
+ // 25%. We expect queue workloads to generally stay at a similar size and
+ // grow less than a vector might, so use 25%.
+ size_t new_capacity =
+ std::max(min_new_capacity, capacity() + capacity() / 4);
+ SetCapacityTo(new_capacity);
+ }
+
+ void ShrinkCapacityIfNecessary() {
+ // Don't auto-shrink below this size.
+ if (capacity() <= internal::kCircularBufferInitialCapacity)
+ return;
+
+ // Shrink when 100% of the size() is wasted.
+ size_t sz = size();
+ size_t empty_spaces = capacity() - sz;
+ if (empty_spaces < sz)
+ return;
+
+ // Leave 1/4 the size as free capacity, not going below the initial
+ // capacity.
+ size_t new_capacity =
+ std::max(internal::kCircularBufferInitialCapacity, sz + sz / 4);
+ if (new_capacity < capacity()) {
+ // Count extra item to convert to internal capacity.
+ SetCapacityTo(new_capacity);
+ }
+ }
+
+ // Backend for clear() but does not resize the internal buffer.
+ void ClearRetainCapacity() {
+ // This can't resize(0) because that requires a default constructor to
+ // compile, which not all contained classes may implement.
+ DestructRange(begin_, end_);
+ begin_ = 0;
+ end_ = 0;
+ IncrementGeneration();
+ }
+
+ // Calls destructors for the given begin->end indices. The indices may wrap
+ // around. The buffer is not resized, and the begin_ and end_ members are
+ // not changed.
+ void DestructRange(size_t begin, size_t end) {
+ if (end == begin) {
+ return;
+ } else if (end > begin) {
+ buffer_.DestructRange(&buffer_[begin], &buffer_[end]);
+ } else {
+ buffer_.DestructRange(&buffer_[begin], &buffer_[buffer_.capacity()]);
+ buffer_.DestructRange(&buffer_[0], &buffer_[end]);
+ }
+ }
+
+ // Makes room for |count| items starting at |*insert_begin|. Since iterators
+ // are not stable across buffer resizes, |*insert_begin| will be updated to
+ // point to the beginning of the newly opened position in the new array (it's
+ // in/out), and the end of the newly opened position (it's out-only).
+ void MakeRoomFor(size_t count, iterator* insert_begin, iterator* insert_end) {
+ if (count == 0) {
+ *insert_end = *insert_begin;
+ return;
+ }
+
+ // The offset from the beginning will be stable across reallocations.
+ size_t begin_offset = insert_begin->OffsetFromBegin();
+ ExpandCapacityIfNecessary(count);
+
+ insert_begin->index_ = (begin_ + begin_offset) % buffer_.capacity();
+ *insert_end =
+ iterator(this, (insert_begin->index_ + count) % buffer_.capacity());
+
+ // Update the new end and prepare the iterators for copying.
+ iterator src = end();
+ end_ = (end_ + count) % buffer_.capacity();
+ iterator dest = end();
+
+ // Move the elements. This will always involve shifting logically to the
+ // right, so move in a right-to-left order.
+ while (true) {
+ if (src == *insert_begin)
+ break;
+ --src;
+ --dest;
+ buffer_.MoveRange(&buffer_[src.index_], &buffer_[src.index_ + 1],
+ &buffer_[dest.index_]);
+ }
+ }
+
+#if DCHECK_IS_ON()
+ // Asserts the given index is dereferencable. The index is an index into the
+ // buffer, not an index used by operator[] or at() which will be offsets from
+ // begin.
+ void CheckValidIndex(size_t i) const {
+ if (begin_ <= end_)
+ DCHECK(i >= begin_ && i < end_);
+ else
+ DCHECK((i >= begin_ && i < buffer_.capacity()) || i < end_);
+ }
+
+ // Asserts the given index is either dereferencable or points to end().
+ void CheckValidIndexOrEnd(size_t i) const {
+ if (i != end_)
+ CheckValidIndex(i);
+ }
+
+ void ValidateIterator(const const_iterator& i) const {
+ DCHECK(i.parent_deque_ == this);
+ i.CheckUnstableUsage();
+ }
+
+ // See generation_ below.
+ void IncrementGeneration() { generation_++; }
+#else
+ // No-op versions of these functions for release builds.
+ void CheckValidIndex(size_t) const {}
+ void CheckValidIndexOrEnd(size_t) const {}
+ void ValidateIterator(const const_iterator& i) const {}
+ void IncrementGeneration() {}
+#endif
+
+ // Danger, the buffer_.capacity() is the "internal capacity" which is
+ // capacity() + 1 since there is an extra item to indicate the end. Otherwise
+ // being completely empty and completely full are indistinguishable (begin ==
+ // end). We could add a separate flag to avoid it, but that adds significant
+ // extra complexity since every computation will have to check for it. Always
+ // keeping one extra unused element in the buffer makes iterator computations
+ // much simpler.
+ //
+ // Container internal code will want to use buffer_.capacity() for offset
+ // computations rather than capacity().
+ VectorBuffer buffer_;
+ size_type begin_ = 0;
+ size_type end_ = 0;
+
+#if DCHECK_IS_ON()
+ // Incremented every time a modification is made that could affect iterator
+ // invalidations.
+ uint64_t generation_ = 0;
+#endif
+};
+
+// Implementations of base::Erase[If] (see base/stl_util.h).
+template <class T, class Value>
+void Erase(circular_deque<T>& container, const Value& value) {
+ container.erase(std::remove(container.begin(), container.end(), value),
+ container.end());
+}
+
+template <class T, class Predicate>
+void EraseIf(circular_deque<T>& container, Predicate pred) {
+ container.erase(std::remove_if(container.begin(), container.end(), pred),
+ container.end());
+}
+
+} // namespace base
+
+#endif // BASE_CONTAINERS_CIRCULAR_DEQUE_H_
diff --git a/security/sandbox/chromium/base/containers/span.h b/security/sandbox/chromium/base/containers/span.h
new file mode 100644
index 0000000000..ce2e3c47e5
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/span.h
@@ -0,0 +1,530 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_SPAN_H_
+#define BASE_CONTAINERS_SPAN_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <array>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+#include <utility>
+
+#include "base/containers/checked_iterators.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+// [views.constants]
+constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
+
+template <typename T, size_t Extent = dynamic_extent>
+class span;
+
+namespace internal {
+
+template <typename T>
+struct ExtentImpl : std::integral_constant<size_t, dynamic_extent> {};
+
+template <typename T, size_t N>
+struct ExtentImpl<T[N]> : std::integral_constant<size_t, N> {};
+
+template <typename T, size_t N>
+struct ExtentImpl<std::array<T, N>> : std::integral_constant<size_t, N> {};
+
+template <typename T, size_t N>
+struct ExtentImpl<base::span<T, N>> : std::integral_constant<size_t, N> {};
+
+template <typename T>
+using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>;
+
+template <typename T>
+struct IsSpanImpl : std::false_type {};
+
+template <typename T, size_t Extent>
+struct IsSpanImpl<span<T, Extent>> : std::true_type {};
+
+template <typename T>
+using IsSpan = IsSpanImpl<std::decay_t<T>>;
+
+template <typename T>
+struct IsStdArrayImpl : std::false_type {};
+
+template <typename T, size_t N>
+struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
+
+template <typename T>
+using IsStdArray = IsStdArrayImpl<std::decay_t<T>>;
+
+template <typename T>
+using IsCArray = std::is_array<std::remove_reference_t<T>>;
+
+template <typename From, typename To>
+using IsLegalDataConversion = std::is_convertible<From (*)[], To (*)[]>;
+
+template <typename Container, typename T>
+using ContainerHasConvertibleData = IsLegalDataConversion<
+ std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>,
+ T>;
+
+template <typename Container>
+using ContainerHasIntegralSize =
+ std::is_integral<decltype(base::size(std::declval<Container>()))>;
+
+template <typename From, size_t FromExtent, typename To, size_t ToExtent>
+using EnableIfLegalSpanConversion =
+ std::enable_if_t<(ToExtent == dynamic_extent || ToExtent == FromExtent) &&
+ IsLegalDataConversion<From, To>::value>;
+
+// SFINAE check if Array can be converted to a span<T>.
+template <typename Array, typename T, size_t Extent>
+using EnableIfSpanCompatibleArray =
+ std::enable_if_t<(Extent == dynamic_extent ||
+ Extent == internal::Extent<Array>::value) &&
+ ContainerHasConvertibleData<Array, T>::value>;
+
+// SFINAE check if Container can be converted to a span<T>.
+template <typename Container, typename T>
+using IsSpanCompatibleContainer =
+ std::conditional_t<!IsSpan<Container>::value &&
+ !IsStdArray<Container>::value &&
+ !IsCArray<Container>::value &&
+ ContainerHasConvertibleData<Container, T>::value &&
+ ContainerHasIntegralSize<Container>::value,
+ std::true_type,
+ std::false_type>;
+
+template <typename Container, typename T>
+using EnableIfSpanCompatibleContainer =
+ std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value>;
+
+template <typename Container, typename T, size_t Extent>
+using EnableIfSpanCompatibleContainerAndSpanIsDynamic =
+ std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value &&
+ Extent == dynamic_extent>;
+
+// A helper template for storing the size of a span. Spans with static extents
+// don't require additional storage, since the extent itself is specified in the
+// template parameter.
+template <size_t Extent>
+class ExtentStorage {
+ public:
+ constexpr explicit ExtentStorage(size_t size) noexcept {}
+ constexpr size_t size() const noexcept { return Extent; }
+};
+
+// Specialization of ExtentStorage for dynamic extents, which do require
+// explicit storage for the size.
+template <>
+struct ExtentStorage<dynamic_extent> {
+ constexpr explicit ExtentStorage(size_t size) noexcept : size_(size) {}
+ constexpr size_t size() const noexcept { return size_; }
+
+ private:
+ size_t size_;
+};
+
+} // namespace internal
+
+// A span is a value type that represents an array of elements of type T. Since
+// it only consists of a pointer to memory with an associated size, it is very
+// light-weight. It is cheap to construct, copy, move and use spans, so that
+// users are encouraged to use it as a pass-by-value parameter. A span does not
+// own the underlying memory, so care must be taken to ensure that a span does
+// not outlive the backing store.
+//
+// span is somewhat analogous to StringPiece, but with arbitrary element types,
+// allowing mutation if T is non-const.
+//
+// span is implicitly convertible from C++ arrays, as well as most [1]
+// container-like types that provide a data() and size() method (such as
+// std::vector<T>). A mutable span<T> can also be implicitly converted to an
+// immutable span<const T>.
+//
+// Consider using a span for functions that take a data pointer and size
+// parameter: it allows the function to still act on an array-like type, while
+// allowing the caller code to be a bit more concise.
+//
+// For read-only data access pass a span<const T>: the caller can supply either
+// a span<const T> or a span<T>, while the callee will have a read-only view.
+// For read-write access a mutable span<T> is required.
+//
+// Without span:
+// Read-Only:
+// // std::string HexEncode(const uint8_t* data, size_t size);
+// std::vector<uint8_t> data_buffer = GenerateData();
+// std::string r = HexEncode(data_buffer.data(), data_buffer.size());
+//
+// Mutable:
+// // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
+// char str_buffer[100];
+// SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
+//
+// With span:
+// Read-Only:
+// // std::string HexEncode(base::span<const uint8_t> data);
+// std::vector<uint8_t> data_buffer = GenerateData();
+// std::string r = HexEncode(data_buffer);
+//
+// Mutable:
+// // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
+// char str_buffer[100];
+// SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
+//
+// Spans with "const" and pointers
+// -------------------------------
+//
+// Const and pointers can get confusing. Here are vectors of pointers and their
+// corresponding spans:
+//
+// const std::vector<int*> => base::span<int* const>
+// std::vector<const int*> => base::span<const int*>
+// const std::vector<const int*> => base::span<const int* const>
+//
+// Differences from the C++20 draft
+// --------------------------------
+//
+// http://eel.is/c++draft/views contains the latest C++20 draft of std::span.
+// Chromium tries to follow the draft as close as possible. Differences between
+// the draft and the implementation are documented in subsections below.
+//
+// Differences from [span.objectrep]:
+// - as_bytes() and as_writable_bytes() return spans of uint8_t instead of
+// std::byte (std::byte is a C++17 feature)
+//
+// Differences from [span.cons]:
+// - Constructing a static span (i.e. Extent != dynamic_extent) from a dynamic
+// sized container (e.g. std::vector) requires an explicit conversion (in the
+// C++20 draft this is simply UB)
+//
+// Differences from [span.obs]:
+// - empty() is marked with WARN_UNUSED_RESULT instead of [[nodiscard]]
+// ([[nodiscard]] is a C++17 feature)
+//
+// Furthermore, all constructors and methods are marked noexcept due to the lack
+// of exceptions in Chromium.
+//
+// Due to the lack of class template argument deduction guides in C++14
+// appropriate make_span() utility functions are provided.
+
+// [span], class template span
+template <typename T, size_t Extent>
+class span : public internal::ExtentStorage<Extent> {
+ private:
+ using ExtentStorage = internal::ExtentStorage<Extent>;
+
+ public:
+ using element_type = T;
+ using value_type = std::remove_cv_t<T>;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using pointer = T*;
+ using reference = T&;
+ using iterator = CheckedContiguousIterator<T>;
+ using const_iterator = CheckedContiguousConstIterator<T>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ static constexpr size_t extent = Extent;
+
+ // [span.cons], span constructors, copy, assignment, and destructor
+ constexpr span() noexcept : ExtentStorage(0), data_(nullptr) {
+ static_assert(Extent == dynamic_extent || Extent == 0, "Invalid Extent");
+ }
+
+ constexpr span(T* data, size_t size) noexcept
+ : ExtentStorage(size), data_(data) {
+ CHECK(Extent == dynamic_extent || Extent == size);
+ }
+
+ // Artificially templatized to break ambiguity for span(ptr, 0).
+ template <typename = void>
+ constexpr span(T* begin, T* end) noexcept : span(begin, end - begin) {
+ // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+ CHECK(begin <= end);
+ }
+
+ template <
+ size_t N,
+ typename = internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>>
+ constexpr span(T (&array)[N]) noexcept : span(base::data(array), N) {}
+
+ template <
+ size_t N,
+ typename = internal::
+ EnableIfSpanCompatibleArray<std::array<value_type, N>&, T, Extent>>
+ constexpr span(std::array<value_type, N>& array) noexcept
+ : span(base::data(array), N) {}
+
+ template <size_t N,
+ typename = internal::EnableIfSpanCompatibleArray<
+ const std::array<value_type, N>&,
+ T,
+ Extent>>
+ constexpr span(const std::array<value_type, N>& array) noexcept
+ : span(base::data(array), N) {}
+
+ // Conversion from a container that has compatible base::data() and integral
+ // base::size().
+ template <
+ typename Container,
+ typename =
+ internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&,
+ T,
+ Extent>>
+ constexpr span(Container& container) noexcept
+ : span(base::data(container), base::size(container)) {}
+
+ template <
+ typename Container,
+ typename = internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<
+ const Container&,
+ T,
+ Extent>>
+ constexpr span(const Container& container) noexcept
+ : span(base::data(container), base::size(container)) {}
+
+ constexpr span(const span& other) noexcept = default;
+
+ // Conversions from spans of compatible types and extents: this allows a
+ // span<T> to be seamlessly used as a span<const T>, but not the other way
+ // around. If extent is not dynamic, OtherExtent has to be equal to Extent.
+ template <
+ typename U,
+ size_t OtherExtent,
+ typename =
+ internal::EnableIfLegalSpanConversion<U, OtherExtent, T, Extent>>
+ constexpr span(const span<U, OtherExtent>& other)
+ : span(other.data(), other.size()) {}
+
+ constexpr span& operator=(const span& other) noexcept = default;
+ ~span() noexcept = default;
+
+ // [span.sub], span subviews
+ template <size_t Count>
+ constexpr span<T, Count> first() const noexcept {
+ static_assert(Extent == dynamic_extent || Count <= Extent,
+ "Count must not exceed Extent");
+ CHECK(Extent != dynamic_extent || Count <= size());
+ return {data(), Count};
+ }
+
+ template <size_t Count>
+ constexpr span<T, Count> last() const noexcept {
+ static_assert(Extent == dynamic_extent || Count <= Extent,
+ "Count must not exceed Extent");
+ CHECK(Extent != dynamic_extent || Count <= size());
+ return {data() + (size() - Count), Count};
+ }
+
+ template <size_t Offset, size_t Count = dynamic_extent>
+ constexpr span<T,
+ (Count != dynamic_extent
+ ? Count
+ : (Extent != dynamic_extent ? Extent - Offset
+ : dynamic_extent))>
+ subspan() const noexcept {
+ static_assert(Extent == dynamic_extent || Offset <= Extent,
+ "Offset must not exceed Extent");
+ static_assert(Extent == dynamic_extent || Count == dynamic_extent ||
+ Count <= Extent - Offset,
+ "Count must not exceed Extent - Offset");
+ CHECK(Extent != dynamic_extent || Offset <= size());
+ CHECK(Extent != dynamic_extent || Count == dynamic_extent ||
+ Count <= size() - Offset);
+ return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
+ }
+
+ constexpr span<T, dynamic_extent> first(size_t count) const noexcept {
+ // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+ CHECK(count <= size());
+ return {data(), count};
+ }
+
+ constexpr span<T, dynamic_extent> last(size_t count) const noexcept {
+ // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+ CHECK(count <= size());
+ return {data() + (size() - count), count};
+ }
+
+ constexpr span<T, dynamic_extent> subspan(size_t offset,
+ size_t count = dynamic_extent) const
+ noexcept {
+ // Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
+ CHECK(offset <= size());
+ CHECK(count == dynamic_extent || count <= size() - offset);
+ return {data() + offset, count != dynamic_extent ? count : size() - offset};
+ }
+
+ // [span.obs], span observers
+ constexpr size_t size() const noexcept { return ExtentStorage::size(); }
+ constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
+ constexpr bool empty() const noexcept WARN_UNUSED_RESULT {
+ return size() == 0;
+ }
+
+ // [span.elem], span element access
+ constexpr T& operator[](size_t idx) const noexcept {
+ // Note: CHECK_LT is not constexpr, hence regular CHECK must be used.
+ CHECK(idx < size());
+ return *(data() + idx);
+ }
+
+ constexpr T& front() const noexcept {
+ static_assert(Extent == dynamic_extent || Extent > 0,
+ "Extent must not be 0");
+ CHECK(Extent != dynamic_extent || !empty());
+ return *data();
+ }
+
+ constexpr T& back() const noexcept {
+ static_assert(Extent == dynamic_extent || Extent > 0,
+ "Extent must not be 0");
+ CHECK(Extent != dynamic_extent || !empty());
+ return *(data() + size() - 1);
+ }
+
+ constexpr T* data() const noexcept { return data_; }
+
+ // [span.iter], span iterator support
+ constexpr iterator begin() const noexcept {
+ return iterator(data_, data_ + size());
+ }
+ constexpr iterator end() const noexcept {
+ return iterator(data_, data_ + size(), data_ + size());
+ }
+
+ constexpr const_iterator cbegin() const noexcept { return begin(); }
+ constexpr const_iterator cend() const noexcept { return end(); }
+
+ constexpr reverse_iterator rbegin() const noexcept {
+ return reverse_iterator(end());
+ }
+ constexpr reverse_iterator rend() const noexcept {
+ return reverse_iterator(begin());
+ }
+
+ constexpr const_reverse_iterator crbegin() const noexcept {
+ return const_reverse_iterator(cend());
+ }
+ constexpr const_reverse_iterator crend() const noexcept {
+ return const_reverse_iterator(cbegin());
+ }
+
+ private:
+ T* data_;
+};
+
+// span<T, Extent>::extent can not be declared inline prior to C++17, hence this
+// definition is required.
+template <class T, size_t Extent>
+constexpr size_t span<T, Extent>::extent;
+
+// [span.objectrep], views of object representation
+template <typename T, size_t X>
+span<const uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
+as_bytes(span<T, X> s) noexcept {
+ return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()};
+}
+
+template <typename T,
+ size_t X,
+ typename = std::enable_if_t<!std::is_const<T>::value>>
+span<uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
+as_writable_bytes(span<T, X> s) noexcept {
+ return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()};
+}
+
+// Type-deducing helpers for constructing a span.
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr span<T> make_span(T* data, size_t size) noexcept {
+ return {data, size};
+}
+
+template <int&... ExplicitArgumentBarrier, typename T>
+constexpr span<T> make_span(T* begin, T* end) noexcept {
+ return {begin, end};
+}
+
+// make_span utility function that deduces both the span's value_type and extent
+// from the passed in argument.
+//
+// Usage: auto span = base::make_span(...);
+template <int&... ExplicitArgumentBarrier, typename Container>
+constexpr auto make_span(Container&& container) noexcept {
+ using T =
+ std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>;
+ using Extent = internal::Extent<Container>;
+ return span<T, Extent::value>(std::forward<Container>(container));
+}
+
+// make_span utility function that allows callers to explicit specify the span's
+// extent, the value_type is deduced automatically. This is useful when passing
+// a dynamically sized container to a method expecting static spans, when the
+// container is known to have the correct size.
+//
+// Note: This will CHECK that N indeed matches size(container).
+//
+// Usage: auto static_span = base::make_span<N>(...);
+template <size_t N, int&... ExplicitArgumentBarrier, typename Container>
+constexpr auto make_span(Container&& container) noexcept {
+ using T =
+ std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>;
+ return span<T, N>(base::data(container), base::size(container));
+}
+
+} // namespace base
+
+// Note: std::tuple_size, std::tuple_element and std::get are specialized for
+// static spans, so that they can be used in C++17's structured bindings. While
+// we don't support C++17 yet, there is no harm in providing these
+// specializations already.
+namespace std {
+
+// [span.tuple], tuple interface
+#if defined(__clang__)
+// Due to https://llvm.org/PR39871 and https://llvm.org/PR41331 and their
+// respective fixes different versions of libc++ declare std::tuple_size and
+// std::tuple_element either as classes or structs. In order to be able to
+// specialize std::tuple_size and std::tuple_element for custom base types we
+// thus need to disable -Wmismatched-tags in order to support all build
+// configurations. Note that this is blessed by the standard in
+// https://timsong-cpp.github.io/cppwp/n4140/dcl.type.elab#3.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmismatched-tags"
+#endif
+template <typename T, size_t X>
+struct tuple_size<base::span<T, X>> : public integral_constant<size_t, X> {};
+
+template <typename T>
+struct tuple_size<base::span<T, base::dynamic_extent>>; // not defined
+
+template <size_t I, typename T, size_t X>
+struct tuple_element<I, base::span<T, X>> {
+ static_assert(
+ base::dynamic_extent != X,
+ "std::tuple_element<> not supported for base::span<T, dynamic_extent>");
+ static_assert(I < X,
+ "Index out of bounds in std::tuple_element<> (base::span)");
+ using type = T;
+};
+#if defined(__clang__)
+#pragma clang diagnostic pop // -Wmismatched-tags
+#endif
+
+template <size_t I, typename T, size_t X>
+constexpr T& get(base::span<T, X> s) noexcept {
+ static_assert(base::dynamic_extent != X,
+ "std::get<> not supported for base::span<T, dynamic_extent>");
+ static_assert(I < X, "Index out of bounds in std::get<> (base::span)");
+ return s[I];
+}
+
+} // namespace std
+
+#endif // BASE_CONTAINERS_SPAN_H_
diff --git a/security/sandbox/chromium/base/containers/stack.h b/security/sandbox/chromium/base/containers/stack.h
new file mode 100644
index 0000000000..5cf06f8251
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/stack.h
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_STACK_H_
+#define BASE_CONTAINERS_STACK_H_
+
+#include <stack>
+
+#include "base/containers/circular_deque.h"
+
+namespace base {
+
+// Provides a definition of base::stack that's like std::stack but uses a
+// base::circular_deque instead of std::deque. Since std::stack is just a
+// wrapper for an underlying type, we can just provide a typedef for it that
+// defaults to the base circular_deque.
+template <class T, class Container = circular_deque<T>>
+using stack = std::stack<T, Container>;
+
+} // namespace base
+
+#endif // BASE_CONTAINERS_STACK_H_
diff --git a/security/sandbox/chromium/base/containers/util.h b/security/sandbox/chromium/base/containers/util.h
new file mode 100644
index 0000000000..435db0d1f8
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/util.h
@@ -0,0 +1,21 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_UTIL_H_
+#define BASE_CONTAINERS_UTIL_H_
+
+#include <stdint.h>
+
+namespace base {
+
+// TODO(crbug.com/817982): What we really need is for checked_math.h to be
+// able to do checked arithmetic on pointers.
+template <typename T>
+static inline uintptr_t get_uintptr(const T* t) {
+ return reinterpret_cast<uintptr_t>(t);
+}
+
+} // namespace base
+
+#endif // BASE_CONTAINERS_UTIL_H_
diff --git a/security/sandbox/chromium/base/containers/vector_buffer.h b/security/sandbox/chromium/base/containers/vector_buffer.h
new file mode 100644
index 0000000000..83cd2ac139
--- /dev/null
+++ b/security/sandbox/chromium/base/containers/vector_buffer.h
@@ -0,0 +1,188 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_VECTOR_BUFFERS_H_
+#define BASE_CONTAINERS_VECTOR_BUFFERS_H_
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <type_traits>
+#include <utility>
+
+#include "base/containers/util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/numerics/checked_math.h"
+
+namespace base {
+namespace internal {
+
+// Internal implementation detail of base/containers.
+//
+// Implements a vector-like buffer that holds a certain capacity of T. Unlike
+// std::vector, VectorBuffer never constructs or destructs its arguments, and
+// can't change sizes. But it does implement templates to assist in efficient
+// moving and destruction of those items manually.
+//
+// In particular, the destructor function does not iterate over the items if
+// there is no destructor. Moves should be implemented as a memcpy/memmove for
+// trivially copyable objects (POD) otherwise, it should be a std::move if
+// possible, and as a last resort it falls back to a copy. This behavior is
+// similar to std::vector.
+//
+// No special consideration is done for noexcept move constructors since
+// we compile without exceptions.
+//
+// The current API does not support moving overlapping ranges.
+template <typename T>
+class VectorBuffer {
+ public:
+ constexpr VectorBuffer() = default;
+
+#if defined(__clang__) && !defined(__native_client__)
+ // This constructor converts an uninitialized void* to a T* which triggers
+ // clang Control Flow Integrity. Since this is as-designed, disable.
+ __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
+#endif
+ VectorBuffer(size_t count)
+ : buffer_(reinterpret_cast<T*>(
+ malloc(CheckMul(sizeof(T), count).ValueOrDie()))),
+ capacity_(count) {
+ }
+ VectorBuffer(VectorBuffer&& other) noexcept
+ : buffer_(other.buffer_), capacity_(other.capacity_) {
+ other.buffer_ = nullptr;
+ other.capacity_ = 0;
+ }
+
+ ~VectorBuffer() { free(buffer_); }
+
+ VectorBuffer& operator=(VectorBuffer&& other) {
+ free(buffer_);
+ buffer_ = other.buffer_;
+ capacity_ = other.capacity_;
+
+ other.buffer_ = nullptr;
+ other.capacity_ = 0;
+ return *this;
+ }
+
+ size_t capacity() const { return capacity_; }
+
+ T& operator[](size_t i) {
+ // TODO(crbug.com/817982): Some call sites (at least circular_deque.h) are
+ // calling this with `i == capacity_` as a way of getting `end()`. Therefore
+ // we have to allow this for now (`i <= capacity_`), until we fix those call
+ // sites to use real iterators. This comment applies here and to `const T&
+ // operator[]`, below.
+ CHECK_LE(i, capacity_);
+ return buffer_[i];
+ }
+
+ const T& operator[](size_t i) const {
+ CHECK_LE(i, capacity_);
+ return buffer_[i];
+ }
+
+ T* begin() { return buffer_; }
+ T* end() { return &buffer_[capacity_]; }
+
+ // DestructRange ------------------------------------------------------------
+
+ // Trivially destructible objects need not have their destructors called.
+ template <typename T2 = T,
+ typename std::enable_if<std::is_trivially_destructible<T2>::value,
+ int>::type = 0>
+ void DestructRange(T* begin, T* end) {}
+
+ // Non-trivially destructible objects must have their destructors called
+ // individually.
+ template <typename T2 = T,
+ typename std::enable_if<!std::is_trivially_destructible<T2>::value,
+ int>::type = 0>
+ void DestructRange(T* begin, T* end) {
+ CHECK_LE(begin, end);
+ while (begin != end) {
+ begin->~T();
+ begin++;
+ }
+ }
+
+ // MoveRange ----------------------------------------------------------------
+ //
+ // The destructor will be called (as necessary) for all moved types. The
+ // ranges must not overlap.
+ //
+ // The parameters and begin and end (one past the last) of the input buffer,
+ // and the address of the first element to copy to. There must be sufficient
+ // room in the destination for all items in the range [begin, end).
+
+ // Trivially copyable types can use memcpy. trivially copyable implies
+ // that there is a trivial destructor as we don't have to call it.
+ template <typename T2 = T,
+ typename std::enable_if<base::is_trivially_copyable<T2>::value,
+ int>::type = 0>
+ static void MoveRange(T* from_begin, T* from_end, T* to) {
+ CHECK(!RangesOverlap(from_begin, from_end, to));
+ memcpy(
+ to, from_begin,
+ CheckSub(get_uintptr(from_end), get_uintptr(from_begin)).ValueOrDie());
+ }
+
+ // Not trivially copyable, but movable: call the move constructor and
+ // destruct the original.
+ template <typename T2 = T,
+ typename std::enable_if<std::is_move_constructible<T2>::value &&
+ !base::is_trivially_copyable<T2>::value,
+ int>::type = 0>
+ static void MoveRange(T* from_begin, T* from_end, T* to) {
+ CHECK(!RangesOverlap(from_begin, from_end, to));
+ while (from_begin != from_end) {
+ new (to) T(std::move(*from_begin));
+ from_begin->~T();
+ from_begin++;
+ to++;
+ }
+ }
+
+ // Not movable, not trivially copyable: call the copy constructor and
+ // destruct the original.
+ template <typename T2 = T,
+ typename std::enable_if<!std::is_move_constructible<T2>::value &&
+ !base::is_trivially_copyable<T2>::value,
+ int>::type = 0>
+ static void MoveRange(T* from_begin, T* from_end, T* to) {
+ CHECK(!RangesOverlap(from_begin, from_end, to));
+ while (from_begin != from_end) {
+ new (to) T(*from_begin);
+ from_begin->~T();
+ from_begin++;
+ to++;
+ }
+ }
+
+ private:
+ static bool RangesOverlap(const T* from_begin,
+ const T* from_end,
+ const T* to) {
+ const auto from_begin_uintptr = get_uintptr(from_begin);
+ const auto from_end_uintptr = get_uintptr(from_end);
+ const auto to_uintptr = get_uintptr(to);
+ return !(
+ to >= from_end ||
+ CheckAdd(to_uintptr, CheckSub(from_end_uintptr, from_begin_uintptr))
+ .ValueOrDie() <= from_begin_uintptr);
+ }
+
+ T* buffer_ = nullptr;
+ size_t capacity_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(VectorBuffer);
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_CONTAINERS_VECTOR_BUFFERS_H_
diff --git a/security/sandbox/chromium/base/cpu.cc b/security/sandbox/chromium/base/cpu.cc
new file mode 100644
index 0000000000..8cc2028a5f
--- /dev/null
+++ b/security/sandbox/chromium/base/cpu.cc
@@ -0,0 +1,312 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/cpu.h"
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <algorithm>
+#include <utility>
+
+#include "base/stl_util.h"
+
+#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+#include "base/files/file_util.h"
+#endif
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#include <immintrin.h> // For _xgetbv()
+#endif
+#endif
+
+namespace base {
+
+#if defined(ARCH_CPU_X86_FAMILY)
+namespace internal {
+
+std::tuple<int, int, int, int> ComputeX86FamilyAndModel(
+ const std::string& vendor,
+ int signature) {
+ int family = (signature >> 8) & 0xf;
+ int model = (signature >> 4) & 0xf;
+ int ext_family = 0;
+ int ext_model = 0;
+
+ // The "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
+ // specifies the Extended Model is defined only when the Base Family is
+ // 06h or 0Fh.
+ // The "AMD CPUID Specification" specifies that the Extended Model is
+ // defined only when Base Family is 0Fh.
+ // Both manuals define the display model as
+ // {ExtendedModel[3:0],BaseModel[3:0]} in that case.
+ if (family == 0xf || (family == 0x6 && vendor == "GenuineIntel")) {
+ ext_model = (signature >> 16) & 0xf;
+ model += ext_model << 4;
+ }
+ // Both the "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
+ // and the "AMD CPUID Specification" specify that the Extended Family is
+ // defined only when the Base Family is 0Fh.
+ // Both manuals define the display family as {0000b,BaseFamily[3:0]} +
+ // ExtendedFamily[7:0] in that case.
+ if (family == 0xf) {
+ ext_family = (signature >> 20) & 0xff;
+ family += ext_family;
+ }
+
+ return {family, model, ext_family, ext_model};
+}
+
+} // namespace internal
+#endif // defined(ARCH_CPU_X86_FAMILY)
+
+CPU::CPU()
+ : signature_(0),
+ type_(0),
+ family_(0),
+ model_(0),
+ stepping_(0),
+ ext_model_(0),
+ ext_family_(0),
+ has_mmx_(false),
+ has_sse_(false),
+ has_sse2_(false),
+ has_sse3_(false),
+ has_ssse3_(false),
+ has_sse41_(false),
+ has_sse42_(false),
+ has_popcnt_(false),
+ has_avx_(false),
+ has_avx2_(false),
+ has_aesni_(false),
+ has_non_stop_time_stamp_counter_(false),
+ is_running_in_vm_(false),
+ cpu_vendor_("unknown") {
+ Initialize();
+}
+
+namespace {
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#if !defined(COMPILER_MSVC)
+
+#if defined(__pic__) && defined(__i386__)
+
+void __cpuid(int cpu_info[4], int info_type) {
+ __asm__ volatile(
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n"
+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]),
+ "=d"(cpu_info[3])
+ : "a"(info_type), "c"(0));
+}
+
+#else
+
+void __cpuid(int cpu_info[4], int info_type) {
+ __asm__ volatile("cpuid\n"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]),
+ "=d"(cpu_info[3])
+ : "a"(info_type), "c"(0));
+}
+
+#endif
+#endif // !defined(COMPILER_MSVC)
+
+// xgetbv returns the value of an Intel Extended Control Register (XCR).
+// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
+uint64_t xgetbv(uint32_t xcr) {
+#if defined(COMPILER_MSVC)
+ return _xgetbv(xcr);
+#else
+ uint32_t eax, edx;
+
+ __asm__ volatile (
+ "xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
+ return (static_cast<uint64_t>(edx) << 32) | eax;
+#endif // defined(COMPILER_MSVC)
+}
+
+#endif // ARCH_CPU_X86_FAMILY
+
+#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+std::string* CpuInfoBrand() {
+ static std::string* brand = []() {
+ // This function finds the value from /proc/cpuinfo under the key "model
+ // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
+ // and later for arm64) and is shown once per CPU. "Processor" is used in
+ // earler versions and is shown only once at the top of /proc/cpuinfo
+ // regardless of the number CPUs.
+ const char kModelNamePrefix[] = "model name\t: ";
+ const char kProcessorPrefix[] = "Processor\t: ";
+
+ std::string contents;
+ ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
+ DCHECK(!contents.empty());
+
+ std::istringstream iss(contents);
+ std::string line;
+ while (std::getline(iss, line)) {
+ if (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0)
+ return new std::string(line.substr(strlen(kModelNamePrefix)));
+ if (line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)
+ return new std::string(line.substr(strlen(kProcessorPrefix)));
+ }
+
+ return new std::string();
+ }();
+
+ return brand;
+}
+#endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
+ // defined(OS_LINUX))
+
+} // namespace
+
+void CPU::Initialize() {
+#if defined(ARCH_CPU_X86_FAMILY)
+ int cpu_info[4] = {-1};
+ // This array is used to temporarily hold the vendor name and then the brand
+ // name. Thus it has to be big enough for both use cases. There are
+ // static_asserts below for each of the use cases to make sure this array is
+ // big enough.
+ char cpu_string[sizeof(cpu_info) * 3 + 1];
+
+ // __cpuid with an InfoType argument of 0 returns the number of
+ // valid Ids in CPUInfo[0] and the CPU identification string in
+ // the other three array elements. The CPU identification string is
+ // not in linear order. The code below arranges the information
+ // in a human readable form. The human readable order is CPUInfo[1] |
+ // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
+ // before using memcpy() to copy these three array elements to |cpu_string|.
+ __cpuid(cpu_info, 0);
+ int num_ids = cpu_info[0];
+ std::swap(cpu_info[2], cpu_info[3]);
+ static constexpr size_t kVendorNameSize = 3 * sizeof(cpu_info[1]);
+ static_assert(kVendorNameSize < base::size(cpu_string),
+ "cpu_string too small");
+ memcpy(cpu_string, &cpu_info[1], kVendorNameSize);
+ cpu_string[kVendorNameSize] = '\0';
+ cpu_vendor_ = cpu_string;
+
+ // Interpret CPU feature information.
+ if (num_ids > 0) {
+ int cpu_info7[4] = {0};
+ __cpuid(cpu_info, 1);
+ if (num_ids >= 7) {
+ __cpuid(cpu_info7, 7);
+ }
+ signature_ = cpu_info[0];
+ stepping_ = cpu_info[0] & 0xf;
+ type_ = (cpu_info[0] >> 12) & 0x3;
+ std::tie(family_, model_, ext_family_, ext_model_) =
+ internal::ComputeX86FamilyAndModel(cpu_vendor_, signature_);
+ has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
+ has_sse_ = (cpu_info[3] & 0x02000000) != 0;
+ has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
+ has_sse3_ = (cpu_info[2] & 0x00000001) != 0;
+ has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
+ has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
+ has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
+ has_popcnt_ = (cpu_info[2] & 0x00800000) != 0;
+
+ // "Hypervisor Present Bit: Bit 31 of ECX of CPUID leaf 0x1."
+ // See https://lwn.net/Articles/301888/
+ // This is checking for any hypervisor. Hypervisors may choose not to
+ // announce themselves. Hypervisors trap CPUID and sometimes return
+ // different results to underlying hardware.
+ is_running_in_vm_ = (cpu_info[2] & 0x80000000) != 0;
+
+ // AVX instructions will generate an illegal instruction exception unless
+ // a) they are supported by the CPU,
+ // b) XSAVE is supported by the CPU and
+ // c) XSAVE is enabled by the kernel.
+ // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
+ //
+ // In addition, we have observed some crashes with the xgetbv instruction
+ // even after following Intel's example code. (See crbug.com/375968.)
+ // Because of that, we also test the XSAVE bit because its description in
+ // the CPUID documentation suggests that it signals xgetbv support.
+ has_avx_ =
+ (cpu_info[2] & 0x10000000) != 0 &&
+ (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
+ (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
+ (xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
+ has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
+ has_avx2_ = has_avx_ && (cpu_info7[1] & 0x00000020) != 0;
+ }
+
+ // Get the brand string of the cpu.
+ __cpuid(cpu_info, 0x80000000);
+ const int max_parameter = cpu_info[0];
+
+ static constexpr int kParameterStart = 0x80000002;
+ static constexpr int kParameterEnd = 0x80000004;
+ static constexpr int kParameterSize = kParameterEnd - kParameterStart + 1;
+ static_assert(kParameterSize * sizeof(cpu_info) + 1 == base::size(cpu_string),
+ "cpu_string has wrong size");
+
+ if (max_parameter >= kParameterEnd) {
+ size_t i = 0;
+ for (int parameter = kParameterStart; parameter <= kParameterEnd;
+ ++parameter) {
+ __cpuid(cpu_info, parameter);
+ memcpy(&cpu_string[i], cpu_info, sizeof(cpu_info));
+ i += sizeof(cpu_info);
+ }
+ cpu_string[i] = '\0';
+ cpu_brand_ = cpu_string;
+ }
+
+ static constexpr int kParameterContainingNonStopTimeStampCounter = 0x80000007;
+ if (max_parameter >= kParameterContainingNonStopTimeStampCounter) {
+ __cpuid(cpu_info, kParameterContainingNonStopTimeStampCounter);
+ has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
+ }
+
+ if (!has_non_stop_time_stamp_counter_ && is_running_in_vm_) {
+ int cpu_info_hv[4] = {};
+ __cpuid(cpu_info_hv, 0x40000000);
+ if (cpu_info_hv[1] == 0x7263694D && // Micr
+ cpu_info_hv[2] == 0x666F736F && // osof
+ cpu_info_hv[3] == 0x76482074) { // t Hv
+ // If CPUID says we have a variant TSC and a hypervisor has identified
+ // itself and the hypervisor says it is Microsoft Hyper-V, then treat
+ // TSC as invariant.
+ //
+ // Microsoft Hyper-V hypervisor reports variant TSC as there are some
+ // scenarios (eg. VM live migration) where the TSC is variant, but for
+ // our purposes we can treat it as invariant.
+ has_non_stop_time_stamp_counter_ = true;
+ }
+ }
+#elif defined(ARCH_CPU_ARM_FAMILY)
+#if (defined(OS_ANDROID) || defined(OS_LINUX))
+ cpu_brand_ = *CpuInfoBrand();
+#elif defined(OS_WIN)
+ // Windows makes high-resolution thread timing information available in
+ // user-space.
+ has_non_stop_time_stamp_counter_ = true;
+#endif
+#endif
+}
+
+CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
+ if (has_avx2()) return AVX2;
+ if (has_avx()) return AVX;
+ if (has_sse42()) return SSE42;
+ if (has_sse41()) return SSE41;
+ if (has_ssse3()) return SSSE3;
+ if (has_sse3()) return SSE3;
+ if (has_sse2()) return SSE2;
+ if (has_sse()) return SSE;
+ return PENTIUM;
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/cpu.h b/security/sandbox/chromium/base/cpu.h
new file mode 100644
index 0000000000..4fcda6904f
--- /dev/null
+++ b/security/sandbox/chromium/base/cpu.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CPU_H_
+#define BASE_CPU_H_
+
+#include <string>
+#include <tuple>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+
+#if defined(ARCH_CPU_X86_FAMILY)
+namespace internal {
+
+// Compute the CPU family and model based on the vendor and CPUID signature.
+// Returns in order: family, model, extended family, extended model.
+BASE_EXPORT std::tuple<int, int, int, int> ComputeX86FamilyAndModel(
+ const std::string& vendor,
+ int signature);
+
+} // namespace internal
+#endif // defined(ARCH_CPU_X86_FAMILY)
+
+// Query information about the processor.
+class BASE_EXPORT CPU final {
+ public:
+ CPU();
+
+ enum IntelMicroArchitecture {
+ PENTIUM,
+ SSE,
+ SSE2,
+ SSE3,
+ SSSE3,
+ SSE41,
+ SSE42,
+ AVX,
+ AVX2,
+ MAX_INTEL_MICRO_ARCHITECTURE
+ };
+
+ // Accessors for CPU information.
+ const std::string& vendor_name() const { return cpu_vendor_; }
+ int signature() const { return signature_; }
+ int stepping() const { return stepping_; }
+ int model() const { return model_; }
+ int family() const { return family_; }
+ int type() const { return type_; }
+ int extended_model() const { return ext_model_; }
+ int extended_family() const { return ext_family_; }
+ bool has_mmx() const { return has_mmx_; }
+ bool has_sse() const { return has_sse_; }
+ bool has_sse2() const { return has_sse2_; }
+ bool has_sse3() const { return has_sse3_; }
+ bool has_ssse3() const { return has_ssse3_; }
+ bool has_sse41() const { return has_sse41_; }
+ bool has_sse42() const { return has_sse42_; }
+ bool has_popcnt() const { return has_popcnt_; }
+ bool has_avx() const { return has_avx_; }
+ bool has_avx2() const { return has_avx2_; }
+ bool has_aesni() const { return has_aesni_; }
+ bool has_non_stop_time_stamp_counter() const {
+ return has_non_stop_time_stamp_counter_;
+ }
+ bool is_running_in_vm() const { return is_running_in_vm_; }
+
+ IntelMicroArchitecture GetIntelMicroArchitecture() const;
+ const std::string& cpu_brand() const { return cpu_brand_; }
+
+ private:
+ // Query the processor for CPUID information.
+ void Initialize();
+
+ int signature_; // raw form of type, family, model, and stepping
+ int type_; // process type
+ int family_; // family of the processor
+ int model_; // model of processor
+ int stepping_; // processor revision number
+ int ext_model_;
+ int ext_family_;
+ bool has_mmx_;
+ bool has_sse_;
+ bool has_sse2_;
+ bool has_sse3_;
+ bool has_ssse3_;
+ bool has_sse41_;
+ bool has_sse42_;
+ bool has_popcnt_;
+ bool has_avx_;
+ bool has_avx2_;
+ bool has_aesni_;
+ bool has_non_stop_time_stamp_counter_;
+ bool is_running_in_vm_;
+ std::string cpu_vendor_;
+ std::string cpu_brand_;
+};
+
+} // namespace base
+
+#endif // BASE_CPU_H_
diff --git a/security/sandbox/chromium/base/debug/alias.cc b/security/sandbox/chromium/base/debug/alias.cc
new file mode 100644
index 0000000000..f808c50345
--- /dev/null
+++ b/security/sandbox/chromium/base/debug/alias.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/alias.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace debug {
+
+// This file/function should be excluded from LTO/LTCG to ensure that the
+// compiler can't see this function's implementation when compiling calls to it.
+NOINLINE void Alias(const void* var) {}
+
+} // namespace debug
+} // namespace base
diff --git a/security/sandbox/chromium/base/debug/alias.h b/security/sandbox/chromium/base/debug/alias.h
new file mode 100644
index 0000000000..35af2c23bf
--- /dev/null
+++ b/security/sandbox/chromium/base/debug/alias.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_ALIAS_H_
+#define BASE_DEBUG_ALIAS_H_
+
+#include "base/base_export.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace debug {
+
+// Make the optimizer think that var is aliased. This is to prevent it from
+// optimizing out local variables that would not otherwise be live at the point
+// of a potential crash.
+// base::debug::Alias should only be used for local variables, not globals,
+// object members, or function return values - these must be copied to locals if
+// you want to ensure they are recorded in crash dumps.
+// Note that if the local variable is a pointer then its value will be retained
+// but the memory that it points to will probably not be saved in the crash
+// dump - by default only stack memory is saved. Therefore the aliasing
+// technique is usually only worthwhile with non-pointer variables. If you have
+// a pointer to an object and you want to retain the object's state you need to
+// copy the object or its fields to local variables. Example usage:
+// int last_error = err_;
+// base::debug::Alias(&last_error);
+// DEBUG_ALIAS_FOR_CSTR(name_copy, p->name, 16);
+// CHECK(false);
+void BASE_EXPORT Alias(const void* var);
+
+} // namespace debug
+} // namespace base
+
+// Convenience macro that copies the null-terminated string from |c_str| into a
+// stack-allocated char array named |var_name| that holds up to |char_count|
+// characters and should be preserved in memory dumps.
+#define DEBUG_ALIAS_FOR_CSTR(var_name, c_str, char_count) \
+ char var_name[char_count]; \
+ ::base::strlcpy(var_name, (c_str), base::size(var_name)); \
+ ::base::debug::Alias(var_name);
+
+#endif // BASE_DEBUG_ALIAS_H_
diff --git a/security/sandbox/chromium/base/debug/crash_logging.h b/security/sandbox/chromium/base/debug/crash_logging.h
new file mode 100644
index 0000000000..9c6cd758da
--- /dev/null
+++ b/security/sandbox/chromium/base/debug/crash_logging.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_CRASH_LOGGING_H_
+#define BASE_DEBUG_CRASH_LOGGING_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+namespace debug {
+
+// A crash key is an annotation that is carried along with a crash report, to
+// provide additional debugging information beyond a stack trace. Crash keys
+// have a name and a string value.
+//
+// The preferred API is //components/crash/core/common:crash_key, however not
+// all clients can hold a direct dependency on that target. The API provided
+// in this file indirects the dependency.
+//
+// Example usage:
+// static CrashKeyString* crash_key =
+// AllocateCrashKeyString("name", CrashKeySize::Size32);
+// SetCrashKeyString(crash_key, "value");
+// ClearCrashKeyString(crash_key);
+
+// The maximum length for a crash key's value must be one of the following
+// pre-determined values.
+enum class CrashKeySize {
+ Size32 = 32,
+ Size64 = 64,
+ Size256 = 256,
+};
+
+struct CrashKeyString;
+
+// Allocates a new crash key with the specified |name| with storage for a
+// value up to length |size|. This will return null if the crash key system is
+// not initialized.
+BASE_EXPORT CrashKeyString* AllocateCrashKeyString(const char name[],
+ CrashKeySize size);
+
+// Stores |value| into the specified |crash_key|. The |crash_key| may be null
+// if AllocateCrashKeyString() returned null. If |value| is longer than the
+// size with which the key was allocated, it will be truncated.
+BASE_EXPORT void SetCrashKeyString(CrashKeyString* crash_key,
+ base::StringPiece value);
+
+// Clears any value that was stored in |crash_key|. The |crash_key| may be
+// null.
+BASE_EXPORT void ClearCrashKeyString(CrashKeyString* crash_key);
+
+// A scoper that sets the specified key to value for the lifetime of the
+// object, and clears it on destruction.
+class BASE_EXPORT ScopedCrashKeyString {
+ public:
+ ScopedCrashKeyString(CrashKeyString* crash_key, base::StringPiece value);
+ ~ScopedCrashKeyString();
+
+ private:
+ CrashKeyString* const crash_key_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCrashKeyString);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// The following declarations are used to initialize the crash key system
+// in //base by providing implementations for the above functions.
+
+// The virtual interface that provides the implementation for the crash key
+// API. This is implemented by a higher-layer component, and the instance is
+// set using the function below.
+class CrashKeyImplementation {
+ public:
+ virtual ~CrashKeyImplementation() = default;
+
+ virtual CrashKeyString* Allocate(const char name[], CrashKeySize size) = 0;
+ virtual void Set(CrashKeyString* crash_key, base::StringPiece value) = 0;
+ virtual void Clear(CrashKeyString* crash_key) = 0;
+};
+
+// Initializes the crash key system in base by replacing the existing
+// implementation, if it exists, with |impl|. The |impl| is copied into base.
+BASE_EXPORT void SetCrashKeyImplementation(
+ std::unique_ptr<CrashKeyImplementation> impl);
+
+// The base structure for a crash key, storing the allocation metadata.
+struct CrashKeyString {
+ constexpr CrashKeyString(const char name[], CrashKeySize size)
+ : name(name), size(size) {}
+ const char* const name;
+ const CrashKeySize size;
+};
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_CRASH_LOGGING_H_
diff --git a/security/sandbox/chromium/base/debug/debugger.h b/security/sandbox/chromium/base/debug/debugger.h
new file mode 100644
index 0000000000..efc9b40cb9
--- /dev/null
+++ b/security/sandbox/chromium/base/debug/debugger.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a cross platform interface for helper functions related to
+// debuggers. You should use this to test if you're running under a debugger,
+// and if you would like to yield (breakpoint) into the debugger.
+
+#ifndef BASE_DEBUG_DEBUGGER_H_
+#define BASE_DEBUG_DEBUGGER_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Waits wait_seconds seconds for a debugger to attach to the current process.
+// When silent is false, an exception is thrown when a debugger is detected.
+BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent);
+
+// Returns true if the given process is being run under a debugger.
+//
+// On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
+// To get around this, this function caches its value.
+//
+// WARNING: Because of this, on OS X, a call MUST be made to this function
+// BEFORE the sandbox is enabled.
+BASE_EXPORT bool BeingDebugged();
+
+// Break into the debugger, assumes a debugger is present.
+BASE_EXPORT void BreakDebugger();
+
+// Used in test code, this controls whether showing dialogs and breaking into
+// the debugger is suppressed for debug errors, even in debug mode (normally
+// release mode doesn't do this stuff -- this is controlled separately).
+// Normally UI is not suppressed. This is normally used when running automated
+// tests where we want a crash rather than a dialog or a debugger.
+BASE_EXPORT void SetSuppressDebugUI(bool suppress);
+BASE_EXPORT bool IsDebugUISuppressed();
+
+// If a debugger is present, verifies that it is properly set up, and DCHECK()s
+// if misconfigured. Currently only verifies that //tools/gdb/gdbinit has been
+// sourced when using gdb on Linux and //tools/lldb/lldbinit.py has been sourced
+// when using lldb on macOS.
+BASE_EXPORT void VerifyDebugger();
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_DEBUGGER_H_
diff --git a/security/sandbox/chromium/base/debug/leak_annotations.h b/security/sandbox/chromium/base/debug/leak_annotations.h
new file mode 100644
index 0000000000..dc502461d0
--- /dev/null
+++ b/security/sandbox/chromium/base/debug/leak_annotations.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
+#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
+// This file defines macros which can be used to annotate intentional memory
+// leaks. Support for annotations is implemented in LeakSanitizer. Annotated
+// objects will be treated as a source of live pointers, i.e. any heap objects
+// reachable by following pointers from an annotated object will not be
+// reported as leaks.
+//
+// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope
+// will be annotated as leaks.
+// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will
+// be annotated as a leak.
+
+#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
+
+#include <sanitizer/lsan_interface.h>
+
+class ScopedLeakSanitizerDisabler {
+ public:
+ ScopedLeakSanitizerDisabler() { __lsan_disable(); }
+ ~ScopedLeakSanitizerDisabler() { __lsan_enable(); }
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler);
+};
+
+#define ANNOTATE_SCOPED_MEMORY_LEAK \
+ ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast<void>(0)
+
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X);
+
+#else
+
+#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
+
+#endif
+
+#endif // BASE_DEBUG_LEAK_ANNOTATIONS_H_
diff --git a/security/sandbox/chromium/base/debug/profiler.cc b/security/sandbox/chromium/base/debug/profiler.cc
new file mode 100644
index 0000000000..3530d61d07
--- /dev/null
+++ b/security/sandbox/chromium/base/debug/profiler.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/profiler.h"
+
+#include <string>
+
+#include "base/allocator/buildflags.h"
+#include "base/debug/debugging_buildflags.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/current_module.h"
+#include "base/win/pe_image.h"
+#endif // defined(OS_WIN)
+
+// TODO(peria): Enable profiling on Windows.
+#if BUILDFLAG(ENABLE_PROFILING) && BUILDFLAG(USE_TCMALLOC) && !defined(OS_WIN)
+#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
+#endif
+
+namespace base {
+namespace debug {
+
+// TODO(peria): Enable profiling on Windows.
+#if BUILDFLAG(ENABLE_PROFILING) && BUILDFLAG(USE_TCMALLOC) && !defined(OS_WIN)
+
+static int profile_count = 0;
+
+void StartProfiling(const std::string& name) {
+ ++profile_count;
+ std::string full_name(name);
+ std::string pid = NumberToString(GetCurrentProcId());
+ std::string count = NumberToString(profile_count);
+ ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
+ ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
+ ProfilerStart(full_name.c_str());
+}
+
+void StopProfiling() {
+ ProfilerFlush();
+ ProfilerStop();
+}
+
+void FlushProfiling() {
+ ProfilerFlush();
+}
+
+bool BeingProfiled() {
+ return ProfilingIsEnabledForAllThreads();
+}
+
+void RestartProfilingAfterFork() {
+ ProfilerRegisterThread();
+}
+
+bool IsProfilingSupported() {
+ return true;
+}
+
+#else
+
+void StartProfiling(const std::string& name) {
+}
+
+void StopProfiling() {
+}
+
+void FlushProfiling() {
+}
+
+bool BeingProfiled() {
+ return false;
+}
+
+void RestartProfilingAfterFork() {
+}
+
+bool IsProfilingSupported() {
+ return false;
+}
+
+#endif
+
+#if !defined(OS_WIN)
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+ return nullptr;
+}
+
+AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
+ return nullptr;
+}
+
+MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
+ return nullptr;
+}
+
+#else // defined(OS_WIN)
+
+namespace {
+
+struct FunctionSearchContext {
+ const char* name;
+ FARPROC function;
+};
+
+// Callback function to PEImage::EnumImportChunks.
+bool FindResolutionFunctionInImports(
+ const base::win::PEImage &image, const char* module_name,
+ PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
+ PVOID cookie) {
+ FunctionSearchContext* context =
+ reinterpret_cast<FunctionSearchContext*>(cookie);
+
+ DCHECK(context);
+ DCHECK(!context->function);
+
+ // Our import address table contains pointers to the functions we import
+ // at this point. Let's retrieve the first such function and use it to
+ // find the module this import was resolved to by the loader.
+ const wchar_t* function_in_module =
+ reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
+
+ // Retrieve the module by a function in the module.
+ const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
+ HMODULE module = NULL;
+ if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
+ // This can happen if someone IAT patches us to a thunk.
+ return true;
+ }
+
+ // See whether this module exports the function we're looking for.
+ FARPROC exported_func = ::GetProcAddress(module, context->name);
+ if (exported_func != NULL) {
+ // We found it, return the function and terminate the enumeration.
+ context->function = exported_func;
+ return false;
+ }
+
+ // Keep going.
+ return true;
+}
+
+template <typename FunctionType>
+FunctionType FindFunctionInImports(const char* function_name) {
+ base::win::PEImage image(CURRENT_MODULE());
+
+ FunctionSearchContext ctx = { function_name, NULL };
+ image.EnumImportChunks(FindResolutionFunctionInImports, &ctx, nullptr);
+
+ return reinterpret_cast<FunctionType>(ctx.function);
+}
+
+} // namespace
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+ return FindFunctionInImports<ReturnAddressLocationResolver>(
+ "ResolveReturnAddressLocation");
+}
+
+AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
+ return FindFunctionInImports<AddDynamicSymbol>(
+ "AddDynamicSymbol");
+}
+
+MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
+ return FindFunctionInImports<MoveDynamicSymbol>(
+ "MoveDynamicSymbol");
+}
+
+#endif // defined(OS_WIN)
+
+} // namespace debug
+} // namespace base
diff --git a/security/sandbox/chromium/base/debug/profiler.h b/security/sandbox/chromium/base/debug/profiler.h
new file mode 100644
index 0000000000..1229e06234
--- /dev/null
+++ b/security/sandbox/chromium/base/debug/profiler.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_PROFILER_H_
+#define BASE_DEBUG_PROFILER_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+// The Profiler functions allow usage of the underlying sampling based
+// profiler. If the application has not been built with the necessary
+// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions
+// are noops.
+namespace base {
+namespace debug {
+
+// Start profiling with the supplied name.
+// {pid} will be replaced by the process' pid and {count} will be replaced
+// by the count of the profile run (starts at 1 with each process).
+BASE_EXPORT void StartProfiling(const std::string& name);
+
+// Stop profiling and write out data.
+BASE_EXPORT void StopProfiling();
+
+// Force data to be written to file.
+BASE_EXPORT void FlushProfiling();
+
+// Returns true if process is being profiled.
+BASE_EXPORT bool BeingProfiled();
+
+// Reset profiling after a fork, which disables timers.
+BASE_EXPORT void RestartProfilingAfterFork();
+
+// Returns true iff this executable supports profiling.
+BASE_EXPORT bool IsProfilingSupported();
+
+// There's a class of profilers that use "return address swizzling" to get a
+// hook on function exits. This class of profilers uses some form of entry hook,
+// like e.g. binary instrumentation, or a compiler flag, that calls a hook each
+// time a function is invoked. The hook then switches the return address on the
+// stack for the address of an exit hook function, and pushes the original
+// return address to a shadow stack of some type. When in due course the CPU
+// executes a return to the exit hook, the exit hook will do whatever work it
+// does on function exit, then arrange to return to the original return address.
+// This class of profiler does not play well with programs that look at the
+// return address, as does e.g. V8. V8 uses the return address to certain
+// runtime functions to find the JIT code that called it, and from there finds
+// the V8 data structures associated to the JS function involved.
+// A return address resolution function is used to fix this. It allows such
+// programs to resolve a location on stack where a return address originally
+// resided, to the shadow stack location where the profiler stashed it.
+typedef uintptr_t (*ReturnAddressLocationResolver)(
+ uintptr_t return_addr_location);
+
+typedef void (*AddDynamicSymbol)(const void* address,
+ size_t length,
+ const char* name,
+ size_t name_len);
+typedef void (*MoveDynamicSymbol)(const void* address, const void* new_address);
+
+
+// If this binary is instrumented and the instrumentation supplies a function
+// for each of those purposes, find and return the function in question.
+// Otherwise returns NULL.
+BASE_EXPORT ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc();
+BASE_EXPORT AddDynamicSymbol GetProfilerAddDynamicSymbolFunc();
+BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_PROFILER_H_
diff --git a/security/sandbox/chromium/base/environment.cc b/security/sandbox/chromium/base/environment.cc
new file mode 100644
index 0000000000..8e3afd8983
--- /dev/null
+++ b/security/sandbox/chromium/base/environment.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/environment.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+namespace {
+
+class EnvironmentImpl : public Environment {
+ public:
+ bool GetVar(StringPiece variable_name, std::string* result) override {
+ if (GetVarImpl(variable_name, result))
+ return true;
+
+ // Some commonly used variable names are uppercase while others
+ // are lowercase, which is inconsistent. Let's try to be helpful
+ // and look for a variable name with the reverse case.
+ // I.e. HTTP_PROXY may be http_proxy for some users/systems.
+ char first_char = variable_name[0];
+ std::string alternate_case_var;
+ if (IsAsciiLower(first_char))
+ alternate_case_var = ToUpperASCII(variable_name);
+ else if (IsAsciiUpper(first_char))
+ alternate_case_var = ToLowerASCII(variable_name);
+ else
+ return false;
+ return GetVarImpl(alternate_case_var, result);
+ }
+
+ bool SetVar(StringPiece variable_name,
+ const std::string& new_value) override {
+ return SetVarImpl(variable_name, new_value);
+ }
+
+ bool UnSetVar(StringPiece variable_name) override {
+ return UnSetVarImpl(variable_name);
+ }
+
+ private:
+ bool GetVarImpl(StringPiece variable_name, std::string* result) {
+#if defined(OS_WIN)
+ DWORD value_length =
+ ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), nullptr, 0);
+ if (value_length == 0)
+ return false;
+ if (result) {
+ std::unique_ptr<wchar_t[]> value(new wchar_t[value_length]);
+ ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(),
+ value_length);
+ *result = WideToUTF8(value.get());
+ }
+ return true;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ const char* env_value = getenv(variable_name.data());
+ if (!env_value)
+ return false;
+ // Note that the variable may be defined but empty.
+ if (result)
+ *result = env_value;
+ return true;
+#endif
+ }
+
+ bool SetVarImpl(StringPiece variable_name, const std::string& new_value) {
+#if defined(OS_WIN)
+ // On success, a nonzero value is returned.
+ return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(),
+ UTF8ToWide(new_value).c_str());
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // On success, zero is returned.
+ return !setenv(variable_name.data(), new_value.c_str(), 1);
+#endif
+ }
+
+ bool UnSetVarImpl(StringPiece variable_name) {
+#if defined(OS_WIN)
+ // On success, a nonzero value is returned.
+ return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), nullptr);
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // On success, zero is returned.
+ return !unsetenv(variable_name.data());
+#endif
+ }
+};
+
+} // namespace
+
+namespace env_vars {
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+// On Posix systems, this variable contains the location of the user's home
+// directory. (e.g, /home/username/).
+const char kHome[] = "HOME";
+#endif
+
+} // namespace env_vars
+
+Environment::~Environment() = default;
+
+// static
+std::unique_ptr<Environment> Environment::Create() {
+ return std::make_unique<EnvironmentImpl>();
+}
+
+bool Environment::HasVar(StringPiece variable_name) {
+ return GetVar(variable_name, nullptr);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/environment.h b/security/sandbox/chromium/base/environment.h
new file mode 100644
index 0000000000..79529a2131
--- /dev/null
+++ b/security/sandbox/chromium/base/environment.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ENVIRONMENT_H_
+#define BASE_ENVIRONMENT_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace env_vars {
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+BASE_EXPORT extern const char kHome[];
+#endif
+
+} // namespace env_vars
+
+class BASE_EXPORT Environment {
+ public:
+ virtual ~Environment();
+
+ // Returns the appropriate platform-specific instance.
+ static std::unique_ptr<Environment> Create();
+
+ // Gets an environment variable's value and stores it in |result|.
+ // Returns false if the key is unset.
+ virtual bool GetVar(StringPiece variable_name, std::string* result) = 0;
+
+ // Syntactic sugar for GetVar(variable_name, nullptr);
+ virtual bool HasVar(StringPiece variable_name);
+
+ // Returns true on success, otherwise returns false. This method should not
+ // be called in a multi-threaded process.
+ virtual bool SetVar(StringPiece variable_name,
+ const std::string& new_value) = 0;
+
+ // Returns true on success, otherwise returns false. This method should not
+ // be called in a multi-threaded process.
+ virtual bool UnSetVar(StringPiece variable_name) = 0;
+};
+
+#if defined(OS_WIN)
+using NativeEnvironmentString = std::wstring;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+using NativeEnvironmentString = std::string;
+#endif
+using EnvironmentMap =
+ std::map<NativeEnvironmentString, NativeEnvironmentString>;
+
+} // namespace base
+
+#endif // BASE_ENVIRONMENT_H_
diff --git a/security/sandbox/chromium/base/file_descriptor_posix.h b/security/sandbox/chromium/base/file_descriptor_posix.h
new file mode 100644
index 0000000000..cb32dde355
--- /dev/null
+++ b/security/sandbox/chromium/base/file_descriptor_posix.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_DESCRIPTOR_POSIX_H_
+#define BASE_FILE_DESCRIPTOR_POSIX_H_
+
+#include "base/files/file.h"
+#include "base/files/scoped_file.h"
+
+namespace base {
+
+constexpr int kInvalidFd = -1;
+
+// -----------------------------------------------------------------------------
+// We introduct a special structure for file descriptors in order that we are
+// able to use template specialisation to special-case their handling.
+//
+// IMPORTANT: This is primarily intended for use when sending file descriptors
+// over IPC. Even if |auto_close| is true, base::FileDescriptor does NOT close()
+// |fd| when going out of scope. Instead, a consumer of a base::FileDescriptor
+// must invoke close() on |fd| if |auto_close| is true.
+//
+// In the case of IPC, the the IPC subsystem knows to close() |fd| after sending
+// a message that contains a base::FileDescriptor if auto_close == true. On the
+// other end, the receiver must make sure to close() |fd| after it has finished
+// processing the IPC message. See the IPC::ParamTraits<> specialization in
+// ipc/ipc_message_utils.h for all the details.
+// -----------------------------------------------------------------------------
+struct FileDescriptor {
+ FileDescriptor() : fd(kInvalidFd), auto_close(false) {}
+
+ FileDescriptor(int ifd, bool iauto_close) : fd(ifd), auto_close(iauto_close) {
+ }
+
+ FileDescriptor(File file) : fd(file.TakePlatformFile()), auto_close(true) {}
+ explicit FileDescriptor(ScopedFD fd) : fd(fd.release()), auto_close(true) {}
+
+ bool operator==(const FileDescriptor& other) const {
+ return (fd == other.fd && auto_close == other.auto_close);
+ }
+
+ bool operator!=(const FileDescriptor& other) const {
+ return !operator==(other);
+ }
+
+ // A comparison operator so that we can use these as keys in a std::map.
+ bool operator<(const FileDescriptor& other) const {
+ return other.fd < fd;
+ }
+
+ int fd;
+ // If true, this file descriptor should be closed after it has been used. For
+ // example an IPC system might interpret this flag as indicating that the
+ // file descriptor it has been given should be closed after use.
+ bool auto_close;
+};
+
+} // namespace base
+
+#endif // BASE_FILE_DESCRIPTOR_POSIX_H_
diff --git a/security/sandbox/chromium/base/files/file_path.h b/security/sandbox/chromium/base/files/file_path.h
new file mode 100644
index 0000000000..4e23f71a92
--- /dev/null
+++ b/security/sandbox/chromium/base/files/file_path.h
@@ -0,0 +1,484 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// FilePath is a container for pathnames stored in a platform's native string
+// type, providing containers for manipulation in according with the
+// platform's conventions for pathnames. It supports the following path
+// types:
+//
+// POSIX Windows
+// --------------- ----------------------------------
+// Fundamental type char[] wchar_t[]
+// Encoding unspecified* UTF-16
+// Separator / \, tolerant of /
+// Drive letters no case-insensitive A-Z followed by :
+// Alternate root // (surprise!) \\, for UNC paths
+//
+// * The encoding need not be specified on POSIX systems, although some
+// POSIX-compliant systems do specify an encoding. Mac OS X uses UTF-8.
+// Chrome OS also uses UTF-8.
+// Linux does not specify an encoding, but in practice, the locale's
+// character set may be used.
+//
+// For more arcane bits of path trivia, see below.
+//
+// FilePath objects are intended to be used anywhere paths are. An
+// application may pass FilePath objects around internally, masking the
+// underlying differences between systems, only differing in implementation
+// where interfacing directly with the system. For example, a single
+// OpenFile(const FilePath &) function may be made available, allowing all
+// callers to operate without regard to the underlying implementation. On
+// POSIX-like platforms, OpenFile might wrap fopen, and on Windows, it might
+// wrap _wfopen_s, perhaps both by calling file_path.value().c_str(). This
+// allows each platform to pass pathnames around without requiring conversions
+// between encodings, which has an impact on performance, but more imporantly,
+// has an impact on correctness on platforms that do not have well-defined
+// encodings for pathnames.
+//
+// Several methods are available to perform common operations on a FilePath
+// object, such as determining the parent directory (DirName), isolating the
+// final path component (BaseName), and appending a relative pathname string
+// to an existing FilePath object (Append). These methods are highly
+// recommended over attempting to split and concatenate strings directly.
+// These methods are based purely on string manipulation and knowledge of
+// platform-specific pathname conventions, and do not consult the filesystem
+// at all, making them safe to use without fear of blocking on I/O operations.
+// These methods do not function as mutators but instead return distinct
+// instances of FilePath objects, and are therefore safe to use on const
+// objects. The objects themselves are safe to share between threads.
+//
+// To aid in initialization of FilePath objects from string literals, a
+// FILE_PATH_LITERAL macro is provided, which accounts for the difference
+// between char[]-based pathnames on POSIX systems and wchar_t[]-based
+// pathnames on Windows.
+//
+// As a precaution against premature truncation, paths can't contain NULs.
+//
+// Because a FilePath object should not be instantiated at the global scope,
+// instead, use a FilePath::CharType[] and initialize it with
+// FILE_PATH_LITERAL. At runtime, a FilePath object can be created from the
+// character array. Example:
+//
+// | const FilePath::CharType kLogFileName[] = FILE_PATH_LITERAL("log.txt");
+// |
+// | void Function() {
+// | FilePath log_file_path(kLogFileName);
+// | [...]
+// | }
+//
+// WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even
+// when the UI language is RTL. This means you always need to pass filepaths
+// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the
+// RTL UI.
+//
+// This is a very common source of bugs, please try to keep this in mind.
+//
+// ARCANE BITS OF PATH TRIVIA
+//
+// - A double leading slash is actually part of the POSIX standard. Systems
+// are allowed to treat // as an alternate root, as Windows does for UNC
+// (network share) paths. Most POSIX systems don't do anything special
+// with two leading slashes, but FilePath handles this case properly
+// in case it ever comes across such a system. FilePath needs this support
+// for Windows UNC paths, anyway.
+// References:
+// The Open Group Base Specifications Issue 7, sections 3.267 ("Pathname")
+// and 4.12 ("Pathname Resolution"), available at:
+// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_267
+// http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12
+//
+// - Windows treats c:\\ the same way it treats \\. This was intended to
+// allow older applications that require drive letters to support UNC paths
+// like \\server\share\path, by permitting c:\\server\share\path as an
+// equivalent. Since the OS treats these paths specially, FilePath needs
+// to do the same. Since Windows can use either / or \ as the separator,
+// FilePath treats c://, c:\\, //, and \\ all equivalently.
+// Reference:
+// The Old New Thing, "Why is a drive letter permitted in front of UNC
+// paths (sometimes)?", available at:
+// http://blogs.msdn.com/oldnewthing/archive/2005/11/22/495740.aspx
+
+#ifndef BASE_FILES_FILE_PATH_H_
+#define BASE_FILES_FILE_PATH_H_
+
+#include <stddef.h>
+
+#include <functional>
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+// Windows-style drive letter support and pathname separator characters can be
+// enabled and disabled independently, to aid testing. These #defines are
+// here so that the same setting can be used in both the implementation and
+// in the unit test.
+#if defined(OS_WIN)
+#define FILE_PATH_USES_DRIVE_LETTERS
+#define FILE_PATH_USES_WIN_SEPARATORS
+#endif // OS_WIN
+
+// To print path names portably use PRFilePath (based on PRIuS and friends from
+// C99 and format_macros.h) like this:
+// base::StringPrintf("Path is %" PRFilePath ".\n", path.value().c_str());
+#if defined(OS_WIN)
+#define PRFilePath "ls"
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#define PRFilePath "s"
+#endif // OS_WIN
+
+// Macros for string literal initialization of FilePath::CharType[].
+#if defined(OS_WIN)
+#define FILE_PATH_LITERAL(x) L##x
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#define FILE_PATH_LITERAL(x) x
+#endif // OS_WIN
+
+namespace base {
+
+class Pickle;
+class PickleIterator;
+
+// An abstraction to isolate users from the differences between native
+// pathnames on different platforms.
+class BASE_EXPORT FilePath {
+ public:
+#if defined(OS_WIN)
+ // On Windows, for Unicode-aware applications, native pathnames are wchar_t
+ // arrays encoded in UTF-16.
+ typedef std::wstring StringType;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // On most platforms, native pathnames are char arrays, and the encoding
+ // may or may not be specified. On Mac OS X, native pathnames are encoded
+ // in UTF-8.
+ typedef std::string StringType;
+#endif // OS_WIN
+
+ typedef BasicStringPiece<StringType> StringPieceType;
+ typedef StringType::value_type CharType;
+
+ // Null-terminated array of separators used to separate components in
+ // hierarchical paths. Each character in this array is a valid separator,
+ // but kSeparators[0] is treated as the canonical separator and will be used
+ // when composing pathnames.
+ static const CharType kSeparators[];
+
+ // base::size(kSeparators).
+ static const size_t kSeparatorsLength;
+
+ // A special path component meaning "this directory."
+ static const CharType kCurrentDirectory[];
+
+ // A special path component meaning "the parent directory."
+ static const CharType kParentDirectory[];
+
+ // The character used to identify a file extension.
+ static const CharType kExtensionSeparator;
+
+ FilePath();
+ FilePath(const FilePath& that);
+ explicit FilePath(StringPieceType path);
+ ~FilePath();
+ FilePath& operator=(const FilePath& that);
+
+ // Constructs FilePath with the contents of |that|, which is left in valid but
+ // unspecified state.
+ FilePath(FilePath&& that) noexcept;
+ // Replaces the contents with those of |that|, which is left in valid but
+ // unspecified state.
+ FilePath& operator=(FilePath&& that);
+
+ bool operator==(const FilePath& that) const;
+
+ bool operator!=(const FilePath& that) const;
+
+ // Required for some STL containers and operations
+ bool operator<(const FilePath& that) const {
+ return path_ < that.path_;
+ }
+
+ const StringType& value() const { return path_; }
+
+ bool empty() const { return path_.empty(); }
+
+ void clear() { path_.clear(); }
+
+ // Returns true if |character| is in kSeparators.
+ static bool IsSeparator(CharType character);
+
+ // Returns a vector of all of the components of the provided path. It is
+ // equivalent to calling DirName().value() on the path's root component,
+ // and BaseName().value() on each child component.
+ //
+ // To make sure this is lossless so we can differentiate absolute and
+ // relative paths, the root slash will be included even though no other
+ // slashes will be. The precise behavior is:
+ //
+ // Posix: "/foo/bar" -> [ "/", "foo", "bar" ]
+ // Windows: "C:\foo\bar" -> [ "C:", "\\", "foo", "bar" ]
+ void GetComponents(std::vector<FilePath::StringType>* components) const;
+
+ // Returns true if this FilePath is a parent or ancestor of the |child|.
+ // Absolute and relative paths are accepted i.e. /foo is a parent to /foo/bar,
+ // and foo is a parent to foo/bar. Any ancestor is considered a parent i.e. /a
+ // is a parent to both /a/b and /a/b/c. Does not convert paths to absolute,
+ // follow symlinks or directory navigation (e.g. ".."). A path is *NOT* its
+ // own parent.
+ bool IsParent(const FilePath& child) const;
+
+ // If IsParent(child) holds, appends to path (if non-NULL) the
+ // relative path to child and returns true. For example, if parent
+ // holds "/Users/johndoe/Library/Application Support", child holds
+ // "/Users/johndoe/Library/Application Support/Google/Chrome/Default", and
+ // *path holds "/Users/johndoe/Library/Caches", then after
+ // parent.AppendRelativePath(child, path) is called *path will hold
+ // "/Users/johndoe/Library/Caches/Google/Chrome/Default". Otherwise,
+ // returns false.
+ bool AppendRelativePath(const FilePath& child, FilePath* path) const;
+
+ // Returns a FilePath corresponding to the directory containing the path
+ // named by this object, stripping away the file component. If this object
+ // only contains one component, returns a FilePath identifying
+ // kCurrentDirectory. If this object already refers to the root directory,
+ // returns a FilePath identifying the root directory. Please note that this
+ // doesn't resolve directory navigation, e.g. the result for "../a" is "..".
+ FilePath DirName() const WARN_UNUSED_RESULT;
+
+ // Returns a FilePath corresponding to the last path component of this
+ // object, either a file or a directory. If this object already refers to
+ // the root directory, returns a FilePath identifying the root directory;
+ // this is the only situation in which BaseName will return an absolute path.
+ FilePath BaseName() const WARN_UNUSED_RESULT;
+
+ // Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if
+ // the file has no extension. If non-empty, Extension() will always start
+ // with precisely one ".". The following code should always work regardless
+ // of the value of path. For common double-extensions like .tar.gz and
+ // .user.js, this method returns the combined extension. For a single
+ // component, use FinalExtension().
+ // new_path = path.RemoveExtension().value().append(path.Extension());
+ // ASSERT(new_path == path.value());
+ // NOTE: this is different from the original file_util implementation which
+ // returned the extension without a leading "." ("jpg" instead of ".jpg")
+ StringType Extension() const WARN_UNUSED_RESULT;
+
+ // Returns the path's file extension, as in Extension(), but will
+ // never return a double extension.
+ //
+ // TODO(davidben): Check all our extension-sensitive code to see if
+ // we can rename this to Extension() and the other to something like
+ // LongExtension(), defaulting to short extensions and leaving the
+ // long "extensions" to logic like base::GetUniquePathNumber().
+ StringType FinalExtension() const WARN_UNUSED_RESULT;
+
+ // Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
+ // NOTE: this is slightly different from the similar file_util implementation
+ // which returned simply 'jojo'.
+ FilePath RemoveExtension() const WARN_UNUSED_RESULT;
+
+ // Removes the path's file extension, as in RemoveExtension(), but
+ // ignores double extensions.
+ FilePath RemoveFinalExtension() const WARN_UNUSED_RESULT;
+
+ // Inserts |suffix| after the file name portion of |path| but before the
+ // extension. Returns "" if BaseName() == "." or "..".
+ // Examples:
+ // path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg"
+ // path == "jojo.jpg" suffix == " (1)", returns "jojo (1).jpg"
+ // path == "C:\pics\jojo" suffix == " (1)", returns "C:\pics\jojo (1)"
+ // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
+ FilePath InsertBeforeExtension(
+ StringPieceType suffix) const WARN_UNUSED_RESULT;
+ FilePath InsertBeforeExtensionASCII(
+ StringPiece suffix) const WARN_UNUSED_RESULT;
+
+ // Adds |extension| to |file_name|. Returns the current FilePath if
+ // |extension| is empty. Returns "" if BaseName() == "." or "..".
+ FilePath AddExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
+
+ // Like above, but takes the extension as an ASCII string. See AppendASCII for
+ // details on how this is handled.
+ FilePath AddExtensionASCII(StringPiece extension) const WARN_UNUSED_RESULT;
+
+ // Replaces the extension of |file_name| with |extension|. If |file_name|
+ // does not have an extension, then |extension| is added. If |extension| is
+ // empty, then the extension is removed from |file_name|.
+ // Returns "" if BaseName() == "." or "..".
+ FilePath ReplaceExtension(StringPieceType extension) const WARN_UNUSED_RESULT;
+
+ // Returns true if the file path matches the specified extension. The test is
+ // case insensitive. Don't forget the leading period if appropriate.
+ bool MatchesExtension(StringPieceType extension) const;
+
+ // Returns a FilePath by appending a separator and the supplied path
+ // component to this object's path. Append takes care to avoid adding
+ // excessive separators if this object's path already ends with a separator.
+ // If this object's path is kCurrentDirectory, a new FilePath corresponding
+ // only to |component| is returned. |component| must be a relative path;
+ // it is an error to pass an absolute path.
+ FilePath Append(StringPieceType component) const WARN_UNUSED_RESULT;
+ FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
+
+ // Although Windows StringType is std::wstring, since the encoding it uses for
+ // paths is well defined, it can handle ASCII path components as well.
+ // Mac uses UTF8, and since ASCII is a subset of that, it works there as well.
+ // On Linux, although it can use any 8-bit encoding for paths, we assume that
+ // ASCII is a valid subset, regardless of the encoding, since many operating
+ // system paths will always be ASCII.
+ FilePath AppendASCII(StringPiece component) const WARN_UNUSED_RESULT;
+
+ // Returns true if this FilePath contains an absolute path. On Windows, an
+ // absolute path begins with either a drive letter specification followed by
+ // a separator character, or with two separator characters. On POSIX
+ // platforms, an absolute path begins with a separator character.
+ bool IsAbsolute() const;
+
+ // Returns true if the patch ends with a path separator character.
+ bool EndsWithSeparator() const WARN_UNUSED_RESULT;
+
+ // Returns a copy of this FilePath that ends with a trailing separator. If
+ // the input path is empty, an empty FilePath will be returned.
+ FilePath AsEndingWithSeparator() const WARN_UNUSED_RESULT;
+
+ // Returns a copy of this FilePath that does not end with a trailing
+ // separator.
+ FilePath StripTrailingSeparators() const WARN_UNUSED_RESULT;
+
+ // Returns true if this FilePath contains an attempt to reference a parent
+ // directory (e.g. has a path component that is "..").
+ bool ReferencesParent() const;
+
+ // Return a Unicode human-readable version of this path.
+ // Warning: you can *not*, in general, go from a display name back to a real
+ // path. Only use this when displaying paths to users, not just when you
+ // want to stuff a string16 into some other API.
+ string16 LossyDisplayName() const;
+
+ // Return the path as ASCII, or the empty string if the path is not ASCII.
+ // This should only be used for cases where the FilePath is representing a
+ // known-ASCII filename.
+ std::string MaybeAsASCII() const;
+
+ // Return the path as UTF-8.
+ //
+ // This function is *unsafe* as there is no way to tell what encoding is
+ // used in file names on POSIX systems other than Mac and Chrome OS,
+ // although UTF-8 is practically used everywhere these days. To mitigate
+ // the encoding issue, this function internally calls
+ // SysNativeMBToWide() on POSIX systems other than Mac and Chrome OS,
+ // per assumption that the current locale's encoding is used in file
+ // names, but this isn't a perfect solution.
+ //
+ // Once it becomes safe to to stop caring about non-UTF-8 file names,
+ // the SysNativeMBToWide() hack will be removed from the code, along
+ // with "Unsafe" in the function name.
+ std::string AsUTF8Unsafe() const;
+
+ // Similar to AsUTF8Unsafe, but returns UTF-16 instead.
+ string16 AsUTF16Unsafe() const;
+
+ // Returns a FilePath object from a path name in UTF-8. This function
+ // should only be used for cases where you are sure that the input
+ // string is UTF-8.
+ //
+ // Like AsUTF8Unsafe(), this function is unsafe. This function
+ // internally calls SysWideToNativeMB() on POSIX systems other than Mac
+ // and Chrome OS, to mitigate the encoding issue. See the comment at
+ // AsUTF8Unsafe() for details.
+ static FilePath FromUTF8Unsafe(StringPiece utf8);
+
+ // Similar to FromUTF8Unsafe, but accepts UTF-16 instead.
+ static FilePath FromUTF16Unsafe(StringPiece16 utf16);
+
+ void WriteToPickle(Pickle* pickle) const;
+ bool ReadFromPickle(PickleIterator* iter);
+
+ // Normalize all path separators to backslash on Windows
+ // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
+ FilePath NormalizePathSeparators() const;
+
+ // Normalize all path separattors to given type on Windows
+ // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
+ FilePath NormalizePathSeparatorsTo(CharType separator) const;
+
+ // Compare two strings in the same way the file system does.
+ // Note that these always ignore case, even on file systems that are case-
+ // sensitive. If case-sensitive comparison is ever needed, add corresponding
+ // methods here.
+ // The methods are written as a static method so that they can also be used
+ // on parts of a file path, e.g., just the extension.
+ // CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and
+ // greater-than respectively.
+ static int CompareIgnoreCase(StringPieceType string1,
+ StringPieceType string2);
+ static bool CompareEqualIgnoreCase(StringPieceType string1,
+ StringPieceType string2) {
+ return CompareIgnoreCase(string1, string2) == 0;
+ }
+ static bool CompareLessIgnoreCase(StringPieceType string1,
+ StringPieceType string2) {
+ return CompareIgnoreCase(string1, string2) < 0;
+ }
+
+#if defined(OS_MACOSX)
+ // Returns the string in the special canonical decomposed form as defined for
+ // HFS, which is close to, but not quite, decomposition form D. See
+ // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
+ // for further comments.
+ // Returns the epmty string if the conversion failed.
+ static StringType GetHFSDecomposedForm(StringPieceType string);
+
+ // Special UTF-8 version of FastUnicodeCompare. Cf:
+ // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+ // IMPORTANT: The input strings must be in the special HFS decomposed form!
+ // (cf. above GetHFSDecomposedForm method)
+ static int HFSFastUnicodeCompare(StringPieceType string1,
+ StringPieceType string2);
+#endif
+
+#if defined(OS_ANDROID)
+ // On android, file selection dialog can return a file with content uri
+ // scheme(starting with content://). Content uri needs to be opened with
+ // ContentResolver to guarantee that the app has appropriate permissions
+ // to access it.
+ // Returns true if the path is a content uri, or false otherwise.
+ bool IsContentUri() const;
+#endif
+
+ private:
+ // Remove trailing separators from this object. If the path is absolute, it
+ // will never be stripped any more than to refer to the absolute root
+ // directory, so "////" will become "/", not "". A leading pair of
+ // separators is never stripped, to support alternate roots. This is used to
+ // support UNC paths on Windows.
+ void StripTrailingSeparatorsInternal();
+
+ StringType path_;
+};
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& out,
+ const FilePath& file_path);
+
+} // namespace base
+
+namespace std {
+
+template <>
+struct hash<base::FilePath> {
+ typedef base::FilePath argument_type;
+ typedef std::size_t result_type;
+ result_type operator()(argument_type const& f) const {
+ return hash<base::FilePath::StringType>()(f.value());
+ }
+};
+
+} // namespace std
+
+#endif // BASE_FILES_FILE_PATH_H_
diff --git a/security/sandbox/chromium/base/files/file_path_constants.cc b/security/sandbox/chromium/base/files/file_path_constants.cc
new file mode 100644
index 0000000000..d2d8d31fe1
--- /dev/null
+++ b/security/sandbox/chromium/base/files/file_path_constants.cc
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include "base/files/file_path.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
+#else // FILE_PATH_USES_WIN_SEPARATORS
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
+#endif // FILE_PATH_USES_WIN_SEPARATORS
+
+const size_t FilePath::kSeparatorsLength = base::size(kSeparators);
+
+const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
+const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
+
+const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/format_macros.h b/security/sandbox/chromium/base/format_macros.h
new file mode 100644
index 0000000000..1279ff7816
--- /dev/null
+++ b/security/sandbox/chromium/base/format_macros.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FORMAT_MACROS_H_
+#define BASE_FORMAT_MACROS_H_
+
+// This file defines the format macros for some integer types.
+
+// To print a 64-bit value in a portable way:
+// int64_t value;
+// printf("xyz:%" PRId64, value);
+// The "d" in the macro corresponds to %d; you can also use PRIu64 etc.
+//
+// For wide strings, prepend "Wide" to the macro:
+// int64_t value;
+// StringPrintf(L"xyz: %" WidePRId64, value);
+//
+// To print a size_t value in a portable way:
+// size_t size;
+// printf("xyz: %" PRIuS, size);
+// The "u" in the macro corresponds to %u, and S is for "size".
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "build/build_config.h"
+
+#if (defined(OS_POSIX) || defined(OS_FUCHSIA)) && \
+ (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && !defined(PRId64)
+#error "inttypes.h has already been included before this header file, but "
+#error "without __STDC_FORMAT_MACROS defined."
+#endif
+
+#if (defined(OS_POSIX) || defined(OS_FUCHSIA)) && !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <inttypes.h>
+
+#if defined(OS_WIN)
+
+#if !defined(PRId64) || !defined(PRIu64) || !defined(PRIx64)
+#error "inttypes.h provided by win toolchain should define these."
+#endif
+
+#define WidePRId64 L"I64d"
+#define WidePRIu64 L"I64u"
+#define WidePRIx64 L"I64x"
+
+#if !defined(PRIuS)
+#define PRIuS "Iu"
+#endif
+
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+
+// GCC will concatenate wide and narrow strings correctly, so nothing needs to
+// be done here.
+#define WidePRId64 PRId64
+#define WidePRIu64 PRIu64
+#define WidePRIx64 PRIx64
+
+#if !defined(PRIuS)
+#define PRIuS "zu"
+#endif
+
+#endif // defined(OS_WIN)
+
+// The size of NSInteger and NSUInteger varies between 32-bit and 64-bit
+// architectures and Apple does not provides standard format macros and
+// recommends casting. This has many drawbacks, so instead define macros
+// for formatting those types.
+#if defined(OS_MACOSX)
+#if defined(ARCH_CPU_64_BITS)
+#if !defined(PRIdNS)
+#define PRIdNS "ld"
+#endif
+#if !defined(PRIuNS)
+#define PRIuNS "lu"
+#endif
+#if !defined(PRIxNS)
+#define PRIxNS "lx"
+#endif
+#else // defined(ARCH_CPU_64_BITS)
+#if !defined(PRIdNS)
+#define PRIdNS "d"
+#endif
+#if !defined(PRIuNS)
+#define PRIuNS "u"
+#endif
+#if !defined(PRIxNS)
+#define PRIxNS "x"
+#endif
+#endif
+#endif // defined(OS_MACOSX)
+
+#endif // BASE_FORMAT_MACROS_H_
diff --git a/security/sandbox/chromium/base/guid.h b/security/sandbox/chromium/base/guid.h
new file mode 100644
index 0000000000..f50d3335aa
--- /dev/null
+++ b/security/sandbox/chromium/base/guid.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_GUID_H_
+#define BASE_GUID_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Generate a 128-bit random GUID in the form of version 4 as described in
+// RFC 4122, section 4.4.
+// The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
+// where y is one of [8, 9, A, B].
+// The hexadecimal values "a" through "f" are output as lower case characters.
+//
+// A cryptographically secure random source will be used, but consider using
+// UnguessableToken for greater type-safety if GUID format is unnecessary.
+BASE_EXPORT std::string GenerateGUID();
+
+// Returns true if the input string conforms to the version 4 GUID format.
+// Note that this does NOT check if the hexadecimal values "a" through "f"
+// are in lower case characters, as Version 4 RFC says onput they're
+// case insensitive. (Use IsValidGUIDOutputString for checking if the
+// given string is valid output string)
+BASE_EXPORT bool IsValidGUID(base::StringPiece guid);
+BASE_EXPORT bool IsValidGUID(base::StringPiece16 guid);
+
+// Returns true if the input string is valid version 4 GUID output string.
+// This also checks if the hexadecimal values "a" through "f" are in lower
+// case characters.
+BASE_EXPORT bool IsValidGUIDOutputString(base::StringPiece guid);
+
+// For unit testing purposes only. Do not use outside of tests.
+BASE_EXPORT std::string RandomDataToGUIDString(const uint64_t bytes[2]);
+
+} // namespace base
+
+#endif // BASE_GUID_H_
diff --git a/security/sandbox/chromium/base/hash/hash.cc b/security/sandbox/chromium/base/hash/hash.cc
new file mode 100644
index 0000000000..c96f8bc843
--- /dev/null
+++ b/security/sandbox/chromium/base/hash/hash.cc
@@ -0,0 +1,167 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/hash/hash.h"
+
+#include "base/rand_util.h"
+#include "base/third_party/cityhash/city.h"
+#include "build/build_config.h"
+
+// Definition in base/third_party/superfasthash/superfasthash.c. (Third-party
+// code did not come with its own header file, so declaring the function here.)
+// Note: This algorithm is also in Blink under Source/wtf/StringHasher.h.
+extern "C" uint32_t SuperFastHash(const char* data, int len);
+
+namespace base {
+
+namespace {
+
+size_t FastHashImpl(base::span<const uint8_t> data) {
+ // We use the updated CityHash within our namespace (not the deprecated
+ // version from third_party/smhasher).
+#if defined(ARCH_CPU_64_BITS)
+ return base::internal::cityhash_v111::CityHash64(
+ reinterpret_cast<const char*>(data.data()), data.size());
+#else
+ return base::internal::cityhash_v111::CityHash32(
+ reinterpret_cast<const char*>(data.data()), data.size());
+#endif
+}
+
+// Implement hashing for pairs of at-most 32 bit integer values.
+// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using
+// multiply-add hashing. This algorithm, as described in
+// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in
+// eingeschränkten Branchingprogrammmodellen" by Woelfel, is:
+//
+// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
+//
+// Contact danakj@chromium.org for any questions.
+size_t HashInts32Impl(uint32_t value1, uint32_t value2) {
+ uint64_t value1_64 = value1;
+ uint64_t hash64 = (value1_64 << 32) | value2;
+
+ if (sizeof(size_t) >= sizeof(uint64_t))
+ return static_cast<size_t>(hash64);
+
+ uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
+ uint32_t shift_random = 10121U << 16;
+
+ hash64 = hash64 * odd_random + shift_random;
+ size_t high_bits =
+ static_cast<size_t>(hash64 >> (8 * (sizeof(uint64_t) - sizeof(size_t))));
+ return high_bits;
+}
+
+// Implement hashing for pairs of up-to 64-bit integer values.
+// We use the compound integer hash method to produce a 64-bit hash code, by
+// breaking the two 64-bit inputs into 4 32-bit values:
+// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
+// Then we reduce our result to 32 bits if required, similar to above.
+size_t HashInts64Impl(uint64_t value1, uint64_t value2) {
+ uint32_t short_random1 = 842304669U;
+ uint32_t short_random2 = 619063811U;
+ uint32_t short_random3 = 937041849U;
+ uint32_t short_random4 = 3309708029U;
+
+ uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
+ uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
+ uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
+ uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
+
+ uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
+ uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
+ uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
+ uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
+
+ uint64_t hash64 = product1 + product2 + product3 + product4;
+
+ if (sizeof(size_t) >= sizeof(uint64_t))
+ return static_cast<size_t>(hash64);
+
+ uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
+ uint32_t shift_random = 20591U << 16;
+
+ hash64 = hash64 * odd_random + shift_random;
+ size_t high_bits =
+ static_cast<size_t>(hash64 >> (8 * (sizeof(uint64_t) - sizeof(size_t))));
+ return high_bits;
+}
+
+// The random seed is used to perturb the output of base::FastHash() and
+// base::HashInts() so that it is only deterministic within the lifetime of a
+// process. This prevents inadvertent dependencies on the underlying
+// implementation, e.g. anything that persists the hash value and expects it to
+// be unchanging will break.
+//
+// Note: this is the same trick absl uses to generate a random seed. This is
+// more robust than using base::RandBytes(), which can fail inside a sandboxed
+// environment. Note that without ASLR, the seed won't be quite as random...
+#if DCHECK_IS_ON()
+constexpr const void* kSeed = &kSeed;
+#endif
+
+template <typename T>
+T Scramble(T input) {
+#if DCHECK_IS_ON()
+ return HashInts64Impl(input, reinterpret_cast<uintptr_t>(kSeed));
+#else
+ return input;
+#endif
+}
+
+} // namespace
+
+size_t FastHash(base::span<const uint8_t> data) {
+ return Scramble(FastHashImpl(data));
+}
+
+uint32_t Hash(const void* data, size_t length) {
+ // Currently our in-memory hash is the same as the persistent hash. The
+ // split between in-memory and persistent hash functions is maintained to
+ // allow the in-memory hash function to be updated in the future.
+ return PersistentHash(data, length);
+}
+
+uint32_t Hash(const std::string& str) {
+ return PersistentHash(as_bytes(make_span(str)));
+}
+
+uint32_t Hash(const string16& str) {
+ return PersistentHash(as_bytes(make_span(str)));
+}
+
+uint32_t PersistentHash(span<const uint8_t> data) {
+ // This hash function must not change, since it is designed to be persistable
+ // to disk.
+ if (data.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
+ NOTREACHED();
+ return 0;
+ }
+ return ::SuperFastHash(reinterpret_cast<const char*>(data.data()),
+ static_cast<int>(data.size()));
+}
+
+uint32_t PersistentHash(const void* data, size_t length) {
+ return PersistentHash(make_span(static_cast<const uint8_t*>(data), length));
+}
+
+uint32_t PersistentHash(const std::string& str) {
+ return PersistentHash(str.data(), str.size());
+}
+
+size_t HashInts32(uint32_t value1, uint32_t value2) {
+ return Scramble(HashInts32Impl(value1, value2));
+}
+
+// Implement hashing for pairs of up-to 64-bit integer values.
+// We use the compound integer hash method to produce a 64-bit hash code, by
+// breaking the two 64-bit inputs into 4 32-bit values:
+// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
+// Then we reduce our result to 32 bits if required, similar to above.
+size_t HashInts64(uint64_t value1, uint64_t value2) {
+ return Scramble(HashInts64Impl(value1, value2));
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/hash/hash.h b/security/sandbox/chromium/base/hash/hash.h
new file mode 100644
index 0000000000..f55ae45b38
--- /dev/null
+++ b/security/sandbox/chromium/base/hash/hash.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_HASH_HASH_H_
+#define BASE_HASH_HASH_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <string>
+#include <utility>
+
+#include "base/base_export.h"
+#include "base/containers/span.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// WARNING: This hash functions should not be used for any cryptographic
+// purpose.
+
+// Deprecated: Computes a hash of a memory buffer, use FastHash() instead.
+// If you need to persist a change on disk or between computers, use
+// PersistentHash().
+// TODO(https://crbug.com/1025358): Migrate client code to new hash function.
+BASE_EXPORT uint32_t Hash(const void* data, size_t length);
+BASE_EXPORT uint32_t Hash(const std::string& str);
+BASE_EXPORT uint32_t Hash(const string16& str);
+
+// Really *fast* and high quality hash.
+// Recommended hash function for general use, we pick the best performant
+// hash for each build target.
+// It is prone to be updated whenever a newer/faster hash function is
+// publicly available.
+// May changed without warning, do not expect stability of outputs.
+BASE_EXPORT size_t FastHash(base::span<const uint8_t> data);
+inline size_t FastHash(StringPiece str) {
+ return FastHash(as_bytes(make_span(str)));
+}
+
+// Computes a hash of a memory buffer. This hash function must not change so
+// that code can use the hashed values for persistent storage purposes or
+// sending across the network. If a new persistent hash function is desired, a
+// new version will have to be added in addition.
+//
+// WARNING: This hash function should not be used for any cryptographic purpose.
+BASE_EXPORT uint32_t PersistentHash(base::span<const uint8_t> data);
+BASE_EXPORT uint32_t PersistentHash(const void* data, size_t length);
+BASE_EXPORT uint32_t PersistentHash(const std::string& str);
+
+// Hash pairs of 32-bit or 64-bit numbers.
+BASE_EXPORT size_t HashInts32(uint32_t value1, uint32_t value2);
+BASE_EXPORT size_t HashInts64(uint64_t value1, uint64_t value2);
+
+template <typename T1, typename T2>
+inline size_t HashInts(T1 value1, T2 value2) {
+ // This condition is expected to be compile-time evaluated and optimised away
+ // in release builds.
+ if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
+ return HashInts64(value1, value2);
+
+ return HashInts32(static_cast<uint32_t>(value1),
+ static_cast<uint32_t>(value2));
+}
+
+// A templated hasher for pairs of integer types. Example:
+//
+// using MyPair = std::pair<int32_t, int32_t>;
+// std::unordered_set<MyPair, base::IntPairHash<MyPair>> set;
+template <typename T>
+struct IntPairHash;
+
+template <typename Type1, typename Type2>
+struct IntPairHash<std::pair<Type1, Type2>> {
+ size_t operator()(std::pair<Type1, Type2> value) const {
+ return HashInts(value.first, value.second);
+ }
+};
+
+} // namespace base
+
+#endif // BASE_HASH_HASH_H_
diff --git a/security/sandbox/chromium/base/immediate_crash.h b/security/sandbox/chromium/base/immediate_crash.h
new file mode 100644
index 0000000000..733110a7ac
--- /dev/null
+++ b/security/sandbox/chromium/base/immediate_crash.h
@@ -0,0 +1,168 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IMMEDIATE_CRASH_H_
+#define BASE_IMMEDIATE_CRASH_H_
+
+#include "build/build_config.h"
+
+// Crashes in the fastest possible way with no attempt at logging.
+// There are several constraints; see http://crbug.com/664209 for more context.
+//
+// - TRAP_SEQUENCE_() must be fatal. It should not be possible to ignore the
+// resulting exception or simply hit 'continue' to skip over it in a debugger.
+// - Different instances of TRAP_SEQUENCE_() must not be folded together, to
+// ensure crash reports are debuggable. Unlike __builtin_trap(), asm volatile
+// blocks will not be folded together.
+// Note: TRAP_SEQUENCE_() previously required an instruction with a unique
+// nonce since unlike clang, GCC folds together identical asm volatile
+// blocks.
+// - TRAP_SEQUENCE_() must produce a signal that is distinct from an invalid
+// memory access.
+// - TRAP_SEQUENCE_() must be treated as a set of noreturn instructions.
+// __builtin_unreachable() is used to provide that hint here. clang also uses
+// this as a heuristic to pack the instructions in the function epilogue to
+// improve code density.
+//
+// Additional properties that are nice to have:
+// - TRAP_SEQUENCE_() should be as compact as possible.
+// - The first instruction of TRAP_SEQUENCE_() should not change, to avoid
+// shifting crash reporting clusters. As a consequence of this, explicit
+// assembly is preferred over intrinsics.
+// Note: this last bullet point may no longer be true, and may be removed in
+// the future.
+
+// Note: TRAP_SEQUENCE Is currently split into two macro helpers due to the fact
+// that clang emits an actual instruction for __builtin_unreachable() on certain
+// platforms (see https://crbug.com/958675). In addition, the int3/bkpt/brk will
+// be removed in followups, so splitting it up like this now makes it easy to
+// land the followups.
+
+#if defined(COMPILER_GCC)
+
+#if defined(OS_NACL)
+
+// Crash report accuracy is not guaranteed on NaCl.
+#define TRAP_SEQUENCE1_() __builtin_trap()
+#define TRAP_SEQUENCE2_() asm volatile("")
+
+#elif defined(ARCH_CPU_X86_FAMILY)
+
+// TODO(https://crbug.com/958675): In theory, it should be possible to use just
+// int3. However, there are a number of crashes with SIGILL as the exception
+// code, so it seems likely that there's a signal handler that allows execution
+// to continue after SIGTRAP.
+#define TRAP_SEQUENCE1_() asm volatile("int3")
+
+#if defined(OS_MACOSX)
+// Intentionally empty: __builtin_unreachable() is always part of the sequence
+// (see IMMEDIATE_CRASH below) and already emits a ud2 on Mac.
+#define TRAP_SEQUENCE2_() asm volatile("")
+#else
+#define TRAP_SEQUENCE2_() asm volatile("ud2")
+#endif // defined(OS_MACOSX)
+
+#elif defined(ARCH_CPU_ARMEL)
+
+// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running
+// as a 32 bit userspace app on arm64. There doesn't seem to be any way to
+// cause a SIGTRAP from userspace without using a syscall (which would be a
+// problem for sandboxing).
+// TODO(https://crbug.com/958675): Remove bkpt from this sequence.
+#define TRAP_SEQUENCE1_() asm volatile("bkpt #0")
+#define TRAP_SEQUENCE2_() asm volatile("udf #0")
+
+#elif defined(ARCH_CPU_ARM64)
+
+// This will always generate a SIGTRAP on arm64.
+// TODO(https://crbug.com/958675): Remove brk from this sequence.
+#define TRAP_SEQUENCE1_() asm volatile("brk #0")
+#define TRAP_SEQUENCE2_() asm volatile("hlt #0")
+
+#else
+
+// Crash report accuracy will not be guaranteed on other architectures, but at
+// least this will crash as expected.
+#define TRAP_SEQUENCE1_() __builtin_trap()
+#define TRAP_SEQUENCE2_() asm volatile("")
+
+#endif // ARCH_CPU_*
+
+#elif defined(COMPILER_MSVC)
+
+#if !defined(__clang__)
+
+// MSVC x64 doesn't support inline asm, so use the MSVC intrinsic.
+#define TRAP_SEQUENCE1_() __debugbreak()
+#define TRAP_SEQUENCE2_()
+
+#elif defined(ARCH_CPU_ARM64)
+
+// Windows ARM64 uses "BRK #F000" as its breakpoint instruction, and
+// __debugbreak() generates that in both VC++ and clang.
+#define TRAP_SEQUENCE1_() __debugbreak()
+// Intentionally empty: __builtin_unreachable() is always part of the sequence
+// (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64,
+// https://crbug.com/958373
+#define TRAP_SEQUENCE2_() __asm volatile("")
+
+#else
+
+#define TRAP_SEQUENCE1_() asm volatile("int3")
+#define TRAP_SEQUENCE2_() asm volatile("ud2")
+
+#endif // __clang__
+
+#else
+
+#error No supported trap sequence!
+
+#endif // COMPILER_GCC
+
+#define TRAP_SEQUENCE_() \
+ do { \
+ TRAP_SEQUENCE1_(); \
+ TRAP_SEQUENCE2_(); \
+ } while (false)
+
+// CHECK() and the trap sequence can be invoked from a constexpr function.
+// This could make compilation fail on GCC, as it forbids directly using inline
+// asm inside a constexpr function. However, it allows calling a lambda
+// expression including the same asm.
+// The side effect is that the top of the stacktrace will not point to the
+// calling function, but to this anonymous lambda. This is still useful as the
+// full name of the lambda will typically include the name of the function that
+// calls CHECK() and the debugger will still break at the right line of code.
+#if !defined(COMPILER_GCC)
+
+#define WRAPPED_TRAP_SEQUENCE_() TRAP_SEQUENCE_()
+
+#else
+
+#define WRAPPED_TRAP_SEQUENCE_() \
+ do { \
+ [] { TRAP_SEQUENCE_(); }(); \
+ } while (false)
+
+#endif // !defined(COMPILER_GCC)
+
+#if defined(__clang__) || defined(COMPILER_GCC)
+
+// __builtin_unreachable() hints to the compiler that this is noreturn and can
+// be packed in the function epilogue.
+#define IMMEDIATE_CRASH() \
+ ({ \
+ WRAPPED_TRAP_SEQUENCE_(); \
+ __builtin_unreachable(); \
+ })
+
+#else
+
+// This is supporting non-chromium user of logging.h to build with MSVC, like
+// pdfium. On MSVC there is no __builtin_unreachable().
+#define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE_()
+
+#endif // defined(__clang__) || defined(COMPILER_GCC)
+
+#endif // BASE_IMMEDIATE_CRASH_H_
diff --git a/security/sandbox/chromium/base/lazy_instance.h b/security/sandbox/chromium/base/lazy_instance.h
new file mode 100644
index 0000000000..4449373ead
--- /dev/null
+++ b/security/sandbox/chromium/base/lazy_instance.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DEPRECATED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// Please don't introduce new instances of LazyInstance<T>. Use a function-local
+// static of type base::NoDestructor<T> instead:
+//
+// Factory& Factory::GetInstance() {
+// static base::NoDestructor<Factory> instance;
+// return *instance;
+// }
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+// The LazyInstance<Type, Traits> class manages a single instance of Type,
+// which will be lazily created on the first time it's accessed. This class is
+// useful for places you would normally use a function-level static, but you
+// need to have guaranteed thread-safety. The Type constructor will only ever
+// be called once, even if two threads are racing to create the object. Get()
+// and Pointer() will always return the same, completely initialized instance.
+// When the instance is constructed it is registered with AtExitManager. The
+// destructor will be called on program exit.
+//
+// LazyInstance is completely thread safe, assuming that you create it safely.
+// The class was designed to be POD initialized, so it shouldn't require a
+// static constructor. It really only makes sense to declare a LazyInstance as
+// a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
+//
+// LazyInstance is similar to Singleton, except it does not have the singleton
+// property. You can have multiple LazyInstance's of the same type, and each
+// will manage a unique instance. It also preallocates the space for Type, as
+// to avoid allocating the Type instance on the heap. This may help with the
+// performance of creating the instance, and reducing heap fragmentation. This
+// requires that Type be a complete type so we can determine the size.
+//
+// Example usage:
+// static LazyInstance<MyClass>::Leaky inst = LAZY_INSTANCE_INITIALIZER;
+// void SomeMethod() {
+// inst.Get().SomeMethod(); // MyClass::SomeMethod()
+//
+// MyClass* ptr = inst.Pointer();
+// ptr->DoDoDo(); // MyClass::DoDoDo
+// }
+
+#ifndef BASE_LAZY_INSTANCE_H_
+#define BASE_LAZY_INSTANCE_H_
+
+#include <new> // For placement new.
+
+#include "base/atomicops.h"
+#include "base/debug/leak_annotations.h"
+#include "base/lazy_instance_helpers.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+// LazyInstance uses its own struct initializer-list style static
+// initialization, which does not require a constructor.
+#define LAZY_INSTANCE_INITIALIZER {}
+
+namespace base {
+
+template <typename Type>
+struct LazyInstanceTraitsBase {
+ static Type* New(void* instance) {
+ DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (alignof(Type) - 1), 0u);
+ // Use placement new to initialize our instance in our preallocated space.
+ // The parenthesis is very important here to force POD type initialization.
+ return new (instance) Type();
+ }
+
+ static void CallDestructor(Type* instance) {
+ // Explicitly call the destructor.
+ instance->~Type();
+ }
+};
+
+// We pull out some of the functionality into non-templated functions, so we
+// can implement the more complicated pieces out of line in the .cc file.
+namespace internal {
+
+// This traits class causes destruction the contained Type at process exit via
+// AtExitManager. This is probably generally not what you want. Instead, prefer
+// Leaky below.
+template <typename Type>
+struct DestructorAtExitLazyInstanceTraits {
+ static const bool kRegisterOnExit = true;
+#if DCHECK_IS_ON()
+ static const bool kAllowedToAccessOnNonjoinableThread = false;
+#endif
+
+ static Type* New(void* instance) {
+ return LazyInstanceTraitsBase<Type>::New(instance);
+ }
+
+ static void Delete(Type* instance) {
+ LazyInstanceTraitsBase<Type>::CallDestructor(instance);
+ }
+};
+
+// Use LazyInstance<T>::Leaky for a less-verbose call-site typedef; e.g.:
+// base::LazyInstance<T>::Leaky my_leaky_lazy_instance;
+// instead of:
+// base::LazyInstance<T, base::internal::LeakyLazyInstanceTraits<T> >
+// my_leaky_lazy_instance;
+// (especially when T is MyLongTypeNameImplClientHolderFactory).
+// Only use this internal::-qualified verbose form to extend this traits class
+// (depending on its implementation details).
+template <typename Type>
+struct LeakyLazyInstanceTraits {
+ static const bool kRegisterOnExit = false;
+#if DCHECK_IS_ON()
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+
+ static Type* New(void* instance) {
+ ANNOTATE_SCOPED_MEMORY_LEAK;
+ return LazyInstanceTraitsBase<Type>::New(instance);
+ }
+ static void Delete(Type* instance) {
+ }
+};
+
+template <typename Type>
+struct ErrorMustSelectLazyOrDestructorAtExitForLazyInstance {};
+
+} // namespace internal
+
+template <
+ typename Type,
+ typename Traits =
+ internal::ErrorMustSelectLazyOrDestructorAtExitForLazyInstance<Type>>
+class LazyInstance {
+ public:
+ // Do not define a destructor, as doing so makes LazyInstance a
+ // non-POD-struct. We don't want that because then a static initializer will
+ // be created to register the (empty) destructor with atexit() under MSVC, for
+ // example. We handle destruction of the contained Type class explicitly via
+ // the OnExit member function, where needed.
+ // ~LazyInstance() {}
+
+ // Convenience typedef to avoid having to repeat Type for leaky lazy
+ // instances.
+ typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type>> Leaky;
+ typedef LazyInstance<Type, internal::DestructorAtExitLazyInstanceTraits<Type>>
+ DestructorAtExit;
+
+ Type& Get() {
+ return *Pointer();
+ }
+
+ Type* Pointer() {
+#if DCHECK_IS_ON()
+ if (!Traits::kAllowedToAccessOnNonjoinableThread)
+ ThreadRestrictions::AssertSingletonAllowed();
+#endif
+
+ return subtle::GetOrCreateLazyPointer(
+ &private_instance_, &Traits::New, private_buf_,
+ Traits::kRegisterOnExit ? OnExit : nullptr, this);
+ }
+
+ // Returns true if the lazy instance has been created. Unlike Get() and
+ // Pointer(), calling IsCreated() will not instantiate the object of Type.
+ bool IsCreated() {
+ // Return true (i.e. "created") if |private_instance_| is either being
+ // created right now (i.e. |private_instance_| has value of
+ // internal::kLazyInstanceStateCreating) or was already created (i.e.
+ // |private_instance_| has any other non-zero value).
+ return 0 != subtle::NoBarrier_Load(&private_instance_);
+ }
+
+ // MSVC gives a warning that the alignment expands the size of the
+ // LazyInstance struct to make the size a multiple of the alignment. This
+ // is expected in this case.
+#if defined(OS_WIN)
+#pragma warning(push)
+#pragma warning(disable: 4324)
+#endif
+
+ // Effectively private: member data is only public to allow the linker to
+ // statically initialize it and to maintain a POD class. DO NOT USE FROM
+ // OUTSIDE THIS CLASS.
+ subtle::AtomicWord private_instance_;
+
+ // Preallocated space for the Type instance.
+ alignas(Type) char private_buf_[sizeof(Type)];
+
+#if defined(OS_WIN)
+#pragma warning(pop)
+#endif
+
+ private:
+ Type* instance() {
+ return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
+ }
+
+ // Adapter function for use with AtExit. This should be called single
+ // threaded, so don't synchronize across threads.
+ // Calling OnExit while the instance is in use by other threads is a mistake.
+ static void OnExit(void* lazy_instance) {
+ LazyInstance<Type, Traits>* me =
+ reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
+ Traits::Delete(me->instance());
+ subtle::NoBarrier_Store(&me->private_instance_, 0);
+ }
+};
+
+} // namespace base
+
+#endif // BASE_LAZY_INSTANCE_H_
diff --git a/security/sandbox/chromium/base/lazy_instance_helpers.cc b/security/sandbox/chromium/base/lazy_instance_helpers.cc
new file mode 100644
index 0000000000..7b9e0de7c6
--- /dev/null
+++ b/security/sandbox/chromium/base/lazy_instance_helpers.cc
@@ -0,0 +1,64 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/lazy_instance_helpers.h"
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+bool NeedsLazyInstance(subtle::AtomicWord* state) {
+ // Try to create the instance, if we're the first, will go from 0 to
+ // kLazyInstanceStateCreating, otherwise we've already been beaten here.
+ // The memory access has no memory ordering as state 0 and
+ // kLazyInstanceStateCreating have no associated data (memory barriers are
+ // all about ordering of memory accesses to *associated* data).
+ if (subtle::NoBarrier_CompareAndSwap(state, 0, kLazyInstanceStateCreating) ==
+ 0) {
+ // Caller must create instance
+ return true;
+ }
+
+ // It's either in the process of being created, or already created. Spin.
+ // The load has acquire memory ordering as a thread which sees
+ // state_ == STATE_CREATED needs to acquire visibility over
+ // the associated data (buf_). Pairing Release_Store is in
+ // CompleteLazyInstance().
+ if (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
+ const base::TimeTicks start = base::TimeTicks::Now();
+ do {
+ const base::TimeDelta elapsed = base::TimeTicks::Now() - start;
+ // Spin with YieldCurrentThread for at most one ms - this ensures maximum
+ // responsiveness. After that spin with Sleep(1ms) so that we don't burn
+ // excessive CPU time - this also avoids infinite loops due to priority
+ // inversions (https://crbug.com/797129).
+ if (elapsed < TimeDelta::FromMilliseconds(1))
+ PlatformThread::YieldCurrentThread();
+ else
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+ } while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating);
+ }
+ // Someone else created the instance.
+ return false;
+}
+
+void CompleteLazyInstance(subtle::AtomicWord* state,
+ subtle::AtomicWord new_instance,
+ void (*destructor)(void*),
+ void* destructor_arg) {
+ // Instance is created, go from CREATING to CREATED (or reset it if
+ // |new_instance| is null). Releases visibility over |private_buf_| to
+ // readers. Pairing Acquire_Load is in NeedsLazyInstance().
+ subtle::Release_Store(state, new_instance);
+
+ // Make sure that the lazily instantiated object will get destroyed at exit.
+ if (new_instance && destructor)
+ AtExitManager::RegisterCallback(destructor, destructor_arg);
+}
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/lazy_instance_helpers.h b/security/sandbox/chromium/base/lazy_instance_helpers.h
new file mode 100644
index 0000000000..5a43d8b1f2
--- /dev/null
+++ b/security/sandbox/chromium/base/lazy_instance_helpers.h
@@ -0,0 +1,101 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LAZY_INSTANCE_INTERNAL_H_
+#define BASE_LAZY_INSTANCE_INTERNAL_H_
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+
+// Helper methods used by LazyInstance and a few other base APIs for thread-safe
+// lazy construction.
+
+namespace base {
+namespace internal {
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kLazyInstanceStateCreating means the spinlock is being held for creation.
+constexpr subtle::AtomicWord kLazyInstanceStateCreating = 1;
+
+// Helper for GetOrCreateLazyPointer(). Checks if instance needs to be created.
+// If so returns true otherwise if another thread has beat us, waits for
+// instance to be created and returns false.
+BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
+
+// Helper for GetOrCreateLazyPointer(). After creating an instance, this is
+// called to register the dtor to be called at program exit and to update the
+// atomic state to hold the |new_instance|
+BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
+ subtle::AtomicWord new_instance,
+ void (*destructor)(void*),
+ void* destructor_arg);
+
+} // namespace internal
+
+namespace subtle {
+
+// If |state| is uninitialized (zero), constructs a value using
+// |creator_func(creator_arg)|, stores it into |state| and registers
+// |destructor(destructor_arg)| to be called when the current AtExitManager goes
+// out of scope. Then, returns the value stored in |state|. It is safe to have
+// concurrent calls to this function with the same |state|. |creator_func| may
+// return nullptr if it doesn't want to create an instance anymore (e.g. on
+// shutdown), it is from then on required to return nullptr to all callers (ref.
+// StaticMemorySingletonTraits). In that case, callers need to synchronize
+// before |creator_func| may return a non-null instance again (ref.
+// StaticMemorySingletonTraits::ResurectForTesting()).
+// Implementation note on |creator_func/creator_arg|. It makes for ugly adapters
+// but it avoids redundant template instantiations (e.g. saves 27KB in
+// chrome.dll) because linker is able to fold these for multiple Types but
+// couldn't with the more advanced CreatorFunc template type which in turn
+// improves code locality (and application startup) -- ref.
+// https://chromium-review.googlesource.com/c/chromium/src/+/530984/5/base/lazy_instance.h#140,
+// worsened by https://chromium-review.googlesource.com/c/chromium/src/+/868013
+// and caught then as https://crbug.com/804034.
+template <typename Type>
+Type* GetOrCreateLazyPointer(subtle::AtomicWord* state,
+ Type* (*creator_func)(void*),
+ void* creator_arg,
+ void (*destructor)(void*),
+ void* destructor_arg) {
+ DCHECK(state);
+ DCHECK(creator_func);
+
+ // If any bit in the created mask is true, the instance has already been
+ // fully constructed.
+ constexpr subtle::AtomicWord kLazyInstanceCreatedMask =
+ ~internal::kLazyInstanceStateCreating;
+
+ // We will hopefully have fast access when the instance is already created.
+ // Since a thread sees |state| == 0 or kLazyInstanceStateCreating at most
+ // once, the load is taken out of NeedsLazyInstance() as a fast-path. The load
+ // has acquire memory ordering as a thread which sees |state| > creating needs
+ // to acquire visibility over the associated data. Pairing Release_Store is in
+ // CompleteLazyInstance().
+ subtle::AtomicWord instance = subtle::Acquire_Load(state);
+ if (!(instance & kLazyInstanceCreatedMask)) {
+ if (internal::NeedsLazyInstance(state)) {
+ // This thread won the race and is now responsible for creating the
+ // instance and storing it back into |state|.
+ instance =
+ reinterpret_cast<subtle::AtomicWord>((*creator_func)(creator_arg));
+ internal::CompleteLazyInstance(state, instance, destructor,
+ destructor_arg);
+ } else {
+ // This thread lost the race but now has visibility over the constructed
+ // instance (NeedsLazyInstance() doesn't return until the constructing
+ // thread releases the instance via CompleteLazyInstance()).
+ instance = subtle::Acquire_Load(state);
+ DCHECK(instance & kLazyInstanceCreatedMask);
+ }
+ }
+ return reinterpret_cast<Type*>(instance);
+}
+
+} // namespace subtle
+
+} // namespace base
+
+#endif // BASE_LAZY_INSTANCE_INTERNAL_H_
diff --git a/security/sandbox/chromium/base/location.cc b/security/sandbox/chromium/base/location.cc
new file mode 100644
index 0000000000..cf189341c7
--- /dev/null
+++ b/security/sandbox/chromium/base/location.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/location.h"
+
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#endif
+
+#include "base/compiler_specific.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+
+namespace base {
+
+Location::Location() = default;
+Location::Location(const Location& other) = default;
+
+Location::Location(const char* file_name, const void* program_counter)
+ : file_name_(file_name), program_counter_(program_counter) {}
+
+Location::Location(const char* function_name,
+ const char* file_name,
+ int line_number,
+ const void* program_counter)
+ : function_name_(function_name),
+ file_name_(file_name),
+ line_number_(line_number),
+ program_counter_(program_counter) {
+#if !defined(OS_NACL)
+ // The program counter should not be null except in a default constructed
+ // (empty) Location object. This value is used for identity, so if it doesn't
+ // uniquely identify a location, things will break.
+ //
+ // The program counter isn't supported in NaCl so location objects won't work
+ // properly in that context.
+ DCHECK(program_counter);
+#endif
+}
+
+std::string Location::ToString() const {
+ if (has_source_info()) {
+ return std::string(function_name_) + "@" + file_name_ + ":" +
+ NumberToString(line_number_);
+ }
+ return StringPrintf("pc:%p", program_counter_);
+}
+
+#if defined(COMPILER_MSVC)
+#define RETURN_ADDRESS() _ReturnAddress()
+#elif defined(COMPILER_GCC) && !defined(OS_NACL)
+#define RETURN_ADDRESS() \
+ __builtin_extract_return_addr(__builtin_return_address(0))
+#else
+#define RETURN_ADDRESS() nullptr
+#endif
+
+// static
+NOINLINE Location Location::CreateFromHere(const char* file_name) {
+ return Location(file_name, RETURN_ADDRESS());
+}
+
+// static
+NOINLINE Location Location::CreateFromHere(const char* function_name,
+ const char* file_name,
+ int line_number) {
+ return Location(function_name, file_name, line_number, RETURN_ADDRESS());
+}
+
+#if SUPPORTS_LOCATION_BUILTINS && BUILDFLAG(ENABLE_LOCATION_SOURCE)
+// static
+NOINLINE Location Location::Current(const char* function_name,
+ const char* file_name,
+ int line_number) {
+ return Location(function_name, file_name, line_number, RETURN_ADDRESS());
+}
+#elif SUPPORTS_LOCATION_BUILTINS
+// static
+NOINLINE Location Location::Current(const char* file_name) {
+ return Location(file_name, RETURN_ADDRESS());
+}
+#else
+// static
+NOINLINE Location Location::Current() {
+ return Location(nullptr, RETURN_ADDRESS());
+}
+#endif
+
+//------------------------------------------------------------------------------
+NOINLINE const void* GetProgramCounter() {
+ return RETURN_ADDRESS();
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/location.h b/security/sandbox/chromium/base/location.h
new file mode 100644
index 0000000000..bcc3ca0e14
--- /dev/null
+++ b/security/sandbox/chromium/base/location.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOCATION_H_
+#define BASE_LOCATION_H_
+
+#include <stddef.h>
+
+#include <cassert>
+#include <functional>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/debug/debugging_buildflags.h"
+#include "base/hash/hash.h"
+#include "build/build_config.h"
+
+namespace base {
+
+#if defined(__has_builtin)
+// Clang allows detection of these builtins.
+#define SUPPORTS_LOCATION_BUILTINS \
+ (__has_builtin(__builtin_FUNCTION) && __has_builtin(__builtin_FILE) && \
+ __has_builtin(__builtin_LINE))
+#elif defined(COMPILER_GCC) && __GNUC__ >= 7
+// GCC has supported these for a long time, but they point at the function
+// declaration in the case of default arguments, rather than at the call site.
+#define SUPPORTS_LOCATION_BUILTINS 1
+#else
+#define SUPPORTS_LOCATION_BUILTINS 0
+#endif
+
+// Location provides basic info where of an object was constructed, or was
+// significantly brought to life.
+class BASE_EXPORT Location {
+ public:
+ Location();
+ Location(const Location& other);
+
+ // Only initializes the file name and program counter, the source information
+ // will be null for the strings, and -1 for the line number.
+ // TODO(http://crbug.com/760702) remove file name from this constructor.
+ Location(const char* file_name, const void* program_counter);
+
+ // Constructor should be called with a long-lived char*, such as __FILE__.
+ // It assumes the provided value will persist as a global constant, and it
+ // will not make a copy of it.
+ Location(const char* function_name,
+ const char* file_name,
+ int line_number,
+ const void* program_counter);
+
+ // Comparator for hash map insertion. The program counter should uniquely
+ // identify a location.
+ bool operator==(const Location& other) const {
+ return program_counter_ == other.program_counter_;
+ }
+
+ // Returns true if there is source code location info. If this is false,
+ // the Location object only contains a program counter or is
+ // default-initialized (the program counter is also null).
+ bool has_source_info() const { return function_name_ && file_name_; }
+
+ // Will be nullptr for default initialized Location objects and when source
+ // names are disabled.
+ const char* function_name() const { return function_name_; }
+
+ // Will be nullptr for default initialized Location objects and when source
+ // names are disabled.
+ const char* file_name() const { return file_name_; }
+
+ // Will be -1 for default initialized Location objects and when source names
+ // are disabled.
+ int line_number() const { return line_number_; }
+
+ // The address of the code generating this Location object. Should always be
+ // valid except for default initialized Location objects, which will be
+ // nullptr.
+ const void* program_counter() const { return program_counter_; }
+
+ // Converts to the most user-readable form possible. If function and filename
+ // are not available, this will return "pc:<hex address>".
+ std::string ToString() const;
+
+ static Location CreateFromHere(const char* file_name);
+ static Location CreateFromHere(const char* function_name,
+ const char* file_name,
+ int line_number);
+
+#if SUPPORTS_LOCATION_BUILTINS && BUILDFLAG(ENABLE_LOCATION_SOURCE)
+ static Location Current(const char* function_name = __builtin_FUNCTION(),
+ const char* file_name = __builtin_FILE(),
+ int line_number = __builtin_LINE());
+#elif SUPPORTS_LOCATION_BUILTINS
+ static Location Current(const char* file_name = __builtin_FILE());
+#else
+ static Location Current();
+#endif
+
+ private:
+ const char* function_name_ = nullptr;
+ const char* file_name_ = nullptr;
+ int line_number_ = -1;
+ const void* program_counter_ = nullptr;
+};
+
+BASE_EXPORT const void* GetProgramCounter();
+
+// The macros defined here will expand to the current function.
+#if BUILDFLAG(ENABLE_LOCATION_SOURCE)
+
+// Full source information should be included.
+#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__func__)
+#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name) \
+ ::base::Location::CreateFromHere(function_name, __FILE__, __LINE__)
+
+#else
+
+// TODO(http://crbug.com/760702) remove the __FILE__ argument from these calls.
+#define FROM_HERE ::base::Location::CreateFromHere(__FILE__)
+#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name) \
+ ::base::Location::CreateFromHere(function_name, __FILE__, -1)
+
+#endif
+
+} // namespace base
+
+namespace std {
+
+// Specialization for using Location in hash tables.
+template <>
+struct hash<::base::Location> {
+ std::size_t operator()(const ::base::Location& loc) const {
+ const void* program_counter = loc.program_counter();
+ return base::FastHash(base::as_bytes(base::make_span(&program_counter, 1)));
+ }
+};
+
+} // namespace std
+
+#endif // BASE_LOCATION_H_
diff --git a/security/sandbox/chromium/base/logging.h b/security/sandbox/chromium/base/logging.h
new file mode 100644
index 0000000000..cb24b94833
--- /dev/null
+++ b/security/sandbox/chromium/base/logging.h
@@ -0,0 +1,1077 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOGGING_H_
+#define BASE_LOGGING_H_
+
+#include <stddef.h>
+
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <sstream>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/immediate_crash.h"
+#include "base/logging_buildflags.h"
+#include "base/macros.h"
+#include "base/scoped_clear_last_error.h"
+#include "base/strings/string_piece_forward.h"
+#include "base/template_util.h"
+#include "build/build_config.h"
+
+#if defined(OS_CHROMEOS)
+#include <cstdio>
+#endif
+
+//
+// Optional message capabilities
+// -----------------------------
+// Assertion failed messages and fatal errors are displayed in a dialog box
+// before the application exits. However, running this UI creates a message
+// loop, which causes application messages to be processed and potentially
+// dispatched to existing application windows. Since the application is in a
+// bad state when this assertion dialog is displayed, these messages may not
+// get processed and hang the dialog, or the application might go crazy.
+//
+// Therefore, it can be beneficial to display the error dialog in a separate
+// process from the main application. When the logging system needs to display
+// a fatal error dialog box, it will look for a program called
+// "DebugMessage.exe" in the same directory as the application executable. It
+// will run this application with the message as the command line, and will
+// not include the name of the application as is traditional for easier
+// parsing.
+//
+// The code for DebugMessage.exe is only one line. In WinMain, do:
+// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
+//
+// If DebugMessage.exe is not found, the logging code will use a normal
+// MessageBox, potentially causing the problems discussed above.
+
+// Instructions
+// ------------
+//
+// Make a bunch of macros for logging. The way to log things is to stream
+// things to LOG(<a particular severity level>). E.g.,
+//
+// LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can also do conditional logging:
+//
+// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// The CHECK(condition) macro is active in both debug and release builds and
+// effectively performs a LOG(FATAL) which terminates the process and
+// generates a crashdump unless a debugger is attached.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+// DLOG(INFO) << "Found cookies";
+//
+// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles. LOG_IF and development flags also work well together
+// because the code can be compiled away sometimes.
+//
+// We also have
+//
+// LOG_ASSERT(assertion);
+// DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros. They look like
+//
+// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module. For instance,
+// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
+// will cause:
+// a. VLOG(2) and lower messages to be printed from profile.{h,cc}
+// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
+// c. VLOG(3) and lower messages to be printed from files prefixed with
+// "browser"
+// d. VLOG(4) and lower messages to be printed from files under a
+// "chromeos" directory.
+// e. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character)
+// wildcards. Any pattern containing a forward or backward slash will
+// be tested against the whole pathname and not just the module.
+// E.g., "*/foo/bar/*=2" would change the logging level for all code
+// in source files under a "foo/bar" directory.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished with just VLOG(2) << ...;
+// }
+//
+// There is also a VLOG_IF "verbose level" condition macro for sample
+// cases, when some extra computation and preparation for logs is not
+// needed.
+//
+// VLOG_IF(1, (size > 1024))
+// << "I'm printed when size is more than 1024 and when you run the "
+// "program with --v=1 or more";
+//
+// We also override the standard 'assert' to use 'DLOG_ASSERT'.
+//
+// Lastly, there is:
+//
+// PLOG(ERROR) << "Couldn't do foo";
+// DPLOG(ERROR) << "Couldn't do foo";
+// PLOG_IF(ERROR, cond) << "Couldn't do foo";
+// DPLOG_IF(ERROR, cond) << "Couldn't do foo";
+// PCHECK(condition) << "Couldn't do foo";
+// DPCHECK(condition) << "Couldn't do foo";
+//
+// which append the last system error to the message in string form (taken from
+// GetLastError() on Windows and errno on POSIX).
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// There is the special severity of DFATAL, which logs FATAL in debug mode,
+// ERROR in normal mode.
+//
+// Output is of the format, for example:
+// [3816:3877:0812/234555.406952:VERBOSE1:drm_device_handle.cc(90)] Succeeded
+// authenticating /dev/dri/card0 in 0 ms with 1 attempt(s)
+//
+// The colon separated fields inside the brackets are as follows:
+// 0. An optional Logfile prefix (not included in this example)
+// 1. Process ID
+// 2. Thread ID
+// 3. The date/time of the log message, in MMDD/HHMMSS.Milliseconds format
+// 4. The log level
+// 5. The filename and line number where the log was instantiated
+//
+// Note that the visibility can be changed by setting preferences in
+// SetLogItems()
+
+namespace logging {
+
+// TODO(avi): do we want to do a unification of character types here?
+#if defined(OS_WIN)
+typedef wchar_t PathChar;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+typedef char PathChar;
+#endif
+
+// A bitmask of potential logging destinations.
+using LoggingDestination = uint32_t;
+// Specifies where logs will be written. Multiple destinations can be specified
+// with bitwise OR.
+// Unless destination is LOG_NONE, all logs with severity ERROR and above will
+// be written to stderr in addition to the specified destination.
+enum : uint32_t {
+ LOG_NONE = 0,
+ LOG_TO_FILE = 1 << 0,
+ LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1,
+ LOG_TO_STDERR = 1 << 2,
+
+ LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR,
+
+// On Windows, use a file next to the exe.
+// On POSIX platforms, where it may not even be possible to locate the
+// executable on disk, use stderr.
+// On Fuchsia, use the Fuchsia logging service.
+#if defined(OS_FUCHSIA) || defined(OS_NACL)
+ LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
+#elif defined(OS_WIN)
+ LOG_DEFAULT = LOG_TO_FILE,
+#elif defined(OS_POSIX)
+ LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR,
+#endif
+};
+
+// Indicates that the log file should be locked when being written to.
+// Unless there is only one single-threaded process that is logging to
+// the log file, the file should be locked during writes to make each
+// log output atomic. Other writers will block.
+//
+// All processes writing to the log file must have their locking set for it to
+// work properly. Defaults to LOCK_LOG_FILE.
+enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
+
+// On startup, should we delete or append to an existing log file (if any)?
+// Defaults to APPEND_TO_OLD_LOG_FILE.
+enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
+
+struct BASE_EXPORT LoggingSettings {
+ // Equivalent to logging destination enum, but allows for multiple
+ // destinations.
+ uint32_t logging_dest = LOG_DEFAULT;
+
+ // The four settings below have an effect only when LOG_TO_FILE is
+ // set in |logging_dest|.
+ const PathChar* log_file_path = nullptr;
+ LogLockingState lock_log = LOCK_LOG_FILE;
+ OldFileDeletionState delete_old = APPEND_TO_OLD_LOG_FILE;
+#if defined(OS_CHROMEOS)
+ // Contains an optional file that logs should be written to. If present,
+ // |log_file_path| will be ignored, and the logging system will take ownership
+ // of the FILE. If there's an error writing to this file, no fallback paths
+ // will be opened.
+ FILE* log_file = nullptr;
+#endif
+};
+
+// Define different names for the BaseInitLoggingImpl() function depending on
+// whether NDEBUG is defined or not so that we'll fail to link if someone tries
+// to compile logging.cc with NDEBUG but includes logging.h without defining it,
+// or vice versa.
+#if defined(NDEBUG)
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG
+#else
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG
+#endif
+
+// Implementation of the InitLogging() method declared below. We use a
+// more-specific name so we can #define it above without affecting other code
+// that has named stuff "InitLogging".
+BASE_EXPORT bool BaseInitLoggingImpl(const LoggingSettings& settings);
+
+// Sets the log file name and other global logging state. Calling this function
+// is recommended, and is normally done at the beginning of application init.
+// If you don't call it, all the flags will be initialized to their default
+// values, and there is a race condition that may leak a critical section
+// object if two threads try to do the first log at the same time.
+// See the definition of the enums above for descriptions and default values.
+//
+// The default log file is initialized to "debug.log" in the application
+// directory. You probably don't want this, especially since the program
+// directory may not be writable on an enduser's system.
+//
+// This function may be called a second time to re-direct logging (e.g after
+// loging in to a user partition), however it should never be called more than
+// twice.
+inline bool InitLogging(const LoggingSettings& settings) {
+ return BaseInitLoggingImpl(settings);
+}
+
+// Sets the log level. Anything at or above this level will be written to the
+// log file/displayed to the user (if applicable). Anything below this level
+// will be silently ignored. The log level defaults to 0 (everything is logged
+// up to level INFO) if this function is not called.
+// Note that log messages for VLOG(x) are logged at level -x, so setting
+// the min log level to negative values enables verbose logging.
+BASE_EXPORT void SetMinLogLevel(int level);
+
+// Gets the current log level.
+BASE_EXPORT int GetMinLogLevel();
+
+// Used by LOG_IS_ON to lazy-evaluate stream arguments.
+BASE_EXPORT bool ShouldCreateLogMessage(int severity);
+
+// Gets the VLOG default verbosity level.
+BASE_EXPORT int GetVlogVerbosity();
+
+// Note that |N| is the size *with* the null terminator.
+BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N);
+
+// Gets the current vlog level for the given file (usually taken from __FILE__).
+template <size_t N>
+int GetVlogLevel(const char (&file)[N]) {
+ return GetVlogLevelHelper(file, N);
+}
+
+// Sets the common items you want to be prepended to each log message.
+// process and thread IDs default to off, the timestamp defaults to on.
+// If this function is not called, logging defaults to writing the timestamp
+// only.
+BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id,
+ bool enable_timestamp, bool enable_tickcount);
+
+// Sets an optional prefix to add to each log message. |prefix| is not copied
+// and should be a raw string constant. |prefix| must only contain ASCII letters
+// to avoid confusion with PIDs and timestamps. Pass null to remove the prefix.
+// Logging defaults to no prefix.
+BASE_EXPORT void SetLogPrefix(const char* prefix);
+
+// Sets whether or not you'd like to see fatal debug messages popped up in
+// a dialog box or not.
+// Dialogs are not shown by default.
+BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
+
+// Sets the Log Assert Handler that will be used to notify of check failures.
+// Resets Log Assert Handler on object destruction.
+// The default handler shows a dialog box and then terminate the process,
+// however clients can use this function to override with their own handling
+// (e.g. a silent one for Unit Tests)
+using LogAssertHandlerFunction =
+ base::RepeatingCallback<void(const char* file,
+ int line,
+ const base::StringPiece message,
+ const base::StringPiece stack_trace)>;
+
+class BASE_EXPORT ScopedLogAssertHandler {
+ public:
+ explicit ScopedLogAssertHandler(LogAssertHandlerFunction handler);
+ ~ScopedLogAssertHandler();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedLogAssertHandler);
+};
+
+// Sets the Log Message Handler that gets passed every log message before
+// it's sent to other log destinations (if any).
+// Returns true to signal that it handled the message and the message
+// should not be sent to other log destinations.
+typedef bool (*LogMessageHandlerFunction)(int severity,
+ const char* file, int line, size_t message_start, const std::string& str);
+BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler);
+BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler();
+
+// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints
+// to Clang which control what code paths are statically analyzed,
+// and is meant to be used in conjunction with assert & assert-like functions.
+// The expression is passed straight through if analysis isn't enabled.
+//
+// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current
+// codepath and any other branching codepaths that might follow.
+#if defined(__clang_analyzer__)
+
+inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
+ return false;
+}
+
+inline constexpr bool AnalyzerAssumeTrue(bool arg) {
+ // AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is
+ // false.
+ return arg || AnalyzerNoReturn();
+}
+
+#define ANALYZER_ASSUME_TRUE(arg) logging::AnalyzerAssumeTrue(!!(arg))
+#define ANALYZER_SKIP_THIS_PATH() \
+ static_cast<void>(::logging::AnalyzerNoReturn())
+#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
+
+#else // !defined(__clang_analyzer__)
+
+#define ANALYZER_ASSUME_TRUE(arg) (arg)
+#define ANALYZER_SKIP_THIS_PATH()
+#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
+
+#endif // defined(__clang_analyzer__)
+
+typedef int LogSeverity;
+const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity
+// Note: the log severities are used to index into the array of names,
+// see log_severity_names.
+const LogSeverity LOG_INFO = 0;
+const LogSeverity LOG_WARNING = 1;
+const LogSeverity LOG_ERROR = 2;
+const LogSeverity LOG_FATAL = 3;
+const LogSeverity LOG_NUM_SEVERITIES = 4;
+
+// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode
+#if defined(NDEBUG)
+const LogSeverity LOG_DFATAL = LOG_ERROR;
+#else
+const LogSeverity LOG_DFATAL = LOG_FATAL;
+#endif
+
+// A few definitions of macros that don't generate much code. These are used
+// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
+// better to have compact code for these operations.
+#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_INFO, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_WARNING, \
+ ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_ERROR, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_FATAL, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_DFATAL, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ ::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_DCHECK, ##__VA_ARGS__)
+
+#define COMPACT_GOOGLE_LOG_INFO COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
+#define COMPACT_GOOGLE_LOG_WARNING COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
+#define COMPACT_GOOGLE_LOG_ERROR COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
+#define COMPACT_GOOGLE_LOG_FATAL COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
+#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_EX_DCHECK(LogMessage)
+
+#if defined(OS_WIN)
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
+// the Windows SDK does for consistency.
+#define ERROR 0
+#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
+// Needed for LOG_IS_ON(ERROR).
+const LogSeverity LOG_0 = LOG_ERROR;
+#endif
+
+// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
+// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
+// always fire if they fail.
+#define LOG_IS_ON(severity) \
+ (::logging::ShouldCreateLogMessage(::logging::LOG_##severity))
+
+// We don't do any caching tricks with VLOG_IS_ON() like the
+// google-glog version since it increases binary size. This means
+// that using the v-logging functions in conjunction with --vmodule
+// may be slow.
+#define VLOG_IS_ON(verboselevel) \
+ ((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
+
+// Helper macro which avoids evaluating the arguments to a stream if
+// the condition doesn't hold. Condition is evaluated once and only once.
+#define LAZY_STREAM(stream, condition) \
+ !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+
+#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_IF(severity, condition) \
+ LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+// The VLOG macros log with negative verbosities.
+#define VLOG_STREAM(verbose_level) \
+ ::logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+
+#define VLOG(verbose_level) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VLOG_IF(verbose_level, condition) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), \
+ VLOG_IS_ON(verbose_level) && (condition))
+
+#if defined (OS_WIN)
+#define VPLOG_STREAM(verbose_level) \
+ ::logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#define VPLOG_STREAM(verbose_level) \
+ ::logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define VPLOG(verbose_level) \
+ LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VPLOG_IF(verbose_level, condition) \
+ LAZY_STREAM(VPLOG_STREAM(verbose_level), \
+ VLOG_IS_ON(verbose_level) && (condition))
+
+// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
+
+#define LOG_ASSERT(condition) \
+ LOG_IF(FATAL, !(ANALYZER_ASSUME_TRUE(condition))) \
+ << "Assert failed: " #condition ". "
+
+#if defined(OS_WIN)
+#define PLOG_STREAM(severity) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#define PLOG_STREAM(severity) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define PLOG(severity) \
+ LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
+
+#define PLOG_IF(severity, condition) \
+ LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+BASE_EXPORT extern std::ostream* g_swallow_stream;
+
+// Note that g_swallow_stream is used instead of an arbitrary LOG() stream to
+// avoid the creation of an object with a non-trivial destructor (LogMessage).
+// On MSVC x86 (checked on 2015 Update 3), this causes a few additional
+// pointless instructions to be emitted even at full optimization level, even
+// though the : arm of the ternary operator is clearly never executed. Using a
+// simpler object to be &'d with Voidify() avoids these extra instructions.
+// Using a simpler POD object with a templated operator<< also works to avoid
+// these instructions. However, this causes warnings on statically defined
+// implementations of operator<<(std::ostream, ...) in some .cc files, because
+// they become defined-but-unreferenced functions. A reinterpret_cast of 0 to an
+// ostream* also is not suitable, because some compilers warn of undefined
+// behavior.
+#define EAT_STREAM_PARAMETERS \
+ true ? (void)0 \
+ : ::logging::LogMessageVoidify() & (*::logging::g_swallow_stream)
+
+// Captures the result of a CHECK_EQ (for example) and facilitates testing as a
+// boolean.
+class CheckOpResult {
+ public:
+ // |message| must be non-null if and only if the check failed.
+ constexpr CheckOpResult(std::string* message) : message_(message) {}
+ // Returns true if the check succeeded.
+ constexpr operator bool() const { return !message_; }
+ // Returns the message.
+ std::string* message() { return message_; }
+
+ private:
+ std::string* message_;
+};
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.
+//
+// We make sure CHECK et al. always evaluates their arguments, as
+// doing CHECK(FunctionWithSideEffect()) is a common idiom.
+
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
+
+// Make all CHECK functions discard their log strings to reduce code bloat, and
+// improve performance, for official release builds.
+//
+// This is not calling BreakDebugger since this is called frequently, and
+// calling an out-of-line function instead of a noreturn inline macro prevents
+// compiler optimizations.
+#define CHECK(condition) \
+ UNLIKELY(!(condition)) ? IMMEDIATE_CRASH() : EAT_STREAM_PARAMETERS
+
+// PCHECK includes the system error code, which is useful for determining
+// why the condition failed. In official builds, preserve only the error code
+// message so that it is available in crash reports. The stringified
+// condition and any additional stream parameters are dropped.
+#define PCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(FATAL), UNLIKELY(!(condition))); \
+ EAT_STREAM_PARAMETERS
+
+#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
+
+#else // !(OFFICIAL_BUILD && NDEBUG)
+
+// Do as much work as possible out of line to reduce inline code size.
+#define CHECK(condition) \
+ LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
+ !ANALYZER_ASSUME_TRUE(condition))
+
+#define PCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(FATAL), !ANALYZER_ASSUME_TRUE(condition)) \
+ << "Check failed: " #condition ". "
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+// CHECK_EQ(2, a);
+#define CHECK_OP(name, op, val1, val2) \
+ switch (0) case 0: default: \
+ if (::logging::CheckOpResult true_if_passed = \
+ ::logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2)) \
+ ; \
+ else \
+ ::logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
+
+#endif // !(OFFICIAL_BUILD && NDEBUG)
+
+// This formats a value for a failing CHECK_XX statement. Ordinarily,
+// it uses the definition for operator<<, with a few special cases below.
+template <typename T>
+inline typename std::enable_if<
+ base::internal::SupportsOstreamOperator<const T&>::value &&
+ !std::is_function<typename std::remove_pointer<T>::type>::value,
+ void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << v;
+}
+
+// Overload for types that no operator<< but do have .ToString() defined.
+template <typename T>
+inline typename std::enable_if<
+ !base::internal::SupportsOstreamOperator<const T&>::value &&
+ base::internal::SupportsToString<const T&>::value,
+ void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << v.ToString();
+}
+
+// Provide an overload for functions and function pointers. Function pointers
+// don't implicitly convert to void* but do implicitly convert to bool, so
+// without this function pointers are always printed as 1 or 0. (MSVC isn't
+// standards-conforming here and converts function pointers to regular
+// pointers, so this is a no-op for MSVC.)
+template <typename T>
+inline typename std::enable_if<
+ std::is_function<typename std::remove_pointer<T>::type>::value,
+ void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << reinterpret_cast<const void*>(v);
+}
+
+// We need overloads for enums that don't support operator<<.
+// (i.e. scoped enums where no operator<< overload was declared).
+template <typename T>
+inline typename std::enable_if<
+ !base::internal::SupportsOstreamOperator<const T&>::value &&
+ std::is_enum<T>::value,
+ void>::type
+MakeCheckOpValueString(std::ostream* os, const T& v) {
+ (*os) << static_cast<typename std::underlying_type<T>::type>(v);
+}
+
+// We need an explicit overload for std::nullptr_t.
+BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p);
+
+// Build the error message string. This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline. Caller
+// takes ownership of the returned string.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+ std::ostringstream ss;
+ ss << names << " (";
+ MakeCheckOpValueString(&ss, v1);
+ ss << " vs. ";
+ MakeCheckOpValueString(&ss, v2);
+ ss << ")";
+ std::string* msg = new std::string(ss.str());
+ return msg;
+}
+
+// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
+// in logging.cc.
+extern template BASE_EXPORT std::string* MakeCheckOpString<int, int>(
+ const int&, const int&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned long, unsigned long>(
+ const unsigned long&, const unsigned long&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned long, unsigned int>(
+ const unsigned long&, const unsigned int&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned int, unsigned long>(
+ const unsigned int&, const unsigned long&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<std::string, std::string>(
+ const std::string&, const std::string&, const char* name);
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+//
+// The checked condition is wrapped with ANALYZER_ASSUME_TRUE, which under
+// static analysis builds, blocks analysis of the current path if the
+// condition is false.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <class t1, class t2> \
+ constexpr std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+ const char* names) { \
+ if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
+ return nullptr; \
+ else \
+ return ::logging::MakeCheckOpString(v1, v2, names); \
+ } \
+ constexpr std::string* Check##name##Impl(int v1, int v2, \
+ const char* names) { \
+ if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
+ return nullptr; \
+ else \
+ return ::logging::MakeCheckOpString(v1, v2, names); \
+ }
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+DEFINE_CHECK_OP_IMPL(NE, !=)
+DEFINE_CHECK_OP_IMPL(LE, <=)
+DEFINE_CHECK_OP_IMPL(LT, < )
+DEFINE_CHECK_OP_IMPL(GE, >=)
+DEFINE_CHECK_OP_IMPL(GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() false
+#else
+#define DCHECK_IS_ON() true
+#endif
+
+// Definitions for DLOG et al.
+
+#if DCHECK_IS_ON()
+
+#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
+#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
+#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
+
+#else // DCHECK_IS_ON()
+
+// If !DCHECK_IS_ON(), we want to avoid emitting any references to |condition|
+// (which may reference a variable defined only if DCHECK_IS_ON()).
+// Contrast this with DCHECK et al., which has different behavior.
+
+#define DLOG_IS_ON(severity) false
+#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS
+#define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+
+#endif // DCHECK_IS_ON()
+
+#define DLOG(severity) \
+ LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DPLOG(severity) \
+ LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DVLOG(verboselevel) DVLOG_IF(verboselevel, true)
+
+#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, true)
+
+// Definitions for DCHECK et al.
+
+#if DCHECK_IS_ON()
+
+#if defined(DCHECK_IS_CONFIGURABLE)
+BASE_EXPORT extern LogSeverity LOG_DCHECK;
+#else
+const LogSeverity LOG_DCHECK = LOG_FATAL;
+#endif // defined(DCHECK_IS_CONFIGURABLE)
+
+#else // DCHECK_IS_ON()
+
+// There may be users of LOG_DCHECK that are enabled independently
+// of DCHECK_IS_ON(), so default to FATAL logging for those.
+const LogSeverity LOG_DCHECK = LOG_FATAL;
+
+#endif // DCHECK_IS_ON()
+
+// DCHECK et al. make sure to reference |condition| regardless of
+// whether DCHECKs are enabled; this is so that we don't get unused
+// variable warnings if the only use of a variable is in a DCHECK.
+// This behavior is different from DLOG_IF et al.
+//
+// Note that the definition of the DCHECK macros depends on whether or not
+// DCHECK_IS_ON() is true. When DCHECK_IS_ON() is false, the macros use
+// EAT_STREAM_PARAMETERS to avoid expressions that would create temporaries.
+
+#if DCHECK_IS_ON()
+
+#define DCHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \
+ << "Check failed: " #condition ". "
+#define DPCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), !ANALYZER_ASSUME_TRUE(condition)) \
+ << "Check failed: " #condition ". "
+
+#else // DCHECK_IS_ON()
+
+#define DCHECK(condition) EAT_STREAM_PARAMETERS << !(condition)
+#define DPCHECK(condition) EAT_STREAM_PARAMETERS << !(condition)
+
+#endif // DCHECK_IS_ON()
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use DCHECK_EQ et al below.
+// The 'switch' is used to prevent the 'else' from being ambiguous when the
+// macro is used in an 'if' clause such as:
+// if (a == 1)
+// DCHECK_EQ(2, a);
+#if DCHECK_IS_ON()
+
+#define DCHECK_OP(name, op, val1, val2) \
+ switch (0) case 0: default: \
+ if (::logging::CheckOpResult true_if_passed = \
+ ::logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2)) \
+ ; \
+ else \
+ ::logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \
+ true_if_passed.message()).stream()
+
+#else // DCHECK_IS_ON()
+
+// When DCHECKs aren't enabled, DCHECK_OP still needs to reference operator<<
+// overloads for |val1| and |val2| to avoid potential compiler warnings about
+// unused functions. For the same reason, it also compares |val1| and |val2|
+// using |op|.
+//
+// Note that the contract of DCHECK_EQ, etc is that arguments are only evaluated
+// once. Even though |val1| and |val2| appear twice in this version of the macro
+// expansion, this is OK, since the expression is never actually evaluated.
+#define DCHECK_OP(name, op, val1, val2) \
+ EAT_STREAM_PARAMETERS << (::logging::MakeCheckOpValueString( \
+ ::logging::g_swallow_stream, val1), \
+ ::logging::MakeCheckOpValueString( \
+ ::logging::g_swallow_stream, val2), \
+ (val1)op(val2))
+
+#endif // DCHECK_IS_ON()
+
+// Equality/Inequality checks - compare two values, and log a
+// LOG_DCHECK message including the two values when the result is not
+// as expected. The values must have operator<<(ostream, ...)
+// defined.
+//
+// You may append to the error message like so:
+// DCHECK_NE(1, 2) << "The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here. In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+// DCHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These don't compile correctly if one of the arguments is a pointer
+// and the other is NULL. In new code, prefer nullptr instead. To
+// work around this for C++98, simply static_cast NULL to the type of the
+// desired pointer.
+
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
+#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
+#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
+
+#if BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED)
+// Implement logging of NOTREACHED() as a dedicated function to get function
+// call overhead down to a minimum.
+void LogErrorNotReached(const char* file, int line);
+#define NOTREACHED() \
+ true ? ::logging::LogErrorNotReached(__FILE__, __LINE__) \
+ : EAT_STREAM_PARAMETERS
+#else
+#define NOTREACHED() DCHECK(false)
+#endif
+
+// Redefine the standard assert to use our nice log files
+#undef assert
+#define assert(x) DLOG_ASSERT(x)
+
+// This class more or less represents a particular log message. You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though. You should use the LOG() macro (and variants thereof)
+// above.
+class BASE_EXPORT LogMessage {
+ public:
+ // Used for LOG(severity).
+ LogMessage(const char* file, int line, LogSeverity severity);
+
+ // Used for CHECK(). Implied severity = LOG_FATAL.
+ LogMessage(const char* file, int line, const char* condition);
+
+ // Used for CHECK_EQ(), etc. Takes ownership of the given string.
+ // Implied severity = LOG_FATAL.
+ LogMessage(const char* file, int line, std::string* result);
+
+ // Used for DCHECK_EQ(), etc. Takes ownership of the given string.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::string* result);
+
+ ~LogMessage();
+
+ std::ostream& stream() { return stream_; }
+
+ LogSeverity severity() { return severity_; }
+ std::string str() { return stream_.str(); }
+
+ private:
+ void Init(const char* file, int line);
+
+ LogSeverity severity_;
+ std::ostringstream stream_;
+ size_t message_start_; // Offset of the start of the message (past prefix
+ // info).
+ // The file and line information passed in to the constructor.
+ const char* file_;
+ const int line_;
+ const char* file_basename_;
+
+ // This is useful since the LogMessage class uses a lot of Win32 calls
+ // that will lose the value of GLE and the code that called the log function
+ // will have lost the thread error value when the log call returns.
+ base::internal::ScopedClearLastError last_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+ LogMessageVoidify() = default;
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) { }
+};
+
+#if defined(OS_WIN)
+typedef unsigned long SystemErrorCode;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+typedef int SystemErrorCode;
+#endif
+
+// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
+// pull in windows.h just for GetLastError() and DWORD.
+BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
+BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code);
+
+#if defined(OS_WIN)
+// Appends a formatted system message of the GetLastError() type.
+class BASE_EXPORT Win32ErrorLogMessage {
+ public:
+ Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ // Appends the error message before destructing the encapsulated class.
+ ~Win32ErrorLogMessage();
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+ SystemErrorCode err_;
+ LogMessage log_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
+};
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+// Appends a formatted system message of the errno type
+class BASE_EXPORT ErrnoLogMessage {
+ public:
+ ErrnoLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ // Appends the error message before destructing the encapsulated class.
+ ~ErrnoLogMessage();
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+ SystemErrorCode err_;
+ LogMessage log_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage);
+};
+#endif // OS_WIN
+
+// Closes the log file explicitly if open.
+// NOTE: Since the log file is opened as necessary by the action of logging
+// statements, there's no guarantee that it will stay closed
+// after this call.
+BASE_EXPORT void CloseLogFile();
+
+#if defined(OS_CHROMEOS)
+// Returns a new file handle that will write to the same destination as the
+// currently open log file. Returns nullptr if logging to a file is disabled,
+// or if opening the file failed. This is intended to be used to initialize
+// logging in child processes that are unable to open files.
+BASE_EXPORT FILE* DuplicateLogFILE();
+#endif
+
+// Async signal safe logging mechanism.
+BASE_EXPORT void RawLog(int level, const char* message);
+
+#define RAW_LOG(level, message) \
+ ::logging::RawLog(::logging::LOG_##level, message)
+
+#define RAW_CHECK(condition) \
+ do { \
+ if (!(condition)) \
+ ::logging::RawLog(::logging::LOG_FATAL, \
+ "Check failed: " #condition "\n"); \
+ } while (0)
+
+#if defined(OS_WIN)
+// Returns true if logging to file is enabled.
+BASE_EXPORT bool IsLoggingToFileEnabled();
+
+// Returns the default log file path.
+BASE_EXPORT std::wstring GetLogFileFullPath();
+#endif
+
+} // namespace logging
+
+// Note that "The behavior of a C++ program is undefined if it adds declarations
+// or definitions to namespace std or to a namespace within namespace std unless
+// otherwise specified." --C++11[namespace.std]
+//
+// We've checked that this particular definition has the intended behavior on
+// our implementations, but it's prone to breaking in the future, and please
+// don't imitate this in your own definitions without checking with some
+// standard library experts.
+namespace std {
+// These functions are provided as a convenience for logging, which is where we
+// use streams (it is against Google style to use streams in other places). It
+// is designed to allow you to emit non-ASCII Unicode strings to the log file,
+// which is normally ASCII. It is relatively slow, so try not to use it for
+// common cases. Non-ASCII characters will be converted to UTF-8 by these
+// operators.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
+inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
+ return out << wstr.c_str();
+}
+} // namespace std
+
+// The NOTIMPLEMENTED() macro annotates codepaths which have not been
+// implemented yet. If output spam is a serious concern,
+// NOTIMPLEMENTED_LOG_ONCE can be used.
+
+#if defined(COMPILER_GCC)
+// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
+// of the current function in the NOTIMPLEMENTED message.
+#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
+#else
+#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
+#endif
+
+#define NOTIMPLEMENTED() DLOG(ERROR) << NOTIMPLEMENTED_MSG
+#define NOTIMPLEMENTED_LOG_ONCE() \
+ do { \
+ static bool logged_once = false; \
+ DLOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG; \
+ logged_once = true; \
+ } while (0); \
+ EAT_STREAM_PARAMETERS
+
+#endif // BASE_LOGGING_H_
diff --git a/security/sandbox/chromium/base/macros.h b/security/sandbox/chromium/base/macros.h
new file mode 100644
index 0000000000..c67bdbd987
--- /dev/null
+++ b/security/sandbox/chromium/base/macros.h
@@ -0,0 +1,48 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains macros and macro-like constructs (e.g., templates) that
+// are commonly used throughout Chromium source. (It may also contain things
+// that are closely related to things that are commonly used that belong in this
+// file.)
+
+#ifndef BASE_MACROS_H_
+#define BASE_MACROS_H_
+
+// ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE.
+// Use explicit deletions instead. See the section on copyability/movability in
+// //styleguide/c++/c++-dos-and-donts.md for more information.
+
+// Put this in the declarations for a class to be uncopyable.
+#define DISALLOW_COPY(TypeName) \
+ TypeName(const TypeName&) = delete
+
+// Put this in the declarations for a class to be unassignable.
+#define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete
+
+// Put this in the declarations for a class to be uncopyable and unassignable.
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ DISALLOW_COPY(TypeName); \
+ DISALLOW_ASSIGN(TypeName)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+// This is especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName() = delete; \
+ DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// Used to explicitly mark the return value of a function as unused. If you are
+// really sure you don't want to do anything with the return value of a function
+// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
+//
+// std::unique_ptr<MyType> my_var = ...;
+// if (TakeOwnership(my_var.get()) == SUCCESS)
+// ignore_result(my_var.release());
+//
+template<typename T>
+inline void ignore_result(const T&) {
+}
+
+#endif // BASE_MACROS_H_
diff --git a/security/sandbox/chromium/base/memory/aligned_memory.h b/security/sandbox/chromium/base/memory/aligned_memory.h
new file mode 100644
index 0000000000..a242b730be
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/aligned_memory.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
+#define BASE_MEMORY_ALIGNED_MEMORY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <type_traits>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+
+// A runtime sized aligned allocation can be created:
+//
+// float* my_array = static_cast<float*>(AlignedAlloc(size, alignment));
+//
+// // ... later, to release the memory:
+// AlignedFree(my_array);
+//
+// Or using unique_ptr:
+//
+// std::unique_ptr<float, AlignedFreeDeleter> my_array(
+// static_cast<float*>(AlignedAlloc(size, alignment)));
+
+namespace base {
+
+// This can be replaced with std::aligned_alloc when we have C++17.
+// Caveat: std::aligned_alloc requires the size parameter be an integral
+// multiple of alignment.
+BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment);
+
+inline void AlignedFree(void* ptr) {
+#if defined(COMPILER_MSVC)
+ _aligned_free(ptr);
+#else
+ free(ptr);
+#endif
+}
+
+// Deleter for use with unique_ptr. E.g., use as
+// std::unique_ptr<Foo, base::AlignedFreeDeleter> foo;
+struct AlignedFreeDeleter {
+ inline void operator()(void* ptr) const {
+ AlignedFree(ptr);
+ }
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_ALIGNED_MEMORY_H_
diff --git a/security/sandbox/chromium/base/memory/free_deleter.h b/security/sandbox/chromium/base/memory/free_deleter.h
new file mode 100644
index 0000000000..5604118865
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/free_deleter.h
@@ -0,0 +1,25 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_FREE_DELETER_H_
+#define BASE_MEMORY_FREE_DELETER_H_
+
+#include <stdlib.h>
+
+namespace base {
+
+// Function object which invokes 'free' on its parameter, which must be
+// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr:
+//
+// std::unique_ptr<int, base::FreeDeleter> foo_ptr(
+// static_cast<int*>(malloc(sizeof(int))));
+struct FreeDeleter {
+ inline void operator()(void* ptr) const {
+ free(ptr);
+ }
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_FREE_DELETER_H_
diff --git a/security/sandbox/chromium/base/memory/platform_shared_memory_region.cc b/security/sandbox/chromium/base/memory/platform_shared_memory_region.cc
new file mode 100644
index 0000000000..45647925b3
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/platform_shared_memory_region.cc
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include "base/memory/shared_memory_mapping.h"
+#include "base/numerics/checked_math.h"
+
+namespace base {
+namespace subtle {
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateWritable(
+ size_t size) {
+ return Create(Mode::kWritable, size);
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateUnsafe(
+ size_t size) {
+ return Create(Mode::kUnsafe, size);
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion() = default;
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+ PlatformSharedMemoryRegion&& other) = default;
+PlatformSharedMemoryRegion& PlatformSharedMemoryRegion::operator=(
+ PlatformSharedMemoryRegion&& other) = default;
+PlatformSharedMemoryRegion::~PlatformSharedMemoryRegion() = default;
+
+PlatformSharedMemoryRegion::ScopedPlatformHandle
+PlatformSharedMemoryRegion::PassPlatformHandle() {
+ return std::move(handle_);
+}
+
+bool PlatformSharedMemoryRegion::MapAt(off_t offset,
+ size_t size,
+ void** memory,
+ size_t* mapped_size) const {
+ if (!IsValid())
+ return false;
+
+ if (size == 0)
+ return false;
+
+ size_t end_byte;
+ if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
+ return false;
+ }
+
+ bool success = MapAtInternal(offset, size, memory, mapped_size);
+ if (success) {
+ DCHECK_EQ(
+ 0U, reinterpret_cast<uintptr_t>(*memory) & (kMapMinimumAlignment - 1));
+ }
+
+ return success;
+}
+
+} // namespace subtle
+} // namespace base
diff --git a/security/sandbox/chromium/base/memory/platform_shared_memory_region.h b/security/sandbox/chromium/base/memory/platform_shared_memory_region.h
new file mode 100644
index 0000000000..220cbdd65e
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/platform_shared_memory_region.h
@@ -0,0 +1,301 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
+#define BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
+
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach.h>
+#include "base/mac/scoped_mach_port.h"
+#elif defined(OS_FUCHSIA)
+#include <lib/zx/vmo.h>
+#elif defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_types.h"
+#elif defined(OS_POSIX)
+#include <sys/types.h>
+#include "base/file_descriptor_posix.h"
+#include "base/files/scoped_file.h"
+#endif
+
+#if defined(OS_LINUX)
+namespace content {
+class SandboxIPCHandler;
+}
+#endif
+
+namespace base {
+namespace subtle {
+
+#if defined(OS_POSIX) && (!defined(OS_MACOSX) || defined(OS_IOS)) && \
+ !defined(OS_ANDROID)
+// Helper structs to keep two descriptors on POSIX. It's needed to support
+// ConvertToReadOnly().
+struct BASE_EXPORT FDPair {
+ // The main shared memory descriptor that is used for mapping. May be either
+ // writable or read-only, depending on region's mode.
+ int fd;
+ // The read-only descriptor, valid only in kWritable mode. Replaces |fd| when
+ // a region is converted to read-only.
+ int readonly_fd;
+};
+
+struct BASE_EXPORT ScopedFDPair {
+ ScopedFDPair();
+ ScopedFDPair(ScopedFD in_fd, ScopedFD in_readonly_fd);
+ ScopedFDPair(ScopedFDPair&&);
+ ScopedFDPair& operator=(ScopedFDPair&&);
+ ~ScopedFDPair();
+
+ FDPair get() const;
+
+ ScopedFD fd;
+ ScopedFD readonly_fd;
+};
+#endif
+
+// Implementation class for shared memory regions.
+//
+// This class does the following:
+//
+// - Wraps and owns a shared memory region platform handle.
+// - Provides a way to allocate a new region of platform shared memory of given
+// size.
+// - Provides a way to create mapping of the region in the current process'
+// address space, under special access-control constraints (see Mode).
+// - Provides methods to help transferring the handle across process boundaries.
+// - Holds a 128-bit unique identifier used to uniquely identify the same
+// kernel region resource across processes (used for memory tracking).
+// - Has a method to retrieve the region's size in bytes.
+//
+// IMPORTANT NOTE: Users should never use this directly, but
+// ReadOnlySharedMemoryRegion, WritableSharedMemoryRegion or
+// UnsafeSharedMemoryRegion since this is an implementation class.
+class BASE_EXPORT PlatformSharedMemoryRegion {
+ public:
+ // Permission mode of the platform handle. Each mode corresponds to one of the
+ // typed shared memory classes:
+ //
+ // * ReadOnlySharedMemoryRegion: A region that can only create read-only
+ // mappings.
+ //
+ // * WritableSharedMemoryRegion: A region that can only create writable
+ // mappings. The region can be demoted to ReadOnlySharedMemoryRegion without
+ // the possibility of promoting back to writable.
+ //
+ // * UnsafeSharedMemoryRegion: A region that can only create writable
+ // mappings. The region cannot be demoted to ReadOnlySharedMemoryRegion.
+ enum class Mode {
+ kReadOnly, // ReadOnlySharedMemoryRegion
+ kWritable, // WritableSharedMemoryRegion
+ kUnsafe, // UnsafeSharedMemoryRegion
+ kMaxValue = kUnsafe
+ };
+
+ // Errors that can occur during Shared Memory construction.
+ // These match tools/metrics/histograms/enums.xml.
+ // This enum is append-only.
+ enum class CreateError {
+ SUCCESS = 0,
+ SIZE_ZERO = 1,
+ SIZE_TOO_LARGE = 2,
+ INITIALIZE_ACL_FAILURE = 3,
+ INITIALIZE_SECURITY_DESC_FAILURE = 4,
+ SET_SECURITY_DESC_FAILURE = 5,
+ CREATE_FILE_MAPPING_FAILURE = 6,
+ REDUCE_PERMISSIONS_FAILURE = 7,
+ ALREADY_EXISTS = 8,
+ ALLOCATE_FILE_REGION_FAILURE = 9,
+ FSTAT_FAILURE = 10,
+ INODES_MISMATCH = 11,
+ GET_SHMEM_TEMP_DIR_FAILURE = 12,
+ kMaxValue = GET_SHMEM_TEMP_DIR_FAILURE
+ };
+
+#if defined(OS_LINUX)
+ // Structure to limit access to executable region creation.
+ struct ExecutableRegion {
+ private:
+ // Creates a new shared memory region the unsafe mode (writable and not and
+ // convertible to read-only), and in addition marked executable. A ScopedFD
+ // to this region is returned. Any any mapping will have to be done
+ // manually, including setting executable permissions if necessary
+ //
+ // This is only used to support sandbox_ipc_linux.cc, and should not be used
+ // anywhere else in chrome. This is restricted via AllowCreateExecutable.
+ // TODO(crbug.com/982879): remove this when NaCl is unshipped.
+ //
+ // Returns an invalid ScopedFD if the call fails.
+ static ScopedFD CreateFD(size_t size);
+
+ friend class content::SandboxIPCHandler;
+ };
+#endif
+
+// Platform-specific shared memory type used by this class.
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ using PlatformHandle = mach_port_t;
+ using ScopedPlatformHandle = mac::ScopedMachSendRight;
+#elif defined(OS_FUCHSIA)
+ using PlatformHandle = zx::unowned_vmo;
+ using ScopedPlatformHandle = zx::vmo;
+#elif defined(OS_WIN)
+ using PlatformHandle = HANDLE;
+ using ScopedPlatformHandle = win::ScopedHandle;
+#elif defined(OS_ANDROID)
+ using PlatformHandle = int;
+ using ScopedPlatformHandle = ScopedFD;
+#else
+ using PlatformHandle = FDPair;
+ using ScopedPlatformHandle = ScopedFDPair;
+#endif
+
+ // The minimum alignment in bytes that any mapped address produced by Map()
+ // and MapAt() is guaranteed to have.
+ enum { kMapMinimumAlignment = 32 };
+
+ // Creates a new PlatformSharedMemoryRegion with corresponding mode and size.
+ // Creating in kReadOnly mode isn't supported because then there will be no
+ // way to modify memory content.
+ static PlatformSharedMemoryRegion CreateWritable(size_t size);
+ static PlatformSharedMemoryRegion CreateUnsafe(size_t size);
+
+ // Returns a new PlatformSharedMemoryRegion that takes ownership of the
+ // |handle|. All parameters must be taken from another valid
+ // PlatformSharedMemoryRegion instance, e.g. |size| must be equal to the
+ // actual region size as allocated by the kernel.
+ // Closes the |handle| and returns an invalid instance if passed parameters
+ // are invalid.
+ static PlatformSharedMemoryRegion Take(ScopedPlatformHandle handle,
+ Mode mode,
+ size_t size,
+ const UnguessableToken& guid);
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && \
+ !(defined(OS_MACOSX) && !defined(OS_IOS))
+ // Specialized version of Take() for POSIX that takes only one file descriptor
+ // instead of pair. Cannot be used with kWritable |mode|.
+ static PlatformSharedMemoryRegion Take(ScopedFD handle,
+ Mode mode,
+ size_t size,
+ const UnguessableToken& guid);
+#endif
+
+ // Default constructor initializes an invalid instance, i.e. an instance that
+ // doesn't wrap any valid platform handle.
+ PlatformSharedMemoryRegion();
+
+ // Move operations are allowed.
+ PlatformSharedMemoryRegion(PlatformSharedMemoryRegion&&);
+ PlatformSharedMemoryRegion& operator=(PlatformSharedMemoryRegion&&);
+
+ // Destructor closes the platform handle. Does nothing if the handle is
+ // invalid.
+ ~PlatformSharedMemoryRegion();
+
+ // Passes ownership of the platform handle to the caller. The current instance
+ // becomes invalid. It's the responsibility of the caller to close the
+ // handle. If the current instance is invalid, ScopedPlatformHandle will also
+ // be invalid.
+ ScopedPlatformHandle PassPlatformHandle() WARN_UNUSED_RESULT;
+
+ // Returns the platform handle. The current instance keeps ownership of this
+ // handle.
+ PlatformHandle GetPlatformHandle() const;
+
+ // Whether the platform handle is valid.
+ bool IsValid() const;
+
+ // Duplicates the platform handle and creates a new PlatformSharedMemoryRegion
+ // with the same |mode_|, |size_| and |guid_| that owns this handle. Returns
+ // invalid region on failure, the current instance remains valid.
+ // Can be called only in kReadOnly and kUnsafe modes, CHECK-fails if is
+ // called in kWritable mode.
+ PlatformSharedMemoryRegion Duplicate() const;
+
+ // Converts the region to read-only. Returns whether the operation succeeded.
+ // Makes the current instance invalid on failure. Can be called only in
+ // kWritable mode, all other modes will CHECK-fail. The object will have
+ // kReadOnly mode after this call on success.
+ bool ConvertToReadOnly();
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // Same as above, but |mapped_addr| is used as a hint to avoid additional
+ // mapping of the memory object.
+ // |mapped_addr| must be mapped location of |memory_object_|. If the location
+ // is unknown, |mapped_addr| should be |nullptr|.
+ bool ConvertToReadOnly(void* mapped_addr);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+ // Converts the region to unsafe. Returns whether the operation succeeded.
+ // Makes the current instance invalid on failure. Can be called only in
+ // kWritable mode, all other modes will CHECK-fail. The object will have
+ // kUnsafe mode after this call on success.
+ bool ConvertToUnsafe();
+
+ // Maps |size| bytes of the shared memory region starting with the given
+ // |offset| into the caller's address space. |offset| must be aligned to value
+ // of |SysInfo::VMAllocationGranularity()|. Fails if requested bytes are out
+ // of the region limits.
+ // Returns true and sets |memory| and |mapped_size| on success, returns false
+ // and leaves output parameters in unspecified state otherwise. The mapped
+ // address is guaranteed to have an alignment of at least
+ // |kMapMinimumAlignment|.
+ bool MapAt(off_t offset,
+ size_t size,
+ void** memory,
+ size_t* mapped_size) const;
+
+ const UnguessableToken& GetGUID() const { return guid_; }
+
+ size_t GetSize() const { return size_; }
+
+ Mode GetMode() const { return mode_; }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
+ CreateReadOnlyRegionDeathTest);
+ FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
+ CheckPlatformHandlePermissionsCorrespondToMode);
+ static PlatformSharedMemoryRegion Create(Mode mode,
+ size_t size
+#if defined(OS_LINUX)
+ ,
+ bool executable = false
+#endif
+ );
+
+ static bool CheckPlatformHandlePermissionsCorrespondToMode(
+ PlatformHandle handle,
+ Mode mode,
+ size_t size);
+
+ PlatformSharedMemoryRegion(ScopedPlatformHandle handle,
+ Mode mode,
+ size_t size,
+ const UnguessableToken& guid);
+
+ bool MapAtInternal(off_t offset,
+ size_t size,
+ void** memory,
+ size_t* mapped_size) const;
+
+ ScopedPlatformHandle handle_;
+ Mode mode_ = Mode::kReadOnly;
+ size_t size_ = 0;
+ UnguessableToken guid_;
+
+ DISALLOW_COPY_AND_ASSIGN(PlatformSharedMemoryRegion);
+};
+
+} // namespace subtle
+} // namespace base
+
+#endif // BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
diff --git a/security/sandbox/chromium/base/memory/platform_shared_memory_region_win.cc b/security/sandbox/chromium/base/memory/platform_shared_memory_region_win.cc
new file mode 100644
index 0000000000..c2f3704f91
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/platform_shared_memory_region_win.cc
@@ -0,0 +1,343 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/platform_shared_memory_region.h"
+
+#include <aclapi.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/allocator/partition_allocator/page_allocator.h"
+#include "base/bits.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/process/process_handle.h"
+#include "base/rand_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace subtle {
+
+namespace {
+
+// Emits UMA metrics about encountered errors. Pass zero (0) for |winerror|
+// if there is no associated Windows error.
+void LogError(PlatformSharedMemoryRegion::CreateError error, DWORD winerror) {
+ UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error);
+ static_assert(ERROR_SUCCESS == 0, "Windows error code changed!");
+ if (winerror != ERROR_SUCCESS)
+ UmaHistogramSparse("SharedMemory.CreateWinError", winerror);
+}
+
+typedef enum _SECTION_INFORMATION_CLASS {
+ SectionBasicInformation,
+} SECTION_INFORMATION_CLASS;
+
+typedef struct _SECTION_BASIC_INFORMATION {
+ PVOID BaseAddress;
+ ULONG Attributes;
+ LARGE_INTEGER Size;
+} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
+
+typedef ULONG(__stdcall* NtQuerySectionType)(
+ HANDLE SectionHandle,
+ SECTION_INFORMATION_CLASS SectionInformationClass,
+ PVOID SectionInformation,
+ ULONG SectionInformationLength,
+ PULONG ResultLength);
+
+// Returns the length of the memory section starting at the supplied address.
+size_t GetMemorySectionSize(void* address) {
+ MEMORY_BASIC_INFORMATION memory_info;
+ if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
+ return 0;
+ return memory_info.RegionSize -
+ (static_cast<char*>(address) -
+ static_cast<char*>(memory_info.AllocationBase));
+}
+
+// Checks if the section object is safe to map. At the moment this just means
+// it's not an image section.
+bool IsSectionSafeToMap(HANDLE handle) {
+ static NtQuerySectionType nt_query_section_func =
+ reinterpret_cast<NtQuerySectionType>(
+ ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
+ DCHECK(nt_query_section_func);
+
+ // The handle must have SECTION_QUERY access for this to succeed.
+ SECTION_BASIC_INFORMATION basic_information = {};
+ ULONG status =
+ nt_query_section_func(handle, SectionBasicInformation, &basic_information,
+ sizeof(basic_information), nullptr);
+ if (status)
+ return false;
+ return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
+}
+
+// Returns a HANDLE on success and |nullptr| on failure.
+// This function is similar to CreateFileMapping, but removes the permissions
+// WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE.
+//
+// A newly created file mapping has two sets of permissions. It has access
+// control permissions (WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE) and
+// file permissions (FILE_MAP_READ, FILE_MAP_WRITE, etc.). The Chrome sandbox
+// prevents HANDLEs with the WRITE_DAC permission from being duplicated into
+// unprivileged processes.
+//
+// In order to remove the access control permissions, after being created the
+// handle is duplicated with only the file access permissions.
+HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa,
+ size_t rounded_size,
+ LPCWSTR name) {
+ HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0,
+ static_cast<DWORD>(rounded_size), name);
+ if (!h) {
+ LogError(
+ PlatformSharedMemoryRegion::CreateError::CREATE_FILE_MAPPING_FAILURE,
+ GetLastError());
+ return nullptr;
+ }
+
+ HANDLE h2;
+ ProcessHandle process = GetCurrentProcess();
+ BOOL success = ::DuplicateHandle(
+ process, h, process, &h2, FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY,
+ FALSE, 0);
+ BOOL rv = ::CloseHandle(h);
+ DCHECK(rv);
+
+ if (!success) {
+ LogError(
+ PlatformSharedMemoryRegion::CreateError::REDUCE_PERMISSIONS_FAILURE,
+ GetLastError());
+ return nullptr;
+ }
+
+ return h2;
+}
+
+} // namespace
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
+ win::ScopedHandle handle,
+ Mode mode,
+ size_t size,
+ const UnguessableToken& guid) {
+ if (!handle.IsValid())
+ return {};
+
+ if (size == 0)
+ return {};
+
+ if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+ return {};
+
+ if (!IsSectionSafeToMap(handle.Get()))
+ return {};
+
+ CHECK(
+ CheckPlatformHandlePermissionsCorrespondToMode(handle.Get(), mode, size));
+
+ return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
+}
+
+HANDLE PlatformSharedMemoryRegion::GetPlatformHandle() const {
+ return handle_.Get();
+}
+
+bool PlatformSharedMemoryRegion::IsValid() const {
+ return handle_.IsValid();
+}
+
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() const {
+ if (!IsValid())
+ return {};
+
+ CHECK_NE(mode_, Mode::kWritable)
+ << "Duplicating a writable shared memory region is prohibited";
+
+ HANDLE duped_handle;
+ ProcessHandle process = GetCurrentProcess();
+ BOOL success =
+ ::DuplicateHandle(process, handle_.Get(), process, &duped_handle, 0,
+ FALSE, DUPLICATE_SAME_ACCESS);
+ if (!success)
+ return {};
+
+ return PlatformSharedMemoryRegion(win::ScopedHandle(duped_handle), mode_,
+ size_, guid_);
+}
+
+bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
+ if (!IsValid())
+ return false;
+
+ CHECK_EQ(mode_, Mode::kWritable)
+ << "Only writable shared memory region can be converted to read-only";
+
+ win::ScopedHandle handle_copy(handle_.Take());
+
+ HANDLE duped_handle;
+ ProcessHandle process = GetCurrentProcess();
+ BOOL success =
+ ::DuplicateHandle(process, handle_copy.Get(), process, &duped_handle,
+ FILE_MAP_READ | SECTION_QUERY, FALSE, 0);
+ if (!success)
+ return false;
+
+ handle_.Set(duped_handle);
+ mode_ = Mode::kReadOnly;
+ return true;
+}
+
+bool PlatformSharedMemoryRegion::ConvertToUnsafe() {
+ if (!IsValid())
+ return false;
+
+ CHECK_EQ(mode_, Mode::kWritable)
+ << "Only writable shared memory region can be converted to unsafe";
+
+ mode_ = Mode::kUnsafe;
+ return true;
+}
+
+bool PlatformSharedMemoryRegion::MapAtInternal(off_t offset,
+ size_t size,
+ void** memory,
+ size_t* mapped_size) const {
+ bool write_allowed = mode_ != Mode::kReadOnly;
+ // Try to map the shared memory. On the first failure, release any reserved
+ // address space for a single entry.
+ for (int i = 0; i < 2; ++i) {
+ *memory = MapViewOfFile(
+ handle_.Get(), FILE_MAP_READ | (write_allowed ? FILE_MAP_WRITE : 0),
+ static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), size);
+ if (*memory)
+ break;
+ ReleaseReservation();
+ }
+ if (!*memory) {
+ DPLOG(ERROR) << "Failed executing MapViewOfFile";
+ return false;
+ }
+
+ *mapped_size = GetMemorySectionSize(*memory);
+ return true;
+}
+
+// static
+PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
+ size_t size) {
+ // TODO(crbug.com/210609): NaCl forces us to round up 64k here, wasting 32k
+ // per mapping on average.
+ static const size_t kSectionSize = 65536;
+ if (size == 0) {
+ LogError(CreateError::SIZE_ZERO, 0);
+ return {};
+ }
+
+ // Aligning may overflow so check that the result doesn't decrease.
+ size_t rounded_size = bits::Align(size, kSectionSize);
+ if (rounded_size < size ||
+ rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
+ LogError(CreateError::SIZE_TOO_LARGE, 0);
+ return {};
+ }
+
+ CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
+ "lead to this region being non-modifiable";
+
+ // Add an empty DACL to enforce anonymous read-only sections.
+ ACL dacl;
+ SECURITY_DESCRIPTOR sd;
+ if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) {
+ LogError(CreateError::INITIALIZE_ACL_FAILURE, GetLastError());
+ return {};
+ }
+ if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
+ LogError(CreateError::INITIALIZE_SECURITY_DESC_FAILURE, GetLastError());
+ return {};
+ }
+ if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) {
+ LogError(CreateError::SET_SECURITY_DESC_FAILURE, GetLastError());
+ return {};
+ }
+
+ string16 name;
+ if (win::GetVersion() < win::Version::WIN8_1) {
+ // Windows < 8.1 ignores DACLs on certain unnamed objects (like shared
+ // sections). So, we generate a random name when we need to enforce
+ // read-only.
+ uint64_t rand_values[4];
+ RandBytes(&rand_values, sizeof(rand_values));
+ name = ASCIIToUTF16(StringPrintf("CrSharedMem_%016llx%016llx%016llx%016llx",
+ rand_values[0], rand_values[1],
+ rand_values[2], rand_values[3]));
+ DCHECK(!name.empty());
+ }
+
+ SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, FALSE};
+ // Ask for the file mapping with reduced permisions to avoid passing the
+ // access control permissions granted by default into unpriviledged process.
+ HANDLE h = CreateFileMappingWithReducedPermissions(
+ &sa, rounded_size, name.empty() ? nullptr : as_wcstr(name));
+ if (h == nullptr) {
+ // The error is logged within CreateFileMappingWithReducedPermissions().
+ return {};
+ }
+
+ win::ScopedHandle scoped_h(h);
+ // Check if the shared memory pre-exists.
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ LogError(CreateError::ALREADY_EXISTS, ERROR_ALREADY_EXISTS);
+ return {};
+ }
+
+ LogError(CreateError::SUCCESS, ERROR_SUCCESS);
+ return PlatformSharedMemoryRegion(std::move(scoped_h), mode, size,
+ UnguessableToken::Create());
+}
+
+// static
+bool PlatformSharedMemoryRegion::CheckPlatformHandlePermissionsCorrespondToMode(
+ PlatformHandle handle,
+ Mode mode,
+ size_t size) {
+ // Call ::DuplicateHandle() with FILE_MAP_WRITE as a desired access to check
+ // if the |handle| has a write access.
+ ProcessHandle process = GetCurrentProcess();
+ HANDLE duped_handle;
+ BOOL success = ::DuplicateHandle(process, handle, process, &duped_handle,
+ FILE_MAP_WRITE, FALSE, 0);
+ if (success) {
+ BOOL rv = ::CloseHandle(duped_handle);
+ DCHECK(rv);
+ }
+
+ bool is_read_only = !success;
+ bool expected_read_only = mode == Mode::kReadOnly;
+
+ if (is_read_only != expected_read_only) {
+ DLOG(ERROR) << "File mapping handle has wrong access rights: it is"
+ << (is_read_only ? " " : " not ") << "read-only but it should"
+ << (expected_read_only ? " " : " not ") << "be";
+ return false;
+ }
+
+ return true;
+}
+
+PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
+ win::ScopedHandle handle,
+ Mode mode,
+ size_t size,
+ const UnguessableToken& guid)
+ : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
+
+} // namespace subtle
+} // namespace base
diff --git a/security/sandbox/chromium/base/memory/ptr_util.h b/security/sandbox/chromium/base/memory/ptr_util.h
new file mode 100644
index 0000000000..42f4f49eeb
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/ptr_util.h
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_PTR_UTIL_H_
+#define BASE_MEMORY_PTR_UTIL_H_
+
+#include <memory>
+#include <utility>
+
+namespace base {
+
+// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
+// Note that std::unique_ptr<T> has very different semantics from
+// std::unique_ptr<T[]>: do not use this helper for array allocations.
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+ return std::unique_ptr<T>(ptr);
+}
+
+} // namespace base
+
+#endif // BASE_MEMORY_PTR_UTIL_H_
diff --git a/security/sandbox/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h b/security/sandbox/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
new file mode 100644
index 0000000000..ab8b2abcbb
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+
+#include <type_traits>
+
+#include "base/template_util.h"
+
+// It is dangerous to post a task with a T* argument where T is a subtype of
+// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
+// object may already have been deleted since it was not held with a
+// scoped_refptr. Example: http://crbug.com/27191
+// The following set of traits are designed to generate a compile error
+// whenever this antipattern is attempted.
+
+namespace base {
+
+// This is a base internal implementation file used by task.h and callback.h.
+// Not for public consumption, so we wrap it in namespace internal.
+namespace internal {
+
+template <typename T, typename = void>
+struct IsRefCountedType : std::false_type {};
+
+template <typename T>
+struct IsRefCountedType<T,
+ void_t<decltype(std::declval<T*>()->AddRef()),
+ decltype(std::declval<T*>()->Release())>>
+ : std::true_type {};
+
+template <typename T>
+struct NeedsScopedRefptrButGetsRawPtr {
+ static_assert(!std::is_reference<T>::value,
+ "NeedsScopedRefptrButGetsRawPtr requires non-reference type.");
+
+ enum {
+ // Human readable translation: you needed to be a scoped_refptr if you are a
+ // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
+ // type.
+ value = std::is_pointer<T>::value &&
+ IsRefCountedType<std::remove_pointer_t<T>>::value
+ };
+};
+
+} // namespace internal
+
+} // namespace base
+
+#endif // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/security/sandbox/chromium/base/memory/ref_counted.cc b/security/sandbox/chromium/base/memory/ref_counted.cc
new file mode 100644
index 0000000000..0a8d32ebf0
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/ref_counted.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+
+#include <limits>
+#include <type_traits>
+
+#include "base/threading/thread_collision_warner.h"
+
+namespace base {
+namespace {
+
+#if DCHECK_IS_ON()
+std::atomic_int g_cross_thread_ref_count_access_allow_count(0);
+#endif
+
+} // namespace
+
+namespace subtle {
+
+bool RefCountedThreadSafeBase::HasOneRef() const {
+ return ref_count_.IsOne();
+}
+
+bool RefCountedThreadSafeBase::HasAtLeastOneRef() const {
+ return !ref_count_.IsZero();
+}
+
+#if DCHECK_IS_ON()
+RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
+ DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
+ "calling Release()";
+}
+#endif
+
+// For security and correctness, we check the arithmetic on ref counts.
+//
+// In an attempt to avoid binary bloat (from inlining the `CHECK`), we define
+// these functions out-of-line. However, compilers are wily. Further testing may
+// show that `NOINLINE` helps or hurts.
+//
+#if defined(ARCH_CPU_64_BITS)
+void RefCountedBase::AddRefImpl() const {
+ // An attacker could induce use-after-free bugs, and potentially exploit them,
+ // by creating so many references to a ref-counted object that the reference
+ // count overflows. On 32-bit architectures, there is not enough address space
+ // to succeed. But on 64-bit architectures, it might indeed be possible.
+ // Therefore, we can elide the check for arithmetic overflow on 32-bit, but we
+ // must check on 64-bit.
+ //
+ // Make sure the addition didn't wrap back around to 0. This form of check
+ // works because we assert that `ref_count_` is an unsigned integer type.
+ CHECK(++ref_count_ != 0);
+}
+
+void RefCountedBase::ReleaseImpl() const {
+ // Make sure the subtraction didn't wrap back around from 0 to the max value.
+ // That could cause memory leaks, and may induce application-semantic
+ // correctness or safety bugs. (E.g. what if we really needed that object to
+ // be destroyed at the right time?)
+ //
+ // Note that unlike with overflow, underflow could also happen on 32-bit
+ // architectures. Arguably, we should do this check on32-bit machines too.
+ CHECK(--ref_count_ != std::numeric_limits<decltype(ref_count_)>::max());
+}
+#endif
+
+#if !defined(ARCH_CPU_X86_FAMILY)
+bool RefCountedThreadSafeBase::Release() const {
+ return ReleaseImpl();
+}
+void RefCountedThreadSafeBase::AddRef() const {
+ AddRefImpl();
+}
+void RefCountedThreadSafeBase::AddRefWithCheck() const {
+ AddRefWithCheckImpl();
+}
+#endif
+
+#if DCHECK_IS_ON()
+bool RefCountedBase::CalledOnValidSequence() const {
+#if defined(MOZ_SANDBOX)
+ return true;
+#else
+ return sequence_checker_.CalledOnValidSequence() ||
+ g_cross_thread_ref_count_access_allow_count.load() != 0;
+#endif
+}
+#endif
+
+} // namespace subtle
+
+#if DCHECK_IS_ON()
+ScopedAllowCrossThreadRefCountAccess::ScopedAllowCrossThreadRefCountAccess() {
+ ++g_cross_thread_ref_count_access_allow_count;
+}
+
+ScopedAllowCrossThreadRefCountAccess::~ScopedAllowCrossThreadRefCountAccess() {
+ --g_cross_thread_ref_count_access_allow_count;
+}
+#endif
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/memory/ref_counted.h b/security/sandbox/chromium/base/memory/ref_counted.h
new file mode 100644
index 0000000000..ac7183a49d
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/ref_counted.h
@@ -0,0 +1,463 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_H_
+#define BASE_MEMORY_REF_COUNTED_H_
+
+#include <stddef.h>
+
+#include <utility>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequence_checker.h"
+#include "base/threading/thread_collision_warner.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace subtle {
+
+class BASE_EXPORT RefCountedBase {
+ public:
+ bool HasOneRef() const { return ref_count_ == 1; }
+ bool HasAtLeastOneRef() const { return ref_count_ >= 1; }
+
+ protected:
+ explicit RefCountedBase(StartRefCountFromZeroTag) {
+#if DCHECK_IS_ON()
+ sequence_checker_.DetachFromSequence();
+#endif
+ }
+
+ explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
+#if DCHECK_IS_ON()
+ needs_adopt_ref_ = true;
+ sequence_checker_.DetachFromSequence();
+#endif
+ }
+
+ ~RefCountedBase() {
+#if DCHECK_IS_ON()
+ DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
+#endif
+ }
+
+ void AddRef() const {
+ // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+ // Current thread books the critical section "AddRelease"
+ // without release it.
+ // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!needs_adopt_ref_)
+ << "This RefCounted object is created with non-zero reference count."
+ << " The first reference to such a object has to be made by AdoptRef or"
+ << " MakeRefCounted.";
+ if (ref_count_ >= 1) {
+ DCHECK(CalledOnValidSequence());
+ }
+#endif
+
+ AddRefImpl();
+ }
+
+ // Returns true if the object should self-delete.
+ bool Release() const {
+ ReleaseImpl();
+
+ // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+ // Current thread books the critical section "AddRelease"
+ // without release it.
+ // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ if (ref_count_ == 0)
+ in_dtor_ = true;
+
+ if (ref_count_ >= 1)
+ DCHECK(CalledOnValidSequence());
+ if (ref_count_ == 1)
+ sequence_checker_.DetachFromSequence();
+#endif
+
+ return ref_count_ == 0;
+ }
+
+ // Returns true if it is safe to read or write the object, from a thread
+ // safety standpoint. Should be DCHECK'd from the methods of RefCounted
+ // classes if there is a danger of objects being shared across threads.
+ //
+ // This produces fewer false positives than adding a separate SequenceChecker
+ // into the subclass, because it automatically detaches from the sequence when
+ // the reference count is 1 (and never fails if there is only one reference).
+ //
+ // This means unlike a separate SequenceChecker, it will permit a singly
+ // referenced object to be passed between threads (not holding a reference on
+ // the sending thread), but will trap if the sending thread holds onto a
+ // reference, or if the object is accessed from multiple threads
+ // simultaneously.
+ bool IsOnValidSequence() const {
+#if DCHECK_IS_ON()
+ return ref_count_ <= 1 || CalledOnValidSequence();
+#else
+ return true;
+#endif
+ }
+
+ private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+
+ FRIEND_TEST_ALL_PREFIXES(RefCountedDeathTest, TestOverflowCheck);
+
+ void Adopted() const {
+#if DCHECK_IS_ON()
+ DCHECK(needs_adopt_ref_);
+ needs_adopt_ref_ = false;
+#endif
+ }
+
+#if defined(ARCH_CPU_64_BITS)
+ void AddRefImpl() const;
+ void ReleaseImpl() const;
+#else
+ void AddRefImpl() const { ++ref_count_; }
+ void ReleaseImpl() const { --ref_count_; }
+#endif
+
+#if DCHECK_IS_ON()
+ bool CalledOnValidSequence() const;
+#endif
+
+ mutable uint32_t ref_count_ = 0;
+ static_assert(std::is_unsigned<decltype(ref_count_)>::value,
+ "ref_count_ must be an unsigned type.");
+
+#if DCHECK_IS_ON()
+ mutable bool needs_adopt_ref_ = false;
+ mutable bool in_dtor_ = false;
+ mutable SequenceChecker sequence_checker_;
+#endif
+
+ DFAKE_MUTEX(add_release_);
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
+};
+
+class BASE_EXPORT RefCountedThreadSafeBase {
+ public:
+ bool HasOneRef() const;
+ bool HasAtLeastOneRef() const;
+
+ protected:
+ explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
+ explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
+ : ref_count_(1) {
+#if DCHECK_IS_ON()
+ needs_adopt_ref_ = true;
+#endif
+ }
+
+#if DCHECK_IS_ON()
+ ~RefCountedThreadSafeBase();
+#else
+ ~RefCountedThreadSafeBase() = default;
+#endif
+
+// Release and AddRef are suitable for inlining on X86 because they generate
+// very small code sequences. On other platforms (ARM), it causes a size
+// regression and is probably not worth it.
+#if defined(ARCH_CPU_X86_FAMILY)
+ // Returns true if the object should self-delete.
+ bool Release() const { return ReleaseImpl(); }
+ void AddRef() const { AddRefImpl(); }
+ void AddRefWithCheck() const { AddRefWithCheckImpl(); }
+#else
+ // Returns true if the object should self-delete.
+ bool Release() const;
+ void AddRef() const;
+ void AddRefWithCheck() const;
+#endif
+
+ private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+
+ void Adopted() const {
+#if DCHECK_IS_ON()
+ DCHECK(needs_adopt_ref_);
+ needs_adopt_ref_ = false;
+#endif
+ }
+
+ ALWAYS_INLINE void AddRefImpl() const {
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!needs_adopt_ref_)
+ << "This RefCounted object is created with non-zero reference count."
+ << " The first reference to such a object has to be made by AdoptRef or"
+ << " MakeRefCounted.";
+#endif
+ ref_count_.Increment();
+ }
+
+ ALWAYS_INLINE void AddRefWithCheckImpl() const {
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!needs_adopt_ref_)
+ << "This RefCounted object is created with non-zero reference count."
+ << " The first reference to such a object has to be made by AdoptRef or"
+ << " MakeRefCounted.";
+#endif
+ CHECK(ref_count_.Increment() > 0);
+ }
+
+ ALWAYS_INLINE bool ReleaseImpl() const {
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!ref_count_.IsZero());
+#endif
+ if (!ref_count_.Decrement()) {
+#if DCHECK_IS_ON()
+ in_dtor_ = true;
+#endif
+ return true;
+ }
+ return false;
+ }
+
+ mutable AtomicRefCount ref_count_{0};
+#if DCHECK_IS_ON()
+ mutable bool needs_adopt_ref_ = false;
+ mutable bool in_dtor_ = false;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
+};
+
+} // namespace subtle
+
+// ScopedAllowCrossThreadRefCountAccess disables the check documented on
+// RefCounted below for rare pre-existing use cases where thread-safety was
+// guaranteed through other means (e.g. explicit sequencing of calls across
+// execution sequences when bouncing between threads in order). New callers
+// should refrain from using this (callsites handling thread-safety through
+// locks should use RefCountedThreadSafe per the overhead of its atomics being
+// negligible compared to locks anyways and callsites doing explicit sequencing
+// should properly std::move() the ref to avoid hitting this check).
+// TODO(tzik): Cleanup existing use cases and remove
+// ScopedAllowCrossThreadRefCountAccess.
+class BASE_EXPORT ScopedAllowCrossThreadRefCountAccess final {
+ public:
+#if DCHECK_IS_ON()
+ ScopedAllowCrossThreadRefCountAccess();
+ ~ScopedAllowCrossThreadRefCountAccess();
+#else
+ ScopedAllowCrossThreadRefCountAccess() {}
+ ~ScopedAllowCrossThreadRefCountAccess() {}
+#endif
+};
+
+//
+// A base class for reference counted classes. Otherwise, known as a cheap
+// knock-off of WebKit's RefCounted<T> class. To use this, just extend your
+// class from it like so:
+//
+// class MyFoo : public base::RefCounted<MyFoo> {
+// ...
+// private:
+// friend class base::RefCounted<MyFoo>;
+// ~MyFoo();
+// };
+//
+// You should always make your destructor non-public, to avoid any code deleting
+// the object accidently while there are references to it.
+//
+//
+// The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
+// to trap unsafe cross thread usage. A subclass instance of RefCounted can be
+// passed to another execution sequence only when its ref count is 1. If the ref
+// count is more than 1, the RefCounted class verifies the ref updates are made
+// on the same execution sequence as the previous ones. The subclass can also
+// manually call IsOnValidSequence to trap other non-thread-safe accesses; see
+// the documentation for that method.
+//
+//
+// The reference count starts from zero by default, and we intended to migrate
+// to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
+// the ref counted class to opt-in.
+//
+// If an object has start-from-one ref count, the first scoped_refptr need to be
+// created by base::AdoptRef() or base::MakeRefCounted(). We can use
+// base::MakeRefCounted() to create create both type of ref counted object.
+//
+// The motivations to use start-from-one ref count are:
+// - Start-from-one ref count doesn't need the ref count increment for the
+// first reference.
+// - It can detect an invalid object acquisition for a being-deleted object
+// that has zero ref count. That tends to happen on custom deleter that
+// delays the deletion.
+// TODO(tzik): Implement invalid acquisition detection.
+// - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
+// And start-from-one ref count is a step to merge WTF::RefCounted into
+// base::RefCounted.
+//
+#define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \
+ static constexpr ::base::subtle::StartRefCountFromOneTag \
+ kRefCountPreference = ::base::subtle::kStartRefCountFromOneTag
+
+template <class T, typename Traits>
+class RefCounted;
+
+template <typename T>
+struct DefaultRefCountedTraits {
+ static void Destruct(const T* x) {
+ RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x);
+ }
+};
+
+template <class T, typename Traits = DefaultRefCountedTraits<T>>
+class RefCounted : public subtle::RefCountedBase {
+ public:
+ static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
+ subtle::kStartRefCountFromZeroTag;
+
+ RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {}
+
+ void AddRef() const {
+ subtle::RefCountedBase::AddRef();
+ }
+
+ void Release() const {
+ if (subtle::RefCountedBase::Release()) {
+ // Prune the code paths which the static analyzer may take to simulate
+ // object destruction. Use-after-free errors aren't possible given the
+ // lifetime guarantees of the refcounting system.
+ ANALYZER_SKIP_THIS_PATH();
+
+ Traits::Destruct(static_cast<const T*>(this));
+ }
+ }
+
+ protected:
+ ~RefCounted() = default;
+
+ private:
+ friend struct DefaultRefCountedTraits<T>;
+ template <typename U>
+ static void DeleteInternal(const U* x) {
+ delete x;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(RefCounted);
+};
+
+// Forward declaration.
+template <class T, typename Traits> class RefCountedThreadSafe;
+
+// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref
+// count reaches 0. Overload to delete it on a different thread etc.
+template<typename T>
+struct DefaultRefCountedThreadSafeTraits {
+ static void Destruct(const T* x) {
+ // Delete through RefCountedThreadSafe to make child classes only need to be
+ // friend with RefCountedThreadSafe instead of this struct, which is an
+ // implementation detail.
+ RefCountedThreadSafe<T,
+ DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
+ }
+};
+
+//
+// A thread-safe variant of RefCounted<T>
+//
+// class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
+// ...
+// };
+//
+// If you're using the default trait, then you should add compile time
+// asserts that no one else is deleting your object. i.e.
+// private:
+// friend class base::RefCountedThreadSafe<MyFoo>;
+// ~MyFoo();
+//
+// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
+// too. See the comment above the RefCounted definition for details.
+template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
+class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
+ public:
+ static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
+ subtle::kStartRefCountFromZeroTag;
+
+ explicit RefCountedThreadSafe()
+ : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
+
+ void AddRef() const { AddRefImpl(T::kRefCountPreference); }
+
+ void Release() const {
+ if (subtle::RefCountedThreadSafeBase::Release()) {
+ ANALYZER_SKIP_THIS_PATH();
+ Traits::Destruct(static_cast<const T*>(this));
+ }
+ }
+
+ protected:
+ ~RefCountedThreadSafe() = default;
+
+ private:
+ friend struct DefaultRefCountedThreadSafeTraits<T>;
+ template <typename U>
+ static void DeleteInternal(const U* x) {
+ delete x;
+ }
+
+ void AddRefImpl(subtle::StartRefCountFromZeroTag) const {
+ subtle::RefCountedThreadSafeBase::AddRef();
+ }
+
+ void AddRefImpl(subtle::StartRefCountFromOneTag) const {
+ subtle::RefCountedThreadSafeBase::AddRefWithCheck();
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
+};
+
+//
+// A thread-safe wrapper for some piece of data so we can place other
+// things in scoped_refptrs<>.
+//
+template<typename T>
+class RefCountedData
+ : public base::RefCountedThreadSafe< base::RefCountedData<T> > {
+ public:
+ RefCountedData() : data() {}
+ RefCountedData(const T& in_value) : data(in_value) {}
+ RefCountedData(T&& in_value) : data(std::move(in_value)) {}
+
+ T data;
+
+ private:
+ friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
+ ~RefCountedData() = default;
+};
+
+template <typename T>
+bool operator==(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
+ return lhs.data == rhs.data;
+}
+
+template <typename T>
+bool operator!=(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace base
+
+#endif // BASE_MEMORY_REF_COUNTED_H_
diff --git a/security/sandbox/chromium/base/memory/scoped_refptr.h b/security/sandbox/chromium/base/memory/scoped_refptr.h
new file mode 100644
index 0000000000..238b61a736
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/scoped_refptr.h
@@ -0,0 +1,375 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_REFPTR_H_
+#define BASE_MEMORY_SCOPED_REFPTR_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <type_traits>
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.h"
+
+template <class T>
+class scoped_refptr;
+
+namespace base {
+
+template <class, typename>
+class RefCounted;
+template <class, typename>
+class RefCountedThreadSafe;
+class SequencedTaskRunner;
+class WrappedPromise;
+
+template <typename T>
+scoped_refptr<T> AdoptRef(T* t);
+
+namespace internal {
+
+class BasePromise;
+
+} // namespace internal
+
+namespace subtle {
+
+enum AdoptRefTag { kAdoptRefTag };
+enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
+enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
+
+template <typename T, typename U, typename V>
+constexpr bool IsRefCountPreferenceOverridden(const T*,
+ const RefCounted<U, V>*) {
+ return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
+ std::decay_t<decltype(U::kRefCountPreference)>>::value;
+}
+
+template <typename T, typename U, typename V>
+constexpr bool IsRefCountPreferenceOverridden(
+ const T*,
+ const RefCountedThreadSafe<U, V>*) {
+ return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
+ std::decay_t<decltype(U::kRefCountPreference)>>::value;
+}
+
+constexpr bool IsRefCountPreferenceOverridden(...) {
+ return false;
+}
+
+} // namespace subtle
+
+// Creates a scoped_refptr from a raw pointer without incrementing the reference
+// count. Use this only for a newly created object whose reference count starts
+// from 1 instead of 0.
+template <typename T>
+scoped_refptr<T> AdoptRef(T* obj) {
+ using Tag = std::decay_t<decltype(T::kRefCountPreference)>;
+ static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value,
+ "Use AdoptRef only if the reference count starts from one.");
+
+ DCHECK(obj);
+ DCHECK(obj->HasOneRef());
+ obj->Adopted();
+ return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
+}
+
+namespace subtle {
+
+template <typename T>
+scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
+ return scoped_refptr<T>(obj);
+}
+
+template <typename T>
+scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
+ return AdoptRef(obj);
+}
+
+} // namespace subtle
+
+// Constructs an instance of T, which is a ref counted type, and wraps the
+// object into a scoped_refptr<T>.
+template <typename T, typename... Args>
+scoped_refptr<T> MakeRefCounted(Args&&... args) {
+ T* obj = new T(std::forward<Args>(args)...);
+ return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
+}
+
+// Takes an instance of T, which is a ref counted type, and wraps the object
+// into a scoped_refptr<T>.
+template <typename T>
+scoped_refptr<T> WrapRefCounted(T* t) {
+ return scoped_refptr<T>(t);
+}
+
+} // namespace base
+
+//
+// A smart pointer class for reference counted objects. Use this class instead
+// of calling AddRef and Release manually on a reference counted object to
+// avoid common memory leaks caused by forgetting to Release an object
+// reference. Sample usage:
+//
+// class MyFoo : public RefCounted<MyFoo> {
+// ...
+// private:
+// friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>.
+// ~MyFoo(); // Destructor must be private/protected.
+// };
+//
+// void some_function() {
+// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
+// foo->Method(param);
+// // |foo| is released when this function returns
+// }
+//
+// void some_other_function() {
+// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
+// ...
+// foo.reset(); // explicitly releases |foo|
+// ...
+// if (foo)
+// foo->Method(param);
+// }
+//
+// The above examples show how scoped_refptr<T> acts like a pointer to T.
+// Given two scoped_refptr<T> classes, it is also possible to exchange
+// references between the two objects, like so:
+//
+// {
+// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
+// scoped_refptr<MyFoo> b;
+//
+// b.swap(a);
+// // now, |b| references the MyFoo object, and |a| references nullptr.
+// }
+//
+// To make both |a| and |b| in the above example reference the same MyFoo
+// object, simply use the assignment operator:
+//
+// {
+// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
+// scoped_refptr<MyFoo> b;
+//
+// b = a;
+// // now, |a| and |b| each own a reference to the same MyFoo object.
+// }
+//
+// Also see Chromium's ownership and calling conventions:
+// https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
+// Specifically:
+// If the function (at least sometimes) takes a ref on a refcounted object,
+// declare the param as scoped_refptr<T>. The caller can decide whether it
+// wishes to transfer ownership (by calling std::move(t) when passing t) or
+// retain its ref (by simply passing t directly).
+// In other words, use scoped_refptr like you would a std::unique_ptr except
+// in the odd case where it's required to hold on to a ref while handing one
+// to another component (if a component merely needs to use t on the stack
+// without keeping a ref: pass t as a raw T*).
+template <class T>
+class scoped_refptr {
+ public:
+ typedef T element_type;
+
+ constexpr scoped_refptr() = default;
+
+ // Allow implicit construction from nullptr.
+ constexpr scoped_refptr(std::nullptr_t) {}
+
+ // Constructs from a raw pointer. Note that this constructor allows implicit
+ // conversion from T* to scoped_refptr<T> which is strongly discouraged. If
+ // you are creating a new ref-counted object please use
+ // base::MakeRefCounted<T>() or base::WrapRefCounted<T>(). Otherwise you
+ // should move or copy construct from an existing scoped_refptr<T> to the
+ // ref-counted object.
+ scoped_refptr(T* p) : ptr_(p) {
+ if (ptr_)
+ AddRef(ptr_);
+ }
+
+ // Copy constructor. This is required in addition to the copy conversion
+ // constructor below.
+ scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
+
+ // Copy conversion constructor.
+ template <typename U,
+ typename = typename std::enable_if<
+ std::is_convertible<U*, T*>::value>::type>
+ scoped_refptr(const scoped_refptr<U>& r) : scoped_refptr(r.ptr_) {}
+
+ // Move constructor. This is required in addition to the move conversion
+ // constructor below.
+ scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; }
+
+ // Move conversion constructor.
+ template <typename U,
+ typename = typename std::enable_if<
+ std::is_convertible<U*, T*>::value>::type>
+ scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.ptr_) {
+ r.ptr_ = nullptr;
+ }
+
+ ~scoped_refptr() {
+ static_assert(!base::subtle::IsRefCountPreferenceOverridden(
+ static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
+ "It's unsafe to override the ref count preference."
+ " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
+ " from subclasses.");
+ if (ptr_)
+ Release(ptr_);
+ }
+
+ T* get() const { return ptr_; }
+
+ T& operator*() const {
+ DCHECK(ptr_);
+ return *ptr_;
+ }
+
+ T* operator->() const {
+ DCHECK(ptr_);
+ return ptr_;
+ }
+
+ scoped_refptr& operator=(std::nullptr_t) {
+ reset();
+ return *this;
+ }
+
+ scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
+
+ // Unified assignment operator.
+ scoped_refptr& operator=(scoped_refptr r) noexcept {
+ swap(r);
+ return *this;
+ }
+
+ // Sets managed object to null and releases reference to the previous managed
+ // object, if it existed.
+ void reset() { scoped_refptr().swap(*this); }
+
+ void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); }
+
+ explicit operator bool() const { return ptr_ != nullptr; }
+
+ template <typename U>
+ bool operator==(const scoped_refptr<U>& rhs) const {
+ return ptr_ == rhs.get();
+ }
+
+ template <typename U>
+ bool operator!=(const scoped_refptr<U>& rhs) const {
+ return !operator==(rhs);
+ }
+
+ template <typename U>
+ bool operator<(const scoped_refptr<U>& rhs) const {
+ return ptr_ < rhs.get();
+ }
+
+ protected:
+ T* ptr_ = nullptr;
+
+ private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+ friend class ::base::SequencedTaskRunner;
+
+ // Friend access so these classes can use the constructor below as part of a
+ // binary size optimization.
+ friend class ::base::internal::BasePromise;
+ friend class ::base::WrappedPromise;
+
+ // Returns the owned pointer (if any), releasing ownership to the caller. The
+ // caller is responsible for managing the lifetime of the reference.
+ T* release();
+
+ scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
+
+ // Friend required for move constructors that set r.ptr_ to null.
+ template <typename U>
+ friend class scoped_refptr;
+
+ // Non-inline helpers to allow:
+ // class Opaque;
+ // extern template class scoped_refptr<Opaque>;
+ // Otherwise the compiler will complain that Opaque is an incomplete type.
+ static void AddRef(T* ptr);
+ static void Release(T* ptr);
+};
+
+template <typename T>
+T* scoped_refptr<T>::release() {
+ T* ptr = ptr_;
+ ptr_ = nullptr;
+ return ptr;
+}
+
+// static
+template <typename T>
+void scoped_refptr<T>::AddRef(T* ptr) {
+ ptr->AddRef();
+}
+
+// static
+template <typename T>
+void scoped_refptr<T>::Release(T* ptr) {
+ ptr->Release();
+}
+
+template <typename T, typename U>
+bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
+ return lhs.get() == rhs;
+}
+
+template <typename T, typename U>
+bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
+ return lhs == rhs.get();
+}
+
+template <typename T>
+bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
+ return !static_cast<bool>(lhs);
+}
+
+template <typename T>
+bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
+ return !static_cast<bool>(rhs);
+}
+
+template <typename T, typename U>
+bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
+ return !operator==(lhs, rhs);
+}
+
+template <typename T, typename U>
+bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
+ return !operator==(lhs, rhs);
+}
+
+template <typename T>
+bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
+ return !operator==(lhs, null);
+}
+
+template <typename T>
+bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
+ return !operator==(null, rhs);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
+ return out << p.get();
+}
+
+template <typename T>
+void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) noexcept {
+ lhs.swap(rhs);
+}
+
+#endif // BASE_MEMORY_SCOPED_REFPTR_H_
diff --git a/security/sandbox/chromium/base/memory/shared_memory_mapping.cc b/security/sandbox/chromium/base/memory/shared_memory_mapping.cc
new file mode 100644
index 0000000000..8426fa8c21
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/shared_memory_mapping.cc
@@ -0,0 +1,115 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/shared_memory_mapping.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/shared_memory_tracker.h"
+#include "base/unguessable_token.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
+
+#if defined(OS_WIN)
+#include <aclapi.h>
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include <mach/mach_vm.h>
+#include "base/mac/mach_logging.h"
+#endif
+
+#if defined(OS_FUCHSIA)
+#include <lib/zx/vmar.h>
+#include "base/fuchsia/fuchsia_logging.h"
+#endif
+
+namespace base {
+
+SharedMemoryMapping::SharedMemoryMapping() = default;
+
+SharedMemoryMapping::SharedMemoryMapping(SharedMemoryMapping&& mapping) noexcept
+ : memory_(mapping.memory_),
+ size_(mapping.size_),
+ mapped_size_(mapping.mapped_size_),
+ guid_(mapping.guid_) {
+ mapping.memory_ = nullptr;
+}
+
+SharedMemoryMapping& SharedMemoryMapping::operator=(
+ SharedMemoryMapping&& mapping) noexcept {
+ Unmap();
+ memory_ = mapping.memory_;
+ size_ = mapping.size_;
+ mapped_size_ = mapping.mapped_size_;
+ guid_ = mapping.guid_;
+ mapping.memory_ = nullptr;
+ return *this;
+}
+
+SharedMemoryMapping::~SharedMemoryMapping() {
+ Unmap();
+}
+
+SharedMemoryMapping::SharedMemoryMapping(void* memory,
+ size_t size,
+ size_t mapped_size,
+ const UnguessableToken& guid)
+ : memory_(memory), size_(size), mapped_size_(mapped_size), guid_(guid) {
+ SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
+}
+
+void SharedMemoryMapping::Unmap() {
+ if (!IsValid())
+ return;
+
+ SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
+#if defined(OS_WIN)
+ if (!UnmapViewOfFile(memory_))
+ DPLOG(ERROR) << "UnmapViewOfFile";
+#elif defined(OS_FUCHSIA)
+ uintptr_t addr = reinterpret_cast<uintptr_t>(memory_);
+ zx_status_t status = zx::vmar::root_self()->unmap(addr, mapped_size_);
+ if (status != ZX_OK)
+ ZX_DLOG(ERROR, status) << "zx_vmar_unmap";
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+ kern_return_t kr = mach_vm_deallocate(
+ mach_task_self(), reinterpret_cast<mach_vm_address_t>(memory_),
+ mapped_size_);
+ MACH_DLOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_vm_deallocate";
+#else
+ if (munmap(memory_, mapped_size_) < 0)
+ DPLOG(ERROR) << "munmap";
+#endif
+}
+
+ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping() = default;
+ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping(
+ ReadOnlySharedMemoryMapping&&) noexcept = default;
+ReadOnlySharedMemoryMapping& ReadOnlySharedMemoryMapping::operator=(
+ ReadOnlySharedMemoryMapping&&) noexcept = default;
+ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping(
+ void* address,
+ size_t size,
+ size_t mapped_size,
+ const UnguessableToken& guid)
+ : SharedMemoryMapping(address, size, mapped_size, guid) {}
+
+WritableSharedMemoryMapping::WritableSharedMemoryMapping() = default;
+WritableSharedMemoryMapping::WritableSharedMemoryMapping(
+ WritableSharedMemoryMapping&&) noexcept = default;
+WritableSharedMemoryMapping& WritableSharedMemoryMapping::operator=(
+ WritableSharedMemoryMapping&&) noexcept = default;
+WritableSharedMemoryMapping::WritableSharedMemoryMapping(
+ void* address,
+ size_t size,
+ size_t mapped_size,
+ const UnguessableToken& guid)
+ : SharedMemoryMapping(address, size, mapped_size, guid) {}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/memory/shared_memory_mapping.h b/security/sandbox/chromium/base/memory/shared_memory_mapping.h
new file mode 100644
index 0000000000..2b8858e166
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/shared_memory_mapping.h
@@ -0,0 +1,252 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
+#define BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
+
+#include <cstddef>
+#include <type_traits>
+
+#include "base/containers/buffer_iterator.h"
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/unguessable_token.h"
+
+namespace base {
+
+namespace subtle {
+class PlatformSharedMemoryRegion;
+} // namespace subtle
+
+// Base class for scoped handles to a shared memory mapping created from a
+// shared memory region. Created shared memory mappings remain valid even if the
+// creator region is transferred or destroyed.
+//
+// Each mapping has an UnguessableToken that identifies the shared memory region
+// it was created from. This is used for memory metrics, to avoid overcounting
+// shared memory.
+class BASE_EXPORT SharedMemoryMapping {
+ public:
+ // Default constructor initializes an invalid instance.
+ SharedMemoryMapping();
+
+ // Move operations are allowed.
+ SharedMemoryMapping(SharedMemoryMapping&& mapping) noexcept;
+ SharedMemoryMapping& operator=(SharedMemoryMapping&& mapping) noexcept;
+
+ // Unmaps the region if the mapping is valid.
+ virtual ~SharedMemoryMapping();
+
+ // Returns true iff the mapping is valid. False means there is no
+ // corresponding area of memory.
+ bool IsValid() const { return memory_ != nullptr; }
+
+ // Returns the logical size of the mapping in bytes. This is precisely the
+ // size requested by whoever created the mapping, and it is always less than
+ // or equal to |mapped_size()|. This is undefined for invalid instances.
+ size_t size() const {
+ DCHECK(IsValid());
+ return size_;
+ }
+
+ // Returns the actual size of the mapping in bytes. This is always at least
+ // as large as |size()| but may be larger due to platform mapping alignment
+ // constraints. This is undefined for invalid instances.
+ size_t mapped_size() const {
+ DCHECK(IsValid());
+ return mapped_size_;
+ }
+
+ // Returns 128-bit GUID of the region this mapping belongs to.
+ const UnguessableToken& guid() const {
+ DCHECK(IsValid());
+ return guid_;
+ }
+
+ protected:
+ SharedMemoryMapping(void* address,
+ size_t size,
+ size_t mapped_size,
+ const UnguessableToken& guid);
+ void* raw_memory_ptr() const { return memory_; }
+
+ private:
+ friend class SharedMemoryTracker;
+
+ void Unmap();
+
+ void* memory_ = nullptr;
+ size_t size_ = 0;
+ size_t mapped_size_ = 0;
+ UnguessableToken guid_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedMemoryMapping);
+};
+
+// Class modeling a read-only mapping of a shared memory region into the
+// current process' address space. This is created by ReadOnlySharedMemoryRegion
+// instances.
+class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
+ public:
+ // Default constructor initializes an invalid instance.
+ ReadOnlySharedMemoryMapping();
+
+ // Move operations are allowed.
+ ReadOnlySharedMemoryMapping(ReadOnlySharedMemoryMapping&&) noexcept;
+ ReadOnlySharedMemoryMapping& operator=(
+ ReadOnlySharedMemoryMapping&&) noexcept;
+
+ // Returns the base address of the mapping. This is read-only memory. This is
+ // page-aligned. This is nullptr for invalid instances.
+ const void* memory() const { return raw_memory_ptr(); }
+
+ // Returns a pointer to a page-aligned const T if the mapping is valid and
+ // large enough to contain a T, or nullptr otherwise.
+ template <typename T>
+ const T* GetMemoryAs() const {
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Copying non-trivially-copyable object across memory spaces "
+ "is dangerous");
+ if (!IsValid())
+ return nullptr;
+ if (sizeof(T) > size())
+ return nullptr;
+ return static_cast<const T*>(raw_memory_ptr());
+ }
+
+ // Returns a span of const T. The number of elements is autodeduced from the
+ // size of the shared memory mapping. The number of elements may be
+ // autodeduced as zero, i.e. the mapping is invalid or the size of the mapping
+ // isn't large enough to contain even one T: in that case, an empty span
+ // will be returned. The first element, if any, is guaranteed to be
+ // page-aligned.
+ template <typename T>
+ span<const T> GetMemoryAsSpan() const {
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Copying non-trivially-copyable object across memory spaces "
+ "is dangerous");
+ if (!IsValid())
+ return span<const T>();
+ size_t count = size() / sizeof(T);
+ return GetMemoryAsSpan<T>(count);
+ }
+
+ // Returns a span of const T with |count| elements if the mapping is valid and
+ // large enough to contain |count| elements, or an empty span otherwise. The
+ // first element, if any, is guaranteed to be page-aligned.
+ template <typename T>
+ span<const T> GetMemoryAsSpan(size_t count) const {
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Copying non-trivially-copyable object across memory spaces "
+ "is dangerous");
+ if (!IsValid())
+ return span<const T>();
+ if (size() / sizeof(T) < count)
+ return span<const T>();
+ return span<const T>(static_cast<const T*>(raw_memory_ptr()), count);
+ }
+
+ // Returns a BufferIterator of const T.
+ template <typename T>
+ BufferIterator<const T> GetMemoryAsBufferIterator() const {
+ return BufferIterator<const T>(GetMemoryAsSpan<T>());
+ }
+
+ private:
+ friend class ReadOnlySharedMemoryRegion;
+ ReadOnlySharedMemoryMapping(void* address,
+ size_t size,
+ size_t mapped_size,
+ const UnguessableToken& guid);
+
+ DISALLOW_COPY_AND_ASSIGN(ReadOnlySharedMemoryMapping);
+};
+
+// Class modeling a writable mapping of a shared memory region into the
+// current process' address space. This is created by *SharedMemoryRegion
+// instances.
+class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
+ public:
+ // Default constructor initializes an invalid instance.
+ WritableSharedMemoryMapping();
+
+ // Move operations are allowed.
+ WritableSharedMemoryMapping(WritableSharedMemoryMapping&&) noexcept;
+ WritableSharedMemoryMapping& operator=(
+ WritableSharedMemoryMapping&&) noexcept;
+
+ // Returns the base address of the mapping. This is writable memory. This is
+ // page-aligned. This is nullptr for invalid instances.
+ void* memory() const { return raw_memory_ptr(); }
+
+ // Returns a pointer to a page-aligned T if the mapping is valid and large
+ // enough to contain a T, or nullptr otherwise.
+ template <typename T>
+ T* GetMemoryAs() const {
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Copying non-trivially-copyable object across memory spaces "
+ "is dangerous");
+ if (!IsValid())
+ return nullptr;
+ if (sizeof(T) > size())
+ return nullptr;
+ return static_cast<T*>(raw_memory_ptr());
+ }
+
+ // Returns a span of T. The number of elements is autodeduced from the size of
+ // the shared memory mapping. The number of elements may be autodeduced as
+ // zero, i.e. the mapping is invalid or the size of the mapping isn't large
+ // enough to contain even one T: in that case, an empty span will be returned.
+ // The first element, if any, is guaranteed to be page-aligned.
+ template <typename T>
+ span<T> GetMemoryAsSpan() const {
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Copying non-trivially-copyable object across memory spaces "
+ "is dangerous");
+ if (!IsValid())
+ return span<T>();
+ size_t count = size() / sizeof(T);
+ return GetMemoryAsSpan<T>(count);
+ }
+
+ // Returns a span of T with |count| elements if the mapping is valid and large
+ // enough to contain |count| elements, or an empty span otherwise. The first
+ // element, if any, is guaranteed to be page-aligned.
+ template <typename T>
+ span<T> GetMemoryAsSpan(size_t count) const {
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Copying non-trivially-copyable object across memory spaces "
+ "is dangerous");
+ if (!IsValid())
+ return span<T>();
+ if (size() / sizeof(T) < count)
+ return span<T>();
+ return span<T>(static_cast<T*>(raw_memory_ptr()), count);
+ }
+
+ // Returns a BufferIterator of T.
+ template <typename T>
+ BufferIterator<T> GetMemoryAsBufferIterator() {
+ return BufferIterator<T>(GetMemoryAsSpan<T>());
+ }
+
+ private:
+ friend WritableSharedMemoryMapping MapAtForTesting(
+ subtle::PlatformSharedMemoryRegion* region,
+ off_t offset,
+ size_t size);
+ friend class ReadOnlySharedMemoryRegion;
+ friend class WritableSharedMemoryRegion;
+ friend class UnsafeSharedMemoryRegion;
+ WritableSharedMemoryMapping(void* address,
+ size_t size,
+ size_t mapped_size,
+ const UnguessableToken& guid);
+
+ DISALLOW_COPY_AND_ASSIGN(WritableSharedMemoryMapping);
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
diff --git a/security/sandbox/chromium/base/memory/singleton.h b/security/sandbox/chromium/base/memory/singleton.h
new file mode 100644
index 0000000000..87b57919c0
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/singleton.h
@@ -0,0 +1,279 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// PLEASE READ: Do you really need a singleton? If possible, use a
+// function-local static of type base::NoDestructor<T> instead:
+//
+// Factory& Factory::GetInstance() {
+// static base::NoDestructor<Factory> instance;
+// return *instance;
+// }
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+// Singletons make it hard to determine the lifetime of an object, which can
+// lead to buggy code and spurious crashes.
+//
+// Instead of adding another singleton into the mix, try to identify either:
+// a) An existing singleton that can manage your object's lifetime
+// b) Locations where you can deterministically create the object and pass
+// into other objects
+//
+// If you absolutely need a singleton, please keep them as trivial as possible
+// and ideally a leaf dependency. Singletons get problematic when they attempt
+// to do too much in their destructor or have circular dependencies.
+
+#ifndef BASE_MEMORY_SINGLETON_H_
+#define BASE_MEMORY_SINGLETON_H_
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/lazy_instance_helpers.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+// Default traits for Singleton<Type>. Calls operator new and operator delete on
+// the object. Registers automatic deletion at process exit.
+// Overload if you need arguments or another memory allocation function.
+template<typename Type>
+struct DefaultSingletonTraits {
+ // Allocates the object.
+ static Type* New() {
+ // The parenthesis is very important here; it forces POD type
+ // initialization.
+ return new Type();
+ }
+
+ // Destroys the object.
+ static void Delete(Type* x) {
+ delete x;
+ }
+
+ // Set to true to automatically register deletion of the object on process
+ // exit. See below for the required call that makes this happen.
+ static const bool kRegisterAtExit = true;
+
+#if DCHECK_IS_ON()
+ // Set to false to disallow access on a non-joinable thread. This is
+ // different from kRegisterAtExit because StaticMemorySingletonTraits allows
+ // access on non-joinable threads, and gracefully handles this.
+ static const bool kAllowedToAccessOnNonjoinableThread = false;
+#endif
+};
+
+
+// Alternate traits for use with the Singleton<Type>. Identical to
+// DefaultSingletonTraits except that the Singleton will not be cleaned up
+// at exit.
+template<typename Type>
+struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
+ static const bool kRegisterAtExit = false;
+#if DCHECK_IS_ON()
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+};
+
+// Alternate traits for use with the Singleton<Type>. Allocates memory
+// for the singleton instance from a static buffer. The singleton will
+// be cleaned up at exit, but can't be revived after destruction unless
+// the ResurrectForTesting() method is called.
+//
+// This is useful for a certain category of things, notably logging and
+// tracing, where the singleton instance is of a type carefully constructed to
+// be safe to access post-destruction.
+// In logging and tracing you'll typically get stray calls at odd times, like
+// during static destruction, thread teardown and the like, and there's a
+// termination race on the heap-based singleton - e.g. if one thread calls
+// get(), but then another thread initiates AtExit processing, the first thread
+// may call into an object residing in unallocated memory. If the instance is
+// allocated from the data segment, then this is survivable.
+//
+// The destructor is to deallocate system resources, in this case to unregister
+// a callback the system will invoke when logging levels change. Note that
+// this is also used in e.g. Chrome Frame, where you have to allow for the
+// possibility of loading briefly into someone else's process space, and
+// so leaking is not an option, as that would sabotage the state of your host
+// process once you've unloaded.
+template <typename Type>
+struct StaticMemorySingletonTraits {
+ // WARNING: User has to support a New() which returns null.
+ static Type* New() {
+ // Only constructs once and returns pointer; otherwise returns null.
+ if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
+ return nullptr;
+
+ return new (buffer_) Type();
+ }
+
+ static void Delete(Type* p) {
+ if (p)
+ p->Type::~Type();
+ }
+
+ static const bool kRegisterAtExit = true;
+
+#if DCHECK_IS_ON()
+ static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+
+ static void ResurrectForTesting() { subtle::NoBarrier_Store(&dead_, 0); }
+
+ private:
+ alignas(Type) static char buffer_[sizeof(Type)];
+ // Signal the object was already deleted, so it is not revived.
+ static subtle::Atomic32 dead_;
+};
+
+template <typename Type>
+alignas(Type) char StaticMemorySingletonTraits<Type>::buffer_[sizeof(Type)];
+template <typename Type>
+subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0;
+
+// The Singleton<Type, Traits, DifferentiatingType> class manages a single
+// instance of Type which will be created on first use and will be destroyed at
+// normal process exit). The Trait::Delete function will not be called on
+// abnormal process exit.
+//
+// DifferentiatingType is used as a key to differentiate two different
+// singletons having the same memory allocation functions but serving a
+// different purpose. This is mainly used for Locks serving different purposes.
+//
+// Example usage:
+//
+// In your header:
+// namespace base {
+// template <typename T>
+// struct DefaultSingletonTraits;
+// }
+// class FooClass {
+// public:
+// static FooClass* GetInstance(); <-- See comment below on this.
+// void Bar() { ... }
+// private:
+// FooClass() { ... }
+// friend struct base::DefaultSingletonTraits<FooClass>;
+//
+// DISALLOW_COPY_AND_ASSIGN(FooClass);
+// };
+//
+// In your source file:
+// #include "base/memory/singleton.h"
+// FooClass* FooClass::GetInstance() {
+// return base::Singleton<FooClass>::get();
+// }
+//
+// Or for leaky singletons:
+// #include "base/memory/singleton.h"
+// FooClass* FooClass::GetInstance() {
+// return base::Singleton<
+// FooClass, base::LeakySingletonTraits<FooClass>>::get();
+// }
+//
+// And to call methods on FooClass:
+// FooClass::GetInstance()->Bar();
+//
+// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance
+// and it is important that FooClass::GetInstance() is not inlined in the
+// header. This makes sure that when source files from multiple targets include
+// this header they don't end up with different copies of the inlined code
+// creating multiple copies of the singleton.
+//
+// Singleton<> has no non-static members and doesn't need to actually be
+// instantiated.
+//
+// This class is itself thread-safe. The underlying Type must of course be
+// thread-safe if you want to use it concurrently. Two parameters may be tuned
+// depending on the user's requirements.
+//
+// Glossary:
+// RAE = kRegisterAtExit
+//
+// On every platform, if Traits::RAE is true, the singleton will be destroyed at
+// process exit. More precisely it uses AtExitManager which requires an
+// object of this type to be instantiated. AtExitManager mimics the semantics
+// of atexit() such as LIFO order but under Windows is safer to call. For more
+// information see at_exit.h.
+//
+// If Traits::RAE is false, the singleton will not be freed at process exit,
+// thus the singleton will be leaked if it is ever accessed. Traits::RAE
+// shouldn't be false unless absolutely necessary. Remember that the heap where
+// the object is allocated may be destroyed by the CRT anyway.
+//
+// Caveats:
+// (a) Every call to get(), operator->() and operator*() incurs some overhead
+// (16ns on my P4/2.8GHz) to check whether the object has already been
+// initialized. You may wish to cache the result of get(); it will not
+// change.
+//
+// (b) Your factory function must never throw an exception. This class is not
+// exception-safe.
+//
+
+template <typename Type,
+ typename Traits = DefaultSingletonTraits<Type>,
+ typename DifferentiatingType = Type>
+class Singleton {
+ private:
+ // A class T using the Singleton<T> pattern should declare a GetInstance()
+ // method and call Singleton::get() from within that. T may also declare a
+ // GetInstanceIfExists() method to invoke Singleton::GetIfExists().
+ friend Type;
+
+ // This class is safe to be constructed and copy-constructed since it has no
+ // member.
+
+ // Returns a pointer to the one true instance of the class.
+ static Type* get() {
+#if DCHECK_IS_ON()
+ if (!Traits::kAllowedToAccessOnNonjoinableThread)
+ ThreadRestrictions::AssertSingletonAllowed();
+#endif
+
+ return subtle::GetOrCreateLazyPointer(
+ &instance_, &CreatorFunc, nullptr,
+ Traits::kRegisterAtExit ? OnExit : nullptr, nullptr);
+ }
+
+ // Returns the same result as get() if the instance exists but doesn't
+ // construct it (and returns null) if it doesn't.
+ static Type* GetIfExists() {
+#if DCHECK_IS_ON()
+ if (!Traits::kAllowedToAccessOnNonjoinableThread)
+ ThreadRestrictions::AssertSingletonAllowed();
+#endif
+
+ if (!subtle::NoBarrier_Load(&instance_))
+ return nullptr;
+
+ // Need to invoke get() nonetheless as some Traits return null after
+ // destruction (even though |instance_| still holds garbage).
+ return get();
+ }
+
+ // Internal method used as an adaptor for GetOrCreateLazyPointer(). Do not use
+ // outside of that use case.
+ static Type* CreatorFunc(void* /* creator_arg*/) { return Traits::New(); }
+
+ // Adapter function for use with AtExit(). This should be called single
+ // threaded, so don't use atomic operations.
+ // Calling OnExit while singleton is in use by other threads is a mistake.
+ static void OnExit(void* /*unused*/) {
+ // AtExit should only ever be register after the singleton instance was
+ // created. We should only ever get here with a valid instance_ pointer.
+ Traits::Delete(reinterpret_cast<Type*>(subtle::NoBarrier_Load(&instance_)));
+ instance_ = 0;
+ }
+ static subtle::AtomicWord instance_;
+};
+
+template <typename Type, typename Traits, typename DifferentiatingType>
+subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::instance_ = 0;
+
+} // namespace base
+
+#endif // BASE_MEMORY_SINGLETON_H_
diff --git a/security/sandbox/chromium/base/memory/unsafe_shared_memory_region.cc b/security/sandbox/chromium/base/memory/unsafe_shared_memory_region.cc
new file mode 100644
index 0000000000..92385d3e78
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/unsafe_shared_memory_region.cc
@@ -0,0 +1,80 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/unsafe_shared_memory_region.h"
+
+#include <utility>
+
+namespace base {
+
+UnsafeSharedMemoryRegion::CreateFunction*
+ UnsafeSharedMemoryRegion::create_hook_ = nullptr;
+
+// static
+UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Create(size_t size) {
+ if (create_hook_)
+ return create_hook_(size);
+
+ subtle::PlatformSharedMemoryRegion handle =
+ subtle::PlatformSharedMemoryRegion::CreateUnsafe(size);
+
+ return UnsafeSharedMemoryRegion(std::move(handle));
+}
+
+// static
+UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Deserialize(
+ subtle::PlatformSharedMemoryRegion handle) {
+ return UnsafeSharedMemoryRegion(std::move(handle));
+}
+
+// static
+subtle::PlatformSharedMemoryRegion
+UnsafeSharedMemoryRegion::TakeHandleForSerialization(
+ UnsafeSharedMemoryRegion region) {
+ return std::move(region.handle_);
+}
+
+UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion() = default;
+UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion(
+ UnsafeSharedMemoryRegion&& region) = default;
+UnsafeSharedMemoryRegion& UnsafeSharedMemoryRegion::operator=(
+ UnsafeSharedMemoryRegion&& region) = default;
+UnsafeSharedMemoryRegion::~UnsafeSharedMemoryRegion() = default;
+
+UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Duplicate() const {
+ return UnsafeSharedMemoryRegion(handle_.Duplicate());
+}
+
+WritableSharedMemoryMapping UnsafeSharedMemoryRegion::Map() const {
+ return MapAt(0, handle_.GetSize());
+}
+
+WritableSharedMemoryMapping UnsafeSharedMemoryRegion::MapAt(off_t offset,
+ size_t size) const {
+ if (!IsValid())
+ return {};
+
+ void* memory = nullptr;
+ size_t mapped_size = 0;
+ if (!handle_.MapAt(offset, size, &memory, &mapped_size))
+ return {};
+
+ return WritableSharedMemoryMapping(memory, size, mapped_size,
+ handle_.GetGUID());
+}
+
+bool UnsafeSharedMemoryRegion::IsValid() const {
+ return handle_.IsValid();
+}
+
+UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion(
+ subtle::PlatformSharedMemoryRegion handle)
+ : handle_(std::move(handle)) {
+ if (handle_.IsValid()) {
+ CHECK_EQ(handle_.GetMode(),
+ subtle::PlatformSharedMemoryRegion::Mode::kUnsafe);
+ }
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/memory/unsafe_shared_memory_region.h b/security/sandbox/chromium/base/memory/unsafe_shared_memory_region.h
new file mode 100644
index 0000000000..559d4c6830
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/unsafe_shared_memory_region.h
@@ -0,0 +1,127 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
+#define BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/shared_memory_mapping.h"
+
+namespace base {
+
+// Scoped move-only handle to a region of platform shared memory. The instance
+// owns the platform handle it wraps. Mappings created by this region are
+// writable. These mappings remain valid even after the region handle is moved
+// or destroyed.
+//
+// NOTE: UnsafeSharedMemoryRegion cannot be converted to a read-only region. Use
+// with caution as the region will be writable to any process with a handle to
+// the region.
+//
+// Use this if and only if the following is true:
+// - You do not need to share the region as read-only, and,
+// - You need to have several instances of the region simultaneously, possibly
+// in different processes, that can produce writable mappings.
+
+class BASE_EXPORT UnsafeSharedMemoryRegion {
+ public:
+ using MappingType = WritableSharedMemoryMapping;
+ // Creates a new UnsafeSharedMemoryRegion instance of a given size that can be
+ // used for mapping writable shared memory into the virtual address space.
+ //
+ // This call will fail if the process does not have sufficient permissions to
+ // create a shared memory region itself. See
+ // mojo::CreateUnsafeSharedMemoryRegion in
+ // mojo/public/cpp/base/shared_memory_utils.h for creating a shared memory
+ // region from a an unprivileged process where a broker must be used.
+ static UnsafeSharedMemoryRegion Create(size_t size);
+ using CreateFunction = decltype(Create);
+
+ // Returns an UnsafeSharedMemoryRegion built from a platform-specific handle
+ // that was taken from another UnsafeSharedMemoryRegion instance. Returns an
+ // invalid region iff the |handle| is invalid. CHECK-fails if the |handle|
+ // isn't unsafe.
+ // This should be used only by the code passing a handle across
+ // process boundaries.
+ static UnsafeSharedMemoryRegion Deserialize(
+ subtle::PlatformSharedMemoryRegion handle);
+
+ // Extracts a platform handle from the region. Ownership is transferred to the
+ // returned region object.
+ // This should be used only for sending the handle from the current
+ // process to another.
+ static subtle::PlatformSharedMemoryRegion TakeHandleForSerialization(
+ UnsafeSharedMemoryRegion region);
+
+ // Default constructor initializes an invalid instance.
+ UnsafeSharedMemoryRegion();
+
+ // Move operations are allowed.
+ UnsafeSharedMemoryRegion(UnsafeSharedMemoryRegion&&);
+ UnsafeSharedMemoryRegion& operator=(UnsafeSharedMemoryRegion&&);
+
+ // Destructor closes shared memory region if valid.
+ // All created mappings will remain valid.
+ ~UnsafeSharedMemoryRegion();
+
+ // Duplicates the underlying platform handle and creates a new
+ // UnsafeSharedMemoryRegion instance that owns the newly created handle.
+ // Returns a valid UnsafeSharedMemoryRegion on success, invalid otherwise.
+ // The current region instance remains valid in any case.
+ UnsafeSharedMemoryRegion Duplicate() const;
+
+ // Maps the shared memory region into the caller's address space with write
+ // access. The mapped address is guaranteed to have an alignment of
+ // at least |subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment|.
+ // Returns a valid WritableSharedMemoryMapping instance on success, invalid
+ // otherwise.
+ WritableSharedMemoryMapping Map() const;
+
+ // Same as above, but maps only |size| bytes of the shared memory region
+ // starting with the given |offset|. |offset| must be aligned to value of
+ // |SysInfo::VMAllocationGranularity()|. Returns an invalid mapping if
+ // requested bytes are out of the region limits.
+ WritableSharedMemoryMapping MapAt(off_t offset, size_t size) const;
+
+ // Whether the underlying platform handle is valid.
+ bool IsValid() const;
+
+ // Returns the maximum mapping size that can be created from this region.
+ size_t GetSize() const {
+ DCHECK(IsValid());
+ return handle_.GetSize();
+ }
+
+ // Returns 128-bit GUID of the region.
+ const UnguessableToken& GetGUID() const {
+ DCHECK(IsValid());
+ return handle_.GetGUID();
+ }
+
+ // Returns a platform shared memory handle. |this| remains the owner of the
+ // handle.
+ subtle::PlatformSharedMemoryRegion::PlatformHandle GetPlatformHandle() const {
+ DCHECK(IsValid());
+ return handle_.GetPlatformHandle();
+ }
+
+ private:
+ friend class SharedMemoryHooks;
+
+ explicit UnsafeSharedMemoryRegion(subtle::PlatformSharedMemoryRegion handle);
+
+ static void set_create_hook(CreateFunction* hook) { create_hook_ = hook; }
+
+ static CreateFunction* create_hook_;
+
+ subtle::PlatformSharedMemoryRegion handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnsafeSharedMemoryRegion);
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_UNSAFE_SHARED_MEMORY_REGION_H_
diff --git a/security/sandbox/chromium/base/memory/weak_ptr.h b/security/sandbox/chromium/base/memory/weak_ptr.h
new file mode 100644
index 0000000000..d274987168
--- /dev/null
+++ b/security/sandbox/chromium/base/memory/weak_ptr.h
@@ -0,0 +1,395 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Weak pointers are pointers to an object that do not affect its lifetime,
+// and which may be invalidated (i.e. reset to nullptr) by the object, or its
+// owner, at any time, most commonly when the object is about to be deleted.
+
+// Weak pointers are useful when an object needs to be accessed safely by one
+// or more objects other than its owner, and those callers can cope with the
+// object vanishing and e.g. tasks posted to it being silently dropped.
+// Reference-counting such an object would complicate the ownership graph and
+// make it harder to reason about the object's lifetime.
+
+// EXAMPLE:
+//
+// class Controller {
+// public:
+// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
+// void WorkComplete(const Result& result) { ... }
+// private:
+// // Member variables should appear before the WeakPtrFactory, to ensure
+// // that any WeakPtrs to Controller are invalidated before its members
+// // variable's destructors are executed, rendering them invalid.
+// WeakPtrFactory<Controller> weak_factory_{this};
+// };
+//
+// class Worker {
+// public:
+// static void StartNew(const WeakPtr<Controller>& controller) {
+// Worker* worker = new Worker(controller);
+// // Kick off asynchronous processing...
+// }
+// private:
+// Worker(const WeakPtr<Controller>& controller)
+// : controller_(controller) {}
+// void DidCompleteAsynchronousProcessing(const Result& result) {
+// if (controller_)
+// controller_->WorkComplete(result);
+// }
+// WeakPtr<Controller> controller_;
+// };
+//
+// With this implementation a caller may use SpawnWorker() to dispatch multiple
+// Workers and subsequently delete the Controller, without waiting for all
+// Workers to have completed.
+
+// ------------------------- IMPORTANT: Thread-safety -------------------------
+
+// Weak pointers may be passed safely between sequences, but must always be
+// dereferenced and invalidated on the same SequencedTaskRunner otherwise
+// checking the pointer would be racey.
+//
+// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
+// is dereferenced, the factory and its WeakPtrs become bound to the calling
+// sequence or current SequencedWorkerPool token, and cannot be dereferenced or
+// invalidated on any other task runner. Bound WeakPtrs can still be handed
+// off to other task runners, e.g. to use to post tasks back to object on the
+// bound sequence.
+//
+// If all WeakPtr objects are destroyed or invalidated then the factory is
+// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be
+// destroyed, or new WeakPtr objects may be used, from a different sequence.
+//
+// Thus, at least one WeakPtr object must exist and have been dereferenced on
+// the correct sequence to enforce that other WeakPtr objects will enforce they
+// are used on the desired sequence.
+
+#ifndef BASE_MEMORY_WEAK_PTR_H_
+#define BASE_MEMORY_WEAK_PTR_H_
+
+#include <cstddef>
+#include <type_traits>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "base/synchronization/atomic_flag.h"
+
+namespace base {
+
+template <typename T> class SupportsWeakPtr;
+template <typename T> class WeakPtr;
+
+namespace internal {
+// These classes are part of the WeakPtr implementation.
+// DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
+
+class BASE_EXPORT WeakReference {
+ public:
+ // Although Flag is bound to a specific SequencedTaskRunner, it may be
+ // deleted from another via base::WeakPtr::~WeakPtr().
+ class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> {
+ public:
+ Flag();
+
+ void Invalidate();
+ bool IsValid() const;
+
+ bool MaybeValid() const;
+
+ void DetachFromSequence();
+
+ private:
+ friend class base::RefCountedThreadSafe<Flag>;
+
+ ~Flag();
+
+ SEQUENCE_CHECKER(sequence_checker_);
+ AtomicFlag invalidated_;
+ };
+
+ WeakReference();
+ explicit WeakReference(const scoped_refptr<Flag>& flag);
+ ~WeakReference();
+
+ WeakReference(WeakReference&& other) noexcept;
+ WeakReference(const WeakReference& other);
+ WeakReference& operator=(WeakReference&& other) noexcept = default;
+ WeakReference& operator=(const WeakReference& other) = default;
+
+ bool IsValid() const;
+ bool MaybeValid() const;
+
+ private:
+ scoped_refptr<const Flag> flag_;
+};
+
+class BASE_EXPORT WeakReferenceOwner {
+ public:
+ WeakReferenceOwner();
+ ~WeakReferenceOwner();
+
+ WeakReference GetRef() const;
+
+ bool HasRefs() const { return !flag_->HasOneRef(); }
+
+ void Invalidate();
+
+ private:
+ scoped_refptr<WeakReference::Flag> flag_;
+};
+
+// This class simplifies the implementation of WeakPtr's type conversion
+// constructor by avoiding the need for a public accessor for ref_. A
+// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this
+// base class gives us a way to access ref_ in a protected fashion.
+class BASE_EXPORT WeakPtrBase {
+ public:
+ WeakPtrBase();
+ ~WeakPtrBase();
+
+ WeakPtrBase(const WeakPtrBase& other) = default;
+ WeakPtrBase(WeakPtrBase&& other) noexcept = default;
+ WeakPtrBase& operator=(const WeakPtrBase& other) = default;
+ WeakPtrBase& operator=(WeakPtrBase&& other) noexcept = default;
+
+ void reset() {
+ ref_ = internal::WeakReference();
+ ptr_ = 0;
+ }
+
+ protected:
+ WeakPtrBase(const WeakReference& ref, uintptr_t ptr);
+
+ WeakReference ref_;
+
+ // This pointer is only valid when ref_.is_valid() is true. Otherwise, its
+ // value is undefined (as opposed to nullptr).
+ uintptr_t ptr_;
+};
+
+// This class provides a common implementation of common functions that would
+// otherwise get instantiated separately for each distinct instantiation of
+// SupportsWeakPtr<>.
+class SupportsWeakPtrBase {
+ public:
+ // A safe static downcast of a WeakPtr<Base> to WeakPtr<Derived>. This
+ // conversion will only compile if there is exists a Base which inherits
+ // from SupportsWeakPtr<Base>. See base::AsWeakPtr() below for a helper
+ // function that makes calling this easier.
+ //
+ // Precondition: t != nullptr
+ template<typename Derived>
+ static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
+ static_assert(
+ std::is_base_of<internal::SupportsWeakPtrBase, Derived>::value,
+ "AsWeakPtr argument must inherit from SupportsWeakPtr");
+ return AsWeakPtrImpl<Derived>(t);
+ }
+
+ private:
+ // This template function uses type inference to find a Base of Derived
+ // which is an instance of SupportsWeakPtr<Base>. We can then safely
+ // static_cast the Base* to a Derived*.
+ template <typename Derived, typename Base>
+ static WeakPtr<Derived> AsWeakPtrImpl(SupportsWeakPtr<Base>* t) {
+ WeakPtr<Base> ptr = t->AsWeakPtr();
+ return WeakPtr<Derived>(
+ ptr.ref_, static_cast<Derived*>(reinterpret_cast<Base*>(ptr.ptr_)));
+ }
+};
+
+} // namespace internal
+
+template <typename T> class WeakPtrFactory;
+
+// The WeakPtr class holds a weak reference to |T*|.
+//
+// This class is designed to be used like a normal pointer. You should always
+// null-test an object of this class before using it or invoking a method that
+// may result in the underlying object being destroyed.
+//
+// EXAMPLE:
+//
+// class Foo { ... };
+// WeakPtr<Foo> foo;
+// if (foo)
+// foo->method();
+//
+template <typename T>
+class WeakPtr : public internal::WeakPtrBase {
+ public:
+ WeakPtr() = default;
+ WeakPtr(std::nullptr_t) {}
+
+ // Allow conversion from U to T provided U "is a" T. Note that this
+ // is separate from the (implicit) copy and move constructors.
+ template <typename U>
+ WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other) {
+ // Need to cast from U* to T* to do pointer adjustment in case of multiple
+ // inheritance. This also enforces the "U is a T" rule.
+ T* t = reinterpret_cast<U*>(other.ptr_);
+ ptr_ = reinterpret_cast<uintptr_t>(t);
+ }
+ template <typename U>
+ WeakPtr(WeakPtr<U>&& other) noexcept : WeakPtrBase(std::move(other)) {
+ // Need to cast from U* to T* to do pointer adjustment in case of multiple
+ // inheritance. This also enforces the "U is a T" rule.
+ T* t = reinterpret_cast<U*>(other.ptr_);
+ ptr_ = reinterpret_cast<uintptr_t>(t);
+ }
+
+ T* get() const {
+ return ref_.IsValid() ? reinterpret_cast<T*>(ptr_) : nullptr;
+ }
+
+ T& operator*() const {
+ DCHECK(get() != nullptr);
+ return *get();
+ }
+ T* operator->() const {
+ DCHECK(get() != nullptr);
+ return get();
+ }
+
+ // Allow conditionals to test validity, e.g. if (weak_ptr) {...};
+ explicit operator bool() const { return get() != nullptr; }
+
+ // Returns false if the WeakPtr is confirmed to be invalid. This call is safe
+ // to make from any thread, e.g. to optimize away unnecessary work, but
+ // operator bool() must always be called, on the correct sequence, before
+ // actually using the pointer.
+ //
+ // Warning: as with any object, this call is only thread-safe if the WeakPtr
+ // instance isn't being re-assigned or reset() racily with this call.
+ bool MaybeValid() const { return ref_.MaybeValid(); }
+
+ // Returns whether the object |this| points to has been invalidated. This can
+ // be used to distinguish a WeakPtr to a destroyed object from one that has
+ // been explicitly set to null.
+ bool WasInvalidated() const { return ptr_ && !ref_.IsValid(); }
+
+ private:
+ friend class internal::SupportsWeakPtrBase;
+ template <typename U> friend class WeakPtr;
+ friend class SupportsWeakPtr<T>;
+ friend class WeakPtrFactory<T>;
+
+ WeakPtr(const internal::WeakReference& ref, T* ptr)
+ : WeakPtrBase(ref, reinterpret_cast<uintptr_t>(ptr)) {}
+};
+
+// Allow callers to compare WeakPtrs against nullptr to test validity.
+template <class T>
+bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
+ return !(weak_ptr == nullptr);
+}
+template <class T>
+bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
+ return weak_ptr != nullptr;
+}
+template <class T>
+bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
+ return weak_ptr.get() == nullptr;
+}
+template <class T>
+bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
+ return weak_ptr == nullptr;
+}
+
+namespace internal {
+class BASE_EXPORT WeakPtrFactoryBase {
+ protected:
+ WeakPtrFactoryBase(uintptr_t ptr);
+ ~WeakPtrFactoryBase();
+ internal::WeakReferenceOwner weak_reference_owner_;
+ uintptr_t ptr_;
+};
+} // namespace internal
+
+// A class may be composed of a WeakPtrFactory and thereby
+// control how it exposes weak pointers to itself. This is helpful if you only
+// need weak pointers within the implementation of a class. This class is also
+// useful when working with primitive types. For example, you could have a
+// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool.
+template <class T>
+class WeakPtrFactory : public internal::WeakPtrFactoryBase {
+ public:
+ explicit WeakPtrFactory(T* ptr)
+ : WeakPtrFactoryBase(reinterpret_cast<uintptr_t>(ptr)) {}
+
+ ~WeakPtrFactory() = default;
+
+ WeakPtr<T> GetWeakPtr() {
+ return WeakPtr<T>(weak_reference_owner_.GetRef(),
+ reinterpret_cast<T*>(ptr_));
+ }
+
+ // Call this method to invalidate all existing weak pointers.
+ void InvalidateWeakPtrs() {
+ DCHECK(ptr_);
+ weak_reference_owner_.Invalidate();
+ }
+
+ // Call this method to determine if any weak pointers exist.
+ bool HasWeakPtrs() const {
+ DCHECK(ptr_);
+ return weak_reference_owner_.HasRefs();
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory);
+};
+
+// A class may extend from SupportsWeakPtr to let others take weak pointers to
+// it. This avoids the class itself implementing boilerplate to dispense weak
+// pointers. However, since SupportsWeakPtr's destructor won't invalidate
+// weak pointers to the class until after the derived class' members have been
+// destroyed, its use can lead to subtle use-after-destroy issues.
+template <class T>
+class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
+ public:
+ SupportsWeakPtr() = default;
+
+ WeakPtr<T> AsWeakPtr() {
+ return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this));
+ }
+
+ protected:
+ ~SupportsWeakPtr() = default;
+
+ private:
+ internal::WeakReferenceOwner weak_reference_owner_;
+ DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr);
+};
+
+// Helper function that uses type deduction to safely return a WeakPtr<Derived>
+// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it
+// extends a Base that extends SupportsWeakPtr<Base>.
+//
+// EXAMPLE:
+// class Base : public base::SupportsWeakPtr<Producer> {};
+// class Derived : public Base {};
+//
+// Derived derived;
+// base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived);
+//
+// Note that the following doesn't work (invalid type conversion) since
+// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(),
+// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at
+// the caller.
+//
+// base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails.
+
+template <typename Derived>
+WeakPtr<Derived> AsWeakPtr(Derived* t) {
+ return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t);
+}
+
+} // namespace base
+
+#endif // BASE_MEMORY_WEAK_PTR_H_
diff --git a/security/sandbox/chromium/base/no_destructor.h b/security/sandbox/chromium/base/no_destructor.h
new file mode 100644
index 0000000000..21cfef8565
--- /dev/null
+++ b/security/sandbox/chromium/base/no_destructor.h
@@ -0,0 +1,98 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NO_DESTRUCTOR_H_
+#define BASE_NO_DESTRUCTOR_H_
+
+#include <new>
+#include <utility>
+
+namespace base {
+
+// A wrapper that makes it easy to create an object of type T with static
+// storage duration that:
+// - is only constructed on first access
+// - never invokes the destructor
+// in order to satisfy the styleguide ban on global constructors and
+// destructors.
+//
+// Runtime constant example:
+// const std::string& GetLineSeparator() {
+// // Forwards to std::string(size_t, char, const Allocator&) constructor.
+// static const base::NoDestructor<std::string> s(5, '-');
+// return *s;
+// }
+//
+// More complex initialization with a lambda:
+// const std::string& GetSessionNonce() {
+// static const base::NoDestructor<std::string> nonce([] {
+// std::string s(16);
+// crypto::RandString(s.data(), s.size());
+// return s;
+// }());
+// return *nonce;
+// }
+//
+// NoDestructor<T> stores the object inline, so it also avoids a pointer
+// indirection and a malloc. Also note that since C++11 static local variable
+// initialization is thread-safe and so is this pattern. Code should prefer to
+// use NoDestructor<T> over:
+// - A function scoped static T* or T& that is dynamically initialized.
+// - A global base::LazyInstance<T>.
+//
+// Note that since the destructor is never run, this *will* leak memory if used
+// as a stack or member variable. Furthermore, a NoDestructor<T> should never
+// have global scope as that may require a static initializer.
+template <typename T>
+class NoDestructor {
+ public:
+ // Not constexpr; just write static constexpr T x = ...; if the value should
+ // be a constexpr.
+ template <typename... Args>
+ explicit NoDestructor(Args&&... args) {
+ new (storage_) T(std::forward<Args>(args)...);
+ }
+
+ // Allows copy and move construction of the contained type, to allow
+ // construction from an initializer list, e.g. for std::vector.
+ explicit NoDestructor(const T& x) { new (storage_) T(x); }
+ explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
+
+ NoDestructor(const NoDestructor&) = delete;
+ NoDestructor& operator=(const NoDestructor&) = delete;
+
+ ~NoDestructor() = default;
+
+ const T& operator*() const { return *get(); }
+ T& operator*() { return *get(); }
+
+ const T* operator->() const { return get(); }
+ T* operator->() { return get(); }
+
+ const T* get() const { return reinterpret_cast<const T*>(storage_); }
+ T* get() { return reinterpret_cast<T*>(storage_); }
+
+ private:
+ alignas(T) char storage_[sizeof(T)];
+
+#if defined(LEAK_SANITIZER)
+ // TODO(https://crbug.com/812277): This is a hack to work around the fact
+ // that LSan doesn't seem to treat NoDestructor as a root for reachability
+ // analysis. This means that code like this:
+ // static base::NoDestructor<std::vector<int>> v({1, 2, 3});
+ // is considered a leak. Using the standard leak sanitizer annotations to
+ // suppress leaks doesn't work: std::vector is implicitly constructed before
+ // calling the base::NoDestructor constructor.
+ //
+ // Unfortunately, I haven't been able to demonstrate this issue in simpler
+ // reproductions: until that's resolved, hold an explicit pointer to the
+ // placement-new'd object in leak sanitizer mode to help LSan realize that
+ // objects allocated by the contained type are still reachable.
+ T* storage_ptr_ = reinterpret_cast<T*>(storage_);
+#endif // defined(LEAK_SANITIZER)
+};
+
+} // namespace base
+
+#endif // BASE_NO_DESTRUCTOR_H_
diff --git a/security/sandbox/chromium/base/numerics/checked_math.h b/security/sandbox/chromium/base/numerics/checked_math.h
new file mode 100644
index 0000000000..ede3344f82
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/checked_math.h
@@ -0,0 +1,393 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_CHECKED_MATH_H_
+#define BASE_NUMERICS_CHECKED_MATH_H_
+
+#include <stddef.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/checked_math_impl.h"
+
+namespace base {
+namespace internal {
+
+template <typename T>
+class CheckedNumeric {
+ static_assert(std::is_arithmetic<T>::value,
+ "CheckedNumeric<T>: T must be a numeric type.");
+
+ public:
+ using type = T;
+
+ constexpr CheckedNumeric() = default;
+
+ // Copy constructor.
+ template <typename Src>
+ constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
+ : state_(rhs.state_.value(), rhs.IsValid()) {}
+
+ template <typename Src>
+ friend class CheckedNumeric;
+
+ // This is not an explicit constructor because we implicitly upgrade regular
+ // numerics to CheckedNumerics to make them easier to use.
+ template <typename Src>
+ constexpr CheckedNumeric(Src value) // NOLINT(runtime/explicit)
+ : state_(value) {
+ static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+ }
+
+ // This is not an explicit constructor because we want a seamless conversion
+ // from StrictNumeric types.
+ template <typename Src>
+ constexpr CheckedNumeric(
+ StrictNumeric<Src> value) // NOLINT(runtime/explicit)
+ : state_(static_cast<Src>(value)) {}
+
+ // IsValid() - The public API to test if a CheckedNumeric is currently valid.
+ // A range checked destination type can be supplied using the Dst template
+ // parameter.
+ template <typename Dst = T>
+ constexpr bool IsValid() const {
+ return state_.is_valid() &&
+ IsValueInRangeForNumericType<Dst>(state_.value());
+ }
+
+ // AssignIfValid(Dst) - Assigns the underlying value if it is currently valid
+ // and is within the range supported by the destination type. Returns true if
+ // successful and false otherwise.
+ template <typename Dst>
+#if defined(__clang__) || defined(__GNUC__)
+ __attribute__((warn_unused_result))
+#elif defined(_MSC_VER)
+ _Check_return_
+#endif
+ constexpr bool
+ AssignIfValid(Dst* result) const {
+ return BASE_NUMERICS_LIKELY(IsValid<Dst>())
+ ? ((*result = static_cast<Dst>(state_.value())), true)
+ : false;
+ }
+
+ // ValueOrDie() - The primary accessor for the underlying value. If the
+ // current state is not valid it will CHECK and crash.
+ // A range checked destination type can be supplied using the Dst template
+ // parameter, which will trigger a CHECK if the value is not in bounds for
+ // the destination.
+ // The CHECK behavior can be overridden by supplying a handler as a
+ // template parameter, for test code, etc. However, the handler cannot access
+ // the underlying value, and it is not available through other means.
+ template <typename Dst = T, class CheckHandler = CheckOnFailure>
+ constexpr StrictNumeric<Dst> ValueOrDie() const {
+ return BASE_NUMERICS_LIKELY(IsValid<Dst>())
+ ? static_cast<Dst>(state_.value())
+ : CheckHandler::template HandleFailure<Dst>();
+ }
+
+ // ValueOrDefault(T default_value) - A convenience method that returns the
+ // current value if the state is valid, and the supplied default_value for
+ // any other state.
+ // A range checked destination type can be supplied using the Dst template
+ // parameter. WARNING: This function may fail to compile or CHECK at runtime
+ // if the supplied default_value is not within range of the destination type.
+ template <typename Dst = T, typename Src>
+ constexpr StrictNumeric<Dst> ValueOrDefault(const Src default_value) const {
+ return BASE_NUMERICS_LIKELY(IsValid<Dst>())
+ ? static_cast<Dst>(state_.value())
+ : checked_cast<Dst>(default_value);
+ }
+
+ // Returns a checked numeric of the specified type, cast from the current
+ // CheckedNumeric. If the current state is invalid or the destination cannot
+ // represent the result then the returned CheckedNumeric will be invalid.
+ template <typename Dst>
+ constexpr CheckedNumeric<typename UnderlyingType<Dst>::type> Cast() const {
+ return *this;
+ }
+
+ // This friend method is available solely for providing more detailed logging
+ // in the the tests. Do not implement it in production code, because the
+ // underlying values may change at any time.
+ template <typename U>
+ friend U GetNumericValueForTest(const CheckedNumeric<U>& src);
+
+ // Prototypes for the supported arithmetic operator overloads.
+ template <typename Src>
+ constexpr CheckedNumeric& operator+=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator-=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator*=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator/=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator%=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator<<=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator>>=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator&=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator|=(const Src rhs);
+ template <typename Src>
+ constexpr CheckedNumeric& operator^=(const Src rhs);
+
+ constexpr CheckedNumeric operator-() const {
+ // The negation of two's complement int min is int min, so we simply
+ // check for that in the constexpr case.
+ // We use an optimized code path for a known run-time variable.
+ return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value ||
+ std::is_floating_point<T>::value
+ ? CheckedNumeric<T>(
+ NegateWrapper(state_.value()),
+ IsValid() && (!std::is_signed<T>::value ||
+ std::is_floating_point<T>::value ||
+ NegateWrapper(state_.value()) !=
+ std::numeric_limits<T>::lowest()))
+ : FastRuntimeNegate();
+ }
+
+ constexpr CheckedNumeric operator~() const {
+ return CheckedNumeric<decltype(InvertWrapper(T()))>(
+ InvertWrapper(state_.value()), IsValid());
+ }
+
+ constexpr CheckedNumeric Abs() const {
+ return !IsValueNegative(state_.value()) ? *this : -*this;
+ }
+
+ template <typename U>
+ constexpr CheckedNumeric<typename MathWrapper<CheckedMaxOp, T, U>::type> Max(
+ const U rhs) const {
+ using R = typename UnderlyingType<U>::type;
+ using result_type = typename MathWrapper<CheckedMaxOp, T, U>::type;
+ // TODO(jschuh): This can be converted to the MathOp version and remain
+ // constexpr once we have C++14 support.
+ return CheckedNumeric<result_type>(
+ static_cast<result_type>(
+ IsGreater<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
+ ? state_.value()
+ : Wrapper<U>::value(rhs)),
+ state_.is_valid() && Wrapper<U>::is_valid(rhs));
+ }
+
+ template <typename U>
+ constexpr CheckedNumeric<typename MathWrapper<CheckedMinOp, T, U>::type> Min(
+ const U rhs) const {
+ using R = typename UnderlyingType<U>::type;
+ using result_type = typename MathWrapper<CheckedMinOp, T, U>::type;
+ // TODO(jschuh): This can be converted to the MathOp version and remain
+ // constexpr once we have C++14 support.
+ return CheckedNumeric<result_type>(
+ static_cast<result_type>(
+ IsLess<T, R>::Test(state_.value(), Wrapper<U>::value(rhs))
+ ? state_.value()
+ : Wrapper<U>::value(rhs)),
+ state_.is_valid() && Wrapper<U>::is_valid(rhs));
+ }
+
+ // This function is available only for integral types. It returns an unsigned
+ // integer of the same width as the source type, containing the absolute value
+ // of the source, and properly handling signed min.
+ constexpr CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>
+ UnsignedAbs() const {
+ return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
+ SafeUnsignedAbs(state_.value()), state_.is_valid());
+ }
+
+ constexpr CheckedNumeric& operator++() {
+ *this += 1;
+ return *this;
+ }
+
+ constexpr CheckedNumeric operator++(int) {
+ CheckedNumeric value = *this;
+ *this += 1;
+ return value;
+ }
+
+ constexpr CheckedNumeric& operator--() {
+ *this -= 1;
+ return *this;
+ }
+
+ constexpr CheckedNumeric operator--(int) {
+ CheckedNumeric value = *this;
+ *this -= 1;
+ return value;
+ }
+
+ // These perform the actual math operations on the CheckedNumerics.
+ // Binary arithmetic operations.
+ template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+ static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) {
+ using Math = typename MathWrapper<M, L, R>::math;
+ T result = 0;
+ bool is_valid =
+ Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
+ Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
+ return CheckedNumeric<T>(result, is_valid);
+ }
+
+ // Assignment arithmetic operations.
+ template <template <typename, typename, typename> class M, typename R>
+ constexpr CheckedNumeric& MathOp(const R rhs) {
+ using Math = typename MathWrapper<M, T, R>::math;
+ T result = 0; // Using T as the destination saves a range check.
+ bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
+ Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
+ *this = CheckedNumeric<T>(result, is_valid);
+ return *this;
+ }
+
+ private:
+ CheckedNumericState<T> state_;
+
+ CheckedNumeric FastRuntimeNegate() const {
+ T result;
+ bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
+ return CheckedNumeric<T>(result, IsValid() && success);
+ }
+
+ template <typename Src>
+ constexpr CheckedNumeric(Src value, bool is_valid)
+ : state_(value, is_valid) {}
+
+ // These wrappers allow us to handle state the same way for both
+ // CheckedNumeric and POD arithmetic types.
+ template <typename Src>
+ struct Wrapper {
+ static constexpr bool is_valid(Src) { return true; }
+ static constexpr Src value(Src value) { return value; }
+ };
+
+ template <typename Src>
+ struct Wrapper<CheckedNumeric<Src>> {
+ static constexpr bool is_valid(const CheckedNumeric<Src> v) {
+ return v.IsValid();
+ }
+ static constexpr Src value(const CheckedNumeric<Src> v) {
+ return v.state_.value();
+ }
+ };
+
+ template <typename Src>
+ struct Wrapper<StrictNumeric<Src>> {
+ static constexpr bool is_valid(const StrictNumeric<Src>) { return true; }
+ static constexpr Src value(const StrictNumeric<Src> v) {
+ return static_cast<Src>(v);
+ }
+ };
+};
+
+// Convenience functions to avoid the ugly template disambiguator syntax.
+template <typename Dst, typename Src>
+constexpr bool IsValidForType(const CheckedNumeric<Src> value) {
+ return value.template IsValid<Dst>();
+}
+
+template <typename Dst, typename Src>
+constexpr StrictNumeric<Dst> ValueOrDieForType(
+ const CheckedNumeric<Src> value) {
+ return value.template ValueOrDie<Dst>();
+}
+
+template <typename Dst, typename Src, typename Default>
+constexpr StrictNumeric<Dst> ValueOrDefaultForType(
+ const CheckedNumeric<Src> value,
+ const Default default_value) {
+ return value.template ValueOrDefault<Dst>(default_value);
+}
+
+// Convience wrapper to return a new CheckedNumeric from the provided arithmetic
+// or CheckedNumericType.
+template <typename T>
+constexpr CheckedNumeric<typename UnderlyingType<T>::type> MakeCheckedNum(
+ const T value) {
+ return value;
+}
+
+// These implement the variadic wrapper for the math operations.
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+constexpr CheckedNumeric<typename MathWrapper<M, L, R>::type> CheckMathOp(
+ const L lhs,
+ const R rhs) {
+ using Math = typename MathWrapper<M, L, R>::math;
+ return CheckedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
+ rhs);
+}
+
+// General purpose wrapper template for arithmetic operations.
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R,
+ typename... Args>
+constexpr CheckedNumeric<typename ResultType<M, L, R, Args...>::type>
+CheckMathOp(const L lhs, const R rhs, const Args... args) {
+ return CheckMathOp<M>(CheckMathOp<M>(lhs, rhs), args...);
+}
+
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Add, +, +=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Sub, -, -=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mul, *, *=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Div, /, /=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Mod, %, %=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Lsh, <<, <<=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Rsh, >>, >>=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, And, &, &=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Or, |, |=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Checked, Check, Xor, ^, ^=)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Max)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min)
+
+// These are some extra StrictNumeric operators to support simple pointer
+// arithmetic with our result types. Since wrapping on a pointer is always
+// bad, we trigger the CHECK condition here.
+template <typename L, typename R>
+L* operator+(L* lhs, const StrictNumeric<R> rhs) {
+ uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
+ CheckMul(sizeof(L), static_cast<R>(rhs)))
+ .template ValueOrDie<uintptr_t>();
+ return reinterpret_cast<L*>(result);
+}
+
+template <typename L, typename R>
+L* operator-(L* lhs, const StrictNumeric<R> rhs) {
+ uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
+ CheckMul(sizeof(L), static_cast<R>(rhs)))
+ .template ValueOrDie<uintptr_t>();
+ return reinterpret_cast<L*>(result);
+}
+
+} // namespace internal
+
+using internal::CheckedNumeric;
+using internal::IsValidForType;
+using internal::ValueOrDieForType;
+using internal::ValueOrDefaultForType;
+using internal::MakeCheckedNum;
+using internal::CheckMax;
+using internal::CheckMin;
+using internal::CheckAdd;
+using internal::CheckSub;
+using internal::CheckMul;
+using internal::CheckDiv;
+using internal::CheckMod;
+using internal::CheckLsh;
+using internal::CheckRsh;
+using internal::CheckAnd;
+using internal::CheckOr;
+using internal::CheckXor;
+
+} // namespace base
+
+#endif // BASE_NUMERICS_CHECKED_MATH_H_
diff --git a/security/sandbox/chromium/base/numerics/checked_math_impl.h b/security/sandbox/chromium/base/numerics/checked_math_impl.h
new file mode 100644
index 0000000000..e083389ebf
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/checked_math_impl.h
@@ -0,0 +1,567 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_CHECKED_MATH_IMPL_H_
+#define BASE_NUMERICS_CHECKED_MATH_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math_shared_impl.h"
+
+namespace base {
+namespace internal {
+
+template <typename T>
+constexpr bool CheckedAddImpl(T x, T y, T* result) {
+ static_assert(std::is_integral<T>::value, "Type must be integral");
+ // Since the value of x+y is undefined if we have a signed type, we compute
+ // it using the unsigned type of the same size.
+ using UnsignedDst = typename std::make_unsigned<T>::type;
+ using SignedDst = typename std::make_signed<T>::type;
+ UnsignedDst ux = static_cast<UnsignedDst>(x);
+ UnsignedDst uy = static_cast<UnsignedDst>(y);
+ UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
+ *result = static_cast<T>(uresult);
+ // Addition is valid if the sign of (x + y) is equal to either that of x or
+ // that of y.
+ return (std::is_signed<T>::value)
+ ? static_cast<SignedDst>((uresult ^ ux) & (uresult ^ uy)) >= 0
+ : uresult >= uy; // Unsigned is either valid or underflow.
+}
+
+template <typename T, typename U, class Enable = void>
+struct CheckedAddOp {};
+
+template <typename T, typename U>
+struct CheckedAddOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ // TODO(jschuh) Make this "constexpr if" once we're C++17.
+ if (CheckedAddFastOp<T, U>::is_supported)
+ return CheckedAddFastOp<T, U>::Do(x, y, result);
+
+ // Double the underlying type up to a full machine word.
+ using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+ using Promotion =
+ typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
+ IntegerBitsPlusSign<intptr_t>::value),
+ typename BigEnoughPromotion<T, U>::type,
+ FastPromotion>::type;
+ // Fail if either operand is out of range for the promoted type.
+ // TODO(jschuh): This could be made to work for a broader range of values.
+ if (BASE_NUMERICS_UNLIKELY(!IsValueInRangeForNumericType<Promotion>(x) ||
+ !IsValueInRangeForNumericType<Promotion>(y))) {
+ return false;
+ }
+
+ Promotion presult = {};
+ bool is_valid = true;
+ if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
+ presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
+ } else {
+ is_valid = CheckedAddImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
+ }
+ *result = static_cast<V>(presult);
+ return is_valid && IsValueInRangeForNumericType<V>(presult);
+ }
+};
+
+template <typename T>
+constexpr bool CheckedSubImpl(T x, T y, T* result) {
+ static_assert(std::is_integral<T>::value, "Type must be integral");
+ // Since the value of x+y is undefined if we have a signed type, we compute
+ // it using the unsigned type of the same size.
+ using UnsignedDst = typename std::make_unsigned<T>::type;
+ using SignedDst = typename std::make_signed<T>::type;
+ UnsignedDst ux = static_cast<UnsignedDst>(x);
+ UnsignedDst uy = static_cast<UnsignedDst>(y);
+ UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
+ *result = static_cast<T>(uresult);
+ // Subtraction is valid if either x and y have same sign, or (x-y) and x have
+ // the same sign.
+ return (std::is_signed<T>::value)
+ ? static_cast<SignedDst>((uresult ^ ux) & (ux ^ uy)) >= 0
+ : x >= y;
+}
+
+template <typename T, typename U, class Enable = void>
+struct CheckedSubOp {};
+
+template <typename T, typename U>
+struct CheckedSubOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ // TODO(jschuh) Make this "constexpr if" once we're C++17.
+ if (CheckedSubFastOp<T, U>::is_supported)
+ return CheckedSubFastOp<T, U>::Do(x, y, result);
+
+ // Double the underlying type up to a full machine word.
+ using FastPromotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+ using Promotion =
+ typename std::conditional<(IntegerBitsPlusSign<FastPromotion>::value >
+ IntegerBitsPlusSign<intptr_t>::value),
+ typename BigEnoughPromotion<T, U>::type,
+ FastPromotion>::type;
+ // Fail if either operand is out of range for the promoted type.
+ // TODO(jschuh): This could be made to work for a broader range of values.
+ if (BASE_NUMERICS_UNLIKELY(!IsValueInRangeForNumericType<Promotion>(x) ||
+ !IsValueInRangeForNumericType<Promotion>(y))) {
+ return false;
+ }
+
+ Promotion presult = {};
+ bool is_valid = true;
+ if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
+ presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
+ } else {
+ is_valid = CheckedSubImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
+ }
+ *result = static_cast<V>(presult);
+ return is_valid && IsValueInRangeForNumericType<V>(presult);
+ }
+};
+
+template <typename T>
+constexpr bool CheckedMulImpl(T x, T y, T* result) {
+ static_assert(std::is_integral<T>::value, "Type must be integral");
+ // Since the value of x*y is potentially undefined if we have a signed type,
+ // we compute it using the unsigned type of the same size.
+ using UnsignedDst = typename std::make_unsigned<T>::type;
+ using SignedDst = typename std::make_signed<T>::type;
+ const UnsignedDst ux = SafeUnsignedAbs(x);
+ const UnsignedDst uy = SafeUnsignedAbs(y);
+ UnsignedDst uresult = static_cast<UnsignedDst>(ux * uy);
+ const bool is_negative =
+ std::is_signed<T>::value && static_cast<SignedDst>(x ^ y) < 0;
+ *result = is_negative ? 0 - uresult : uresult;
+ // We have a fast out for unsigned identity or zero on the second operand.
+ // After that it's an unsigned overflow check on the absolute value, with
+ // a +1 bound for a negative result.
+ return uy <= UnsignedDst(!std::is_signed<T>::value || is_negative) ||
+ ux <= (std::numeric_limits<T>::max() + UnsignedDst(is_negative)) / uy;
+}
+
+template <typename T, typename U, class Enable = void>
+struct CheckedMulOp {};
+
+template <typename T, typename U>
+struct CheckedMulOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ // TODO(jschuh) Make this "constexpr if" once we're C++17.
+ if (CheckedMulFastOp<T, U>::is_supported)
+ return CheckedMulFastOp<T, U>::Do(x, y, result);
+
+ using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+ // Verify the destination type can hold the result (always true for 0).
+ if (BASE_NUMERICS_UNLIKELY((!IsValueInRangeForNumericType<Promotion>(x) ||
+ !IsValueInRangeForNumericType<Promotion>(y)) &&
+ x && y)) {
+ return false;
+ }
+
+ Promotion presult = {};
+ bool is_valid = true;
+ if (CheckedMulFastOp<Promotion, Promotion>::is_supported) {
+ // The fast op may be available with the promoted type.
+ is_valid = CheckedMulFastOp<Promotion, Promotion>::Do(x, y, &presult);
+ } else if (IsIntegerArithmeticSafe<Promotion, T, U>::value) {
+ presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
+ } else {
+ is_valid = CheckedMulImpl(static_cast<Promotion>(x),
+ static_cast<Promotion>(y), &presult);
+ }
+ *result = static_cast<V>(presult);
+ return is_valid && IsValueInRangeForNumericType<V>(presult);
+ }
+};
+
+// Division just requires a check for a zero denominator or an invalid negation
+// on signed min/-1.
+template <typename T, typename U, class Enable = void>
+struct CheckedDivOp {};
+
+template <typename T, typename U>
+struct CheckedDivOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ if (BASE_NUMERICS_UNLIKELY(!y))
+ return false;
+
+ // The overflow check can be compiled away if we don't have the exact
+ // combination of types needed to trigger this case.
+ using Promotion = typename BigEnoughPromotion<T, U>::type;
+ if (BASE_NUMERICS_UNLIKELY(
+ (std::is_signed<T>::value && std::is_signed<U>::value &&
+ IsTypeInRangeForNumericType<T, Promotion>::value &&
+ static_cast<Promotion>(x) ==
+ std::numeric_limits<Promotion>::lowest() &&
+ y == static_cast<U>(-1)))) {
+ return false;
+ }
+
+ // This branch always compiles away if the above branch wasn't removed.
+ if (BASE_NUMERICS_UNLIKELY((!IsValueInRangeForNumericType<Promotion>(x) ||
+ !IsValueInRangeForNumericType<Promotion>(y)) &&
+ x)) {
+ return false;
+ }
+
+ Promotion presult = Promotion(x) / Promotion(y);
+ *result = static_cast<V>(presult);
+ return IsValueInRangeForNumericType<V>(presult);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedModOp {};
+
+template <typename T, typename U>
+struct CheckedModOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ using Promotion = typename BigEnoughPromotion<T, U>::type;
+ if (BASE_NUMERICS_LIKELY(y)) {
+ Promotion presult = static_cast<Promotion>(x) % static_cast<Promotion>(y);
+ *result = static_cast<Promotion>(presult);
+ return IsValueInRangeForNumericType<V>(presult);
+ }
+ return false;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedLshOp {};
+
+// Left shift. Shifts less than 0 or greater than or equal to the number
+// of bits in the promoted type are undefined. Shifts of negative values
+// are undefined. Otherwise it is defined when the result fits.
+template <typename T, typename U>
+struct CheckedLshOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = T;
+ template <typename V>
+ static constexpr bool Do(T x, U shift, V* result) {
+ // Disallow negative numbers and verify the shift is in bounds.
+ if (BASE_NUMERICS_LIKELY(!IsValueNegative(x) &&
+ as_unsigned(shift) <
+ as_unsigned(std::numeric_limits<T>::digits))) {
+ // Shift as unsigned to avoid undefined behavior.
+ *result = static_cast<V>(as_unsigned(x) << shift);
+ // If the shift can be reversed, we know it was valid.
+ return *result >> shift == x;
+ }
+
+ // Handle the legal corner-case of a full-width signed shift of zero.
+ return std::is_signed<T>::value && !x &&
+ as_unsigned(shift) == as_unsigned(std::numeric_limits<T>::digits);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedRshOp {};
+
+// Right shift. Shifts less than 0 or greater than or equal to the number
+// of bits in the promoted type are undefined. Otherwise, it is always defined,
+// but a right shift of a negative value is implementation-dependent.
+template <typename T, typename U>
+struct CheckedRshOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = T;
+ template <typename V>
+ static bool Do(T x, U shift, V* result) {
+ // Use the type conversion push negative values out of range.
+ if (BASE_NUMERICS_LIKELY(as_unsigned(shift) <
+ IntegerBitsPlusSign<T>::value)) {
+ T tmp = x >> shift;
+ *result = static_cast<V>(tmp);
+ return IsValueInRangeForNumericType<V>(tmp);
+ }
+ return false;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedAndOp {};
+
+// For simplicity we support only unsigned integer results.
+template <typename T, typename U>
+struct CheckedAndOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename std::make_unsigned<
+ typename MaxExponentPromotion<T, U>::type>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ result_type tmp = static_cast<result_type>(x) & static_cast<result_type>(y);
+ *result = static_cast<V>(tmp);
+ return IsValueInRangeForNumericType<V>(tmp);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedOrOp {};
+
+// For simplicity we support only unsigned integers.
+template <typename T, typename U>
+struct CheckedOrOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename std::make_unsigned<
+ typename MaxExponentPromotion<T, U>::type>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ result_type tmp = static_cast<result_type>(x) | static_cast<result_type>(y);
+ *result = static_cast<V>(tmp);
+ return IsValueInRangeForNumericType<V>(tmp);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct CheckedXorOp {};
+
+// For simplicity we support only unsigned integers.
+template <typename T, typename U>
+struct CheckedXorOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename std::make_unsigned<
+ typename MaxExponentPromotion<T, U>::type>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ result_type tmp = static_cast<result_type>(x) ^ static_cast<result_type>(y);
+ *result = static_cast<V>(tmp);
+ return IsValueInRangeForNumericType<V>(tmp);
+ }
+};
+
+// Max doesn't really need to be implemented this way because it can't fail,
+// but it makes the code much cleaner to use the MathOp wrappers.
+template <typename T, typename U, class Enable = void>
+struct CheckedMaxOp {};
+
+template <typename T, typename U>
+struct CheckedMaxOp<
+ T,
+ U,
+ typename std::enable_if<std::is_arithmetic<T>::value &&
+ std::is_arithmetic<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ result_type tmp = IsGreater<T, U>::Test(x, y) ? static_cast<result_type>(x)
+ : static_cast<result_type>(y);
+ *result = static_cast<V>(tmp);
+ return IsValueInRangeForNumericType<V>(tmp);
+ }
+};
+
+// Min doesn't really need to be implemented this way because it can't fail,
+// but it makes the code much cleaner to use the MathOp wrappers.
+template <typename T, typename U, class Enable = void>
+struct CheckedMinOp {};
+
+template <typename T, typename U>
+struct CheckedMinOp<
+ T,
+ U,
+ typename std::enable_if<std::is_arithmetic<T>::value &&
+ std::is_arithmetic<U>::value>::type> {
+ using result_type = typename LowestValuePromotion<T, U>::type;
+ template <typename V>
+ static constexpr bool Do(T x, U y, V* result) {
+ result_type tmp = IsLess<T, U>::Test(x, y) ? static_cast<result_type>(x)
+ : static_cast<result_type>(y);
+ *result = static_cast<V>(tmp);
+ return IsValueInRangeForNumericType<V>(tmp);
+ }
+};
+
+// This is just boilerplate that wraps the standard floating point arithmetic.
+// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
+#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
+ template <typename T, typename U> \
+ struct Checked##NAME##Op< \
+ T, U, \
+ typename std::enable_if<std::is_floating_point<T>::value || \
+ std::is_floating_point<U>::value>::type> { \
+ using result_type = typename MaxExponentPromotion<T, U>::type; \
+ template <typename V> \
+ static constexpr bool Do(T x, U y, V* result) { \
+ using Promotion = typename MaxExponentPromotion<T, U>::type; \
+ Promotion presult = x OP y; \
+ *result = static_cast<V>(presult); \
+ return IsValueInRangeForNumericType<V>(presult); \
+ } \
+ };
+
+BASE_FLOAT_ARITHMETIC_OPS(Add, +)
+BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
+BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
+BASE_FLOAT_ARITHMETIC_OPS(Div, /)
+
+#undef BASE_FLOAT_ARITHMETIC_OPS
+
+// Floats carry around their validity state with them, but integers do not. So,
+// we wrap the underlying value in a specialization in order to hide that detail
+// and expose an interface via accessors.
+enum NumericRepresentation {
+ NUMERIC_INTEGER,
+ NUMERIC_FLOATING,
+ NUMERIC_UNKNOWN
+};
+
+template <typename NumericType>
+struct GetNumericRepresentation {
+ static const NumericRepresentation value =
+ std::is_integral<NumericType>::value
+ ? NUMERIC_INTEGER
+ : (std::is_floating_point<NumericType>::value ? NUMERIC_FLOATING
+ : NUMERIC_UNKNOWN);
+};
+
+template <typename T,
+ NumericRepresentation type = GetNumericRepresentation<T>::value>
+class CheckedNumericState {};
+
+// Integrals require quite a bit of additional housekeeping to manage state.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_INTEGER> {
+ private:
+ // is_valid_ precedes value_ because member intializers in the constructors
+ // are evaluated in field order, and is_valid_ must be read when initializing
+ // value_.
+ bool is_valid_;
+ T value_;
+
+ // Ensures that a type conversion does not trigger undefined behavior.
+ template <typename Src>
+ static constexpr T WellDefinedConversionOrZero(const Src value,
+ const bool is_valid) {
+ using SrcType = typename internal::UnderlyingType<Src>::type;
+ return (std::is_integral<SrcType>::value || is_valid)
+ ? static_cast<T>(value)
+ : static_cast<T>(0);
+ }
+
+ public:
+ template <typename Src, NumericRepresentation type>
+ friend class CheckedNumericState;
+
+ constexpr CheckedNumericState() : is_valid_(true), value_(0) {}
+
+ template <typename Src>
+ constexpr CheckedNumericState(Src value, bool is_valid)
+ : is_valid_(is_valid && IsValueInRangeForNumericType<T>(value)),
+ value_(WellDefinedConversionOrZero(value, is_valid_)) {
+ static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+ }
+
+ // Copy constructor.
+ template <typename Src>
+ constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
+ : is_valid_(rhs.IsValid()),
+ value_(WellDefinedConversionOrZero(rhs.value(), is_valid_)) {}
+
+ template <typename Src>
+ constexpr explicit CheckedNumericState(Src value)
+ : is_valid_(IsValueInRangeForNumericType<T>(value)),
+ value_(WellDefinedConversionOrZero(value, is_valid_)) {}
+
+ constexpr bool is_valid() const { return is_valid_; }
+ constexpr T value() const { return value_; }
+};
+
+// Floating points maintain their own validity, but need translation wrappers.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_FLOATING> {
+ private:
+ T value_;
+
+ // Ensures that a type conversion does not trigger undefined behavior.
+ template <typename Src>
+ static constexpr T WellDefinedConversionOrNaN(const Src value,
+ const bool is_valid) {
+ using SrcType = typename internal::UnderlyingType<Src>::type;
+ return (StaticDstRangeRelationToSrcRange<T, SrcType>::value ==
+ NUMERIC_RANGE_CONTAINED ||
+ is_valid)
+ ? static_cast<T>(value)
+ : std::numeric_limits<T>::quiet_NaN();
+ }
+
+ public:
+ template <typename Src, NumericRepresentation type>
+ friend class CheckedNumericState;
+
+ constexpr CheckedNumericState() : value_(0.0) {}
+
+ template <typename Src>
+ constexpr CheckedNumericState(Src value, bool is_valid)
+ : value_(WellDefinedConversionOrNaN(value, is_valid)) {}
+
+ template <typename Src>
+ constexpr explicit CheckedNumericState(Src value)
+ : value_(WellDefinedConversionOrNaN(
+ value,
+ IsValueInRangeForNumericType<T>(value))) {}
+
+ // Copy constructor.
+ template <typename Src>
+ constexpr CheckedNumericState(const CheckedNumericState<Src>& rhs)
+ : value_(WellDefinedConversionOrNaN(
+ rhs.value(),
+ rhs.is_valid() && IsValueInRangeForNumericType<T>(rhs.value()))) {}
+
+ constexpr bool is_valid() const {
+ // Written this way because std::isfinite is not reliably constexpr.
+ return MustTreatAsConstexpr(value_)
+ ? value_ <= std::numeric_limits<T>::max() &&
+ value_ >= std::numeric_limits<T>::lowest()
+ : std::isfinite(value_);
+ }
+ constexpr T value() const { return value_; }
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_CHECKED_MATH_IMPL_H_
diff --git a/security/sandbox/chromium/base/numerics/clamped_math.h b/security/sandbox/chromium/base/numerics/clamped_math.h
new file mode 100644
index 0000000000..37a4cfd22a
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/clamped_math.h
@@ -0,0 +1,264 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_CLAMPED_MATH_H_
+#define BASE_NUMERICS_CLAMPED_MATH_H_
+
+#include <stddef.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/clamped_math_impl.h"
+
+namespace base {
+namespace internal {
+
+template <typename T>
+class ClampedNumeric {
+ static_assert(std::is_arithmetic<T>::value,
+ "ClampedNumeric<T>: T must be a numeric type.");
+
+ public:
+ using type = T;
+
+ constexpr ClampedNumeric() : value_(0) {}
+
+ // Copy constructor.
+ template <typename Src>
+ constexpr ClampedNumeric(const ClampedNumeric<Src>& rhs)
+ : value_(saturated_cast<T>(rhs.value_)) {}
+
+ template <typename Src>
+ friend class ClampedNumeric;
+
+ // This is not an explicit constructor because we implicitly upgrade regular
+ // numerics to ClampedNumerics to make them easier to use.
+ template <typename Src>
+ constexpr ClampedNumeric(Src value) // NOLINT(runtime/explicit)
+ : value_(saturated_cast<T>(value)) {
+ static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+ }
+
+ // This is not an explicit constructor because we want a seamless conversion
+ // from StrictNumeric types.
+ template <typename Src>
+ constexpr ClampedNumeric(
+ StrictNumeric<Src> value) // NOLINT(runtime/explicit)
+ : value_(saturated_cast<T>(static_cast<Src>(value))) {}
+
+ // Returns a ClampedNumeric of the specified type, cast from the current
+ // ClampedNumeric, and saturated to the destination type.
+ template <typename Dst>
+ constexpr ClampedNumeric<typename UnderlyingType<Dst>::type> Cast() const {
+ return *this;
+ }
+
+ // Prototypes for the supported arithmetic operator overloads.
+ template <typename Src>
+ constexpr ClampedNumeric& operator+=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator-=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator*=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator/=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator%=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator<<=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator>>=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator&=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator|=(const Src rhs);
+ template <typename Src>
+ constexpr ClampedNumeric& operator^=(const Src rhs);
+
+ constexpr ClampedNumeric operator-() const {
+ // The negation of two's complement int min is int min, so that's the
+ // only overflow case where we will saturate.
+ return ClampedNumeric<T>(SaturatedNegWrapper(value_));
+ }
+
+ constexpr ClampedNumeric operator~() const {
+ return ClampedNumeric<decltype(InvertWrapper(T()))>(InvertWrapper(value_));
+ }
+
+ constexpr ClampedNumeric Abs() const {
+ // The negation of two's complement int min is int min, so that's the
+ // only overflow case where we will saturate.
+ return ClampedNumeric<T>(SaturatedAbsWrapper(value_));
+ }
+
+ template <typename U>
+ constexpr ClampedNumeric<typename MathWrapper<ClampedMaxOp, T, U>::type> Max(
+ const U rhs) const {
+ using result_type = typename MathWrapper<ClampedMaxOp, T, U>::type;
+ return ClampedNumeric<result_type>(
+ ClampedMaxOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
+ }
+
+ template <typename U>
+ constexpr ClampedNumeric<typename MathWrapper<ClampedMinOp, T, U>::type> Min(
+ const U rhs) const {
+ using result_type = typename MathWrapper<ClampedMinOp, T, U>::type;
+ return ClampedNumeric<result_type>(
+ ClampedMinOp<T, U>::Do(value_, Wrapper<U>::value(rhs)));
+ }
+
+ // This function is available only for integral types. It returns an unsigned
+ // integer of the same width as the source type, containing the absolute value
+ // of the source, and properly handling signed min.
+ constexpr ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>
+ UnsignedAbs() const {
+ return ClampedNumeric<typename UnsignedOrFloatForSize<T>::type>(
+ SafeUnsignedAbs(value_));
+ }
+
+ constexpr ClampedNumeric& operator++() {
+ *this += 1;
+ return *this;
+ }
+
+ constexpr ClampedNumeric operator++(int) {
+ ClampedNumeric value = *this;
+ *this += 1;
+ return value;
+ }
+
+ constexpr ClampedNumeric& operator--() {
+ *this -= 1;
+ return *this;
+ }
+
+ constexpr ClampedNumeric operator--(int) {
+ ClampedNumeric value = *this;
+ *this -= 1;
+ return value;
+ }
+
+ // These perform the actual math operations on the ClampedNumerics.
+ // Binary arithmetic operations.
+ template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+ static constexpr ClampedNumeric MathOp(const L lhs, const R rhs) {
+ using Math = typename MathWrapper<M, L, R>::math;
+ return ClampedNumeric<T>(
+ Math::template Do<T>(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs)));
+ }
+
+ // Assignment arithmetic operations.
+ template <template <typename, typename, typename> class M, typename R>
+ constexpr ClampedNumeric& MathOp(const R rhs) {
+ using Math = typename MathWrapper<M, T, R>::math;
+ *this =
+ ClampedNumeric<T>(Math::template Do<T>(value_, Wrapper<R>::value(rhs)));
+ return *this;
+ }
+
+ template <typename Dst>
+ constexpr operator Dst() const {
+ return saturated_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(
+ value_);
+ }
+
+ // This method extracts the raw integer value without saturating it to the
+ // destination type as the conversion operator does. This is useful when
+ // e.g. assigning to an auto type or passing as a deduced template parameter.
+ constexpr T RawValue() const { return value_; }
+
+ private:
+ T value_;
+
+ // These wrappers allow us to handle state the same way for both
+ // ClampedNumeric and POD arithmetic types.
+ template <typename Src>
+ struct Wrapper {
+ static constexpr Src value(Src value) {
+ return static_cast<typename UnderlyingType<Src>::type>(value);
+ }
+ };
+};
+
+// Convience wrapper to return a new ClampedNumeric from the provided arithmetic
+// or ClampedNumericType.
+template <typename T>
+constexpr ClampedNumeric<typename UnderlyingType<T>::type> MakeClampedNum(
+ const T value) {
+ return value;
+}
+
+#if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS
+// Overload the ostream output operator to make logging work nicely.
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const ClampedNumeric<T>& value) {
+ os << static_cast<T>(value);
+ return os;
+}
+#endif
+
+// These implement the variadic wrapper for the math operations.
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+constexpr ClampedNumeric<typename MathWrapper<M, L, R>::type> ClampMathOp(
+ const L lhs,
+ const R rhs) {
+ using Math = typename MathWrapper<M, L, R>::math;
+ return ClampedNumeric<typename Math::result_type>::template MathOp<M>(lhs,
+ rhs);
+}
+
+// General purpose wrapper template for arithmetic operations.
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R,
+ typename... Args>
+constexpr ClampedNumeric<typename ResultType<M, L, R, Args...>::type>
+ClampMathOp(const L lhs, const R rhs, const Args... args) {
+ return ClampMathOp<M>(ClampMathOp<M>(lhs, rhs), args...);
+}
+
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Add, +, +=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Sub, -, -=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mul, *, *=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Div, /, /=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Mod, %, %=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Lsh, <<, <<=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Rsh, >>, >>=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, And, &, &=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Or, |, |=)
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Clamped, Clamp, Xor, ^, ^=)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Max)
+BASE_NUMERIC_ARITHMETIC_VARIADIC(Clamped, Clamp, Min)
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLess, <)
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsLessOrEqual, <=)
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreater, >)
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsGreaterOrEqual, >=)
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsEqual, ==)
+BASE_NUMERIC_COMPARISON_OPERATORS(Clamped, IsNotEqual, !=)
+
+} // namespace internal
+
+using internal::ClampedNumeric;
+using internal::MakeClampedNum;
+using internal::ClampMax;
+using internal::ClampMin;
+using internal::ClampAdd;
+using internal::ClampSub;
+using internal::ClampMul;
+using internal::ClampDiv;
+using internal::ClampMod;
+using internal::ClampLsh;
+using internal::ClampRsh;
+using internal::ClampAnd;
+using internal::ClampOr;
+using internal::ClampXor;
+
+} // namespace base
+
+#endif // BASE_NUMERICS_CLAMPED_MATH_H_
diff --git a/security/sandbox/chromium/base/numerics/clamped_math_impl.h b/security/sandbox/chromium/base/numerics/clamped_math_impl.h
new file mode 100644
index 0000000000..303a7e945a
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/clamped_math_impl.h
@@ -0,0 +1,341 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
+#define BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/checked_math.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math_shared_impl.h"
+
+namespace base {
+namespace internal {
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_signed<T>::value>::type* = nullptr>
+constexpr T SaturatedNegWrapper(T value) {
+ return MustTreatAsConstexpr(value) || !ClampedNegFastOp<T>::is_supported
+ ? (NegateWrapper(value) != std::numeric_limits<T>::lowest()
+ ? NegateWrapper(value)
+ : std::numeric_limits<T>::max())
+ : ClampedNegFastOp<T>::Do(value);
+}
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value &&
+ !std::is_signed<T>::value>::type* = nullptr>
+constexpr T SaturatedNegWrapper(T value) {
+ return T(0);
+}
+
+template <
+ typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T SaturatedNegWrapper(T value) {
+ return -value;
+}
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr T SaturatedAbsWrapper(T value) {
+ // The calculation below is a static identity for unsigned types, but for
+ // signed integer types it provides a non-branching, saturated absolute value.
+ // This works because SafeUnsignedAbs() returns an unsigned type, which can
+ // represent the absolute value of all negative numbers of an equal-width
+ // integer type. The call to IsValueNegative() then detects overflow in the
+ // special case of numeric_limits<T>::min(), by evaluating the bit pattern as
+ // a signed integer value. If it is the overflow case, we end up subtracting
+ // one from the unsigned result, thus saturating to numeric_limits<T>::max().
+ return static_cast<T>(SafeUnsignedAbs(value) -
+ IsValueNegative<T>(SafeUnsignedAbs(value)));
+}
+
+template <
+ typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T SaturatedAbsWrapper(T value) {
+ return value < 0 ? -value : value;
+}
+
+template <typename T, typename U, class Enable = void>
+struct ClampedAddOp {};
+
+template <typename T, typename U>
+struct ClampedAddOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U y) {
+ if (ClampedAddFastOp<T, U>::is_supported)
+ return ClampedAddFastOp<T, U>::template Do<V>(x, y);
+
+ static_assert(std::is_same<V, result_type>::value ||
+ IsTypeInRangeForNumericType<U, V>::value,
+ "The saturation result cannot be determined from the "
+ "provided types.");
+ const V saturated = CommonMaxOrMin<V>(IsValueNegative(y));
+ V result = {};
+ return BASE_NUMERICS_LIKELY((CheckedAddOp<T, U>::Do(x, y, &result)))
+ ? result
+ : saturated;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedSubOp {};
+
+template <typename T, typename U>
+struct ClampedSubOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U y) {
+ // TODO(jschuh) Make this "constexpr if" once we're C++17.
+ if (ClampedSubFastOp<T, U>::is_supported)
+ return ClampedSubFastOp<T, U>::template Do<V>(x, y);
+
+ static_assert(std::is_same<V, result_type>::value ||
+ IsTypeInRangeForNumericType<U, V>::value,
+ "The saturation result cannot be determined from the "
+ "provided types.");
+ const V saturated = CommonMaxOrMin<V>(!IsValueNegative(y));
+ V result = {};
+ return BASE_NUMERICS_LIKELY((CheckedSubOp<T, U>::Do(x, y, &result)))
+ ? result
+ : saturated;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedMulOp {};
+
+template <typename T, typename U>
+struct ClampedMulOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U y) {
+ // TODO(jschuh) Make this "constexpr if" once we're C++17.
+ if (ClampedMulFastOp<T, U>::is_supported)
+ return ClampedMulFastOp<T, U>::template Do<V>(x, y);
+
+ V result = {};
+ const V saturated =
+ CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
+ return BASE_NUMERICS_LIKELY((CheckedMulOp<T, U>::Do(x, y, &result)))
+ ? result
+ : saturated;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedDivOp {};
+
+template <typename T, typename U>
+struct ClampedDivOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U y) {
+ V result = {};
+ if (BASE_NUMERICS_LIKELY((CheckedDivOp<T, U>::Do(x, y, &result))))
+ return result;
+ // Saturation goes to max, min, or NaN (if x is zero).
+ return x ? CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y))
+ : SaturationDefaultLimits<V>::NaN();
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedModOp {};
+
+template <typename T, typename U>
+struct ClampedModOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U y) {
+ V result = {};
+ return BASE_NUMERICS_LIKELY((CheckedModOp<T, U>::Do(x, y, &result)))
+ ? result
+ : x;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedLshOp {};
+
+// Left shift. Non-zero values saturate in the direction of the sign. A zero
+// shifted by any value always results in zero.
+template <typename T, typename U>
+struct ClampedLshOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = T;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U shift) {
+ static_assert(!std::is_signed<U>::value, "Shift value must be unsigned.");
+ if (BASE_NUMERICS_LIKELY(shift < std::numeric_limits<T>::digits)) {
+ // Shift as unsigned to avoid undefined behavior.
+ V result = static_cast<V>(as_unsigned(x) << shift);
+ // If the shift can be reversed, we know it was valid.
+ if (BASE_NUMERICS_LIKELY(result >> shift == x))
+ return result;
+ }
+ return x ? CommonMaxOrMin<V>(IsValueNegative(x)) : 0;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedRshOp {};
+
+// Right shift. Negative values saturate to -1. Positive or 0 saturates to 0.
+template <typename T, typename U>
+struct ClampedRshOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = T;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U shift) {
+ static_assert(!std::is_signed<U>::value, "Shift value must be unsigned.");
+ // Signed right shift is odd, because it saturates to -1 or 0.
+ const V saturated = as_unsigned(V(0)) - IsValueNegative(x);
+ return BASE_NUMERICS_LIKELY(shift < IntegerBitsPlusSign<T>::value)
+ ? saturated_cast<V>(x >> shift)
+ : saturated;
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedAndOp {};
+
+template <typename T, typename U>
+struct ClampedAndOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename std::make_unsigned<
+ typename MaxExponentPromotion<T, U>::type>::type;
+ template <typename V>
+ static constexpr V Do(T x, U y) {
+ return static_cast<result_type>(x) & static_cast<result_type>(y);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedOrOp {};
+
+// For simplicity we promote to unsigned integers.
+template <typename T, typename U>
+struct ClampedOrOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename std::make_unsigned<
+ typename MaxExponentPromotion<T, U>::type>::type;
+ template <typename V>
+ static constexpr V Do(T x, U y) {
+ return static_cast<result_type>(x) | static_cast<result_type>(y);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedXorOp {};
+
+// For simplicity we support only unsigned integers.
+template <typename T, typename U>
+struct ClampedXorOp<T,
+ U,
+ typename std::enable_if<std::is_integral<T>::value &&
+ std::is_integral<U>::value>::type> {
+ using result_type = typename std::make_unsigned<
+ typename MaxExponentPromotion<T, U>::type>::type;
+ template <typename V>
+ static constexpr V Do(T x, U y) {
+ return static_cast<result_type>(x) ^ static_cast<result_type>(y);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedMaxOp {};
+
+template <typename T, typename U>
+struct ClampedMaxOp<
+ T,
+ U,
+ typename std::enable_if<std::is_arithmetic<T>::value &&
+ std::is_arithmetic<U>::value>::type> {
+ using result_type = typename MaxExponentPromotion<T, U>::type;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U y) {
+ return IsGreater<T, U>::Test(x, y) ? saturated_cast<V>(x)
+ : saturated_cast<V>(y);
+ }
+};
+
+template <typename T, typename U, class Enable = void>
+struct ClampedMinOp {};
+
+template <typename T, typename U>
+struct ClampedMinOp<
+ T,
+ U,
+ typename std::enable_if<std::is_arithmetic<T>::value &&
+ std::is_arithmetic<U>::value>::type> {
+ using result_type = typename LowestValuePromotion<T, U>::type;
+ template <typename V = result_type>
+ static constexpr V Do(T x, U y) {
+ return IsLess<T, U>::Test(x, y) ? saturated_cast<V>(x)
+ : saturated_cast<V>(y);
+ }
+};
+
+// This is just boilerplate that wraps the standard floating point arithmetic.
+// A macro isn't the nicest solution, but it beats rewriting these repeatedly.
+#define BASE_FLOAT_ARITHMETIC_OPS(NAME, OP) \
+ template <typename T, typename U> \
+ struct Clamped##NAME##Op< \
+ T, U, \
+ typename std::enable_if<std::is_floating_point<T>::value || \
+ std::is_floating_point<U>::value>::type> { \
+ using result_type = typename MaxExponentPromotion<T, U>::type; \
+ template <typename V = result_type> \
+ static constexpr V Do(T x, U y) { \
+ return saturated_cast<V>(x OP y); \
+ } \
+ };
+
+BASE_FLOAT_ARITHMETIC_OPS(Add, +)
+BASE_FLOAT_ARITHMETIC_OPS(Sub, -)
+BASE_FLOAT_ARITHMETIC_OPS(Mul, *)
+BASE_FLOAT_ARITHMETIC_OPS(Div, /)
+
+#undef BASE_FLOAT_ARITHMETIC_OPS
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_CLAMPED_MATH_IMPL_H_
diff --git a/security/sandbox/chromium/base/numerics/safe_conversions.h b/security/sandbox/chromium/base/numerics/safe_conversions.h
new file mode 100644
index 0000000000..b9636fec42
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/safe_conversions.h
@@ -0,0 +1,358 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
+
+#include <stddef.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions_impl.h"
+
+#if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__))
+#include "base/numerics/safe_conversions_arm_impl.h"
+#define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (1)
+#else
+#define BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS (0)
+#endif
+
+#if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS
+#include <ostream>
+#endif
+
+namespace base {
+namespace internal {
+
+#if !BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
+template <typename Dst, typename Src>
+struct SaturateFastAsmOp {
+ static const bool is_supported = false;
+ static constexpr Dst Do(Src) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<Dst>();
+ }
+};
+#endif // BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
+#undef BASE_HAS_OPTIMIZED_SAFE_CONVERSIONS
+
+// The following special case a few specific integer conversions where we can
+// eke out better performance than range checking.
+template <typename Dst, typename Src, typename Enable = void>
+struct IsValueInRangeFastOp {
+ static const bool is_supported = false;
+ static constexpr bool Do(Src value) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<bool>();
+ }
+};
+
+// Signed to signed range comparison.
+template <typename Dst, typename Src>
+struct IsValueInRangeFastOp<
+ Dst,
+ Src,
+ typename std::enable_if<
+ std::is_integral<Dst>::value && std::is_integral<Src>::value &&
+ std::is_signed<Dst>::value && std::is_signed<Src>::value &&
+ !IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
+ static const bool is_supported = true;
+
+ static constexpr bool Do(Src value) {
+ // Just downcast to the smaller type, sign extend it back to the original
+ // type, and then see if it matches the original value.
+ return value == static_cast<Dst>(value);
+ }
+};
+
+// Signed to unsigned range comparison.
+template <typename Dst, typename Src>
+struct IsValueInRangeFastOp<
+ Dst,
+ Src,
+ typename std::enable_if<
+ std::is_integral<Dst>::value && std::is_integral<Src>::value &&
+ !std::is_signed<Dst>::value && std::is_signed<Src>::value &&
+ !IsTypeInRangeForNumericType<Dst, Src>::value>::type> {
+ static const bool is_supported = true;
+
+ static constexpr bool Do(Src value) {
+ // We cast a signed as unsigned to overflow negative values to the top,
+ // then compare against whichever maximum is smaller, as our upper bound.
+ return as_unsigned(value) <= as_unsigned(CommonMax<Src, Dst>());
+ }
+};
+
+// Convenience function that returns true if the supplied value is in range
+// for the destination type.
+template <typename Dst, typename Src>
+constexpr bool IsValueInRangeForNumericType(Src value) {
+ using SrcType = typename internal::UnderlyingType<Src>::type;
+ return internal::IsValueInRangeFastOp<Dst, SrcType>::is_supported
+ ? internal::IsValueInRangeFastOp<Dst, SrcType>::Do(
+ static_cast<SrcType>(value))
+ : internal::DstRangeRelationToSrcRange<Dst>(
+ static_cast<SrcType>(value))
+ .IsValid();
+}
+
+// checked_cast<> is analogous to static_cast<> for numeric types,
+// except that it CHECKs that the specified numeric conversion will not
+// overflow or underflow. NaN source will always trigger a CHECK.
+template <typename Dst,
+ class CheckHandler = internal::CheckOnFailure,
+ typename Src>
+constexpr Dst checked_cast(Src value) {
+ // This throws a compile-time error on evaluating the constexpr if it can be
+ // determined at compile-time as failing, otherwise it will CHECK at runtime.
+ using SrcType = typename internal::UnderlyingType<Src>::type;
+ return BASE_NUMERICS_LIKELY((IsValueInRangeForNumericType<Dst>(value)))
+ ? static_cast<Dst>(static_cast<SrcType>(value))
+ : CheckHandler::template HandleFailure<Dst>();
+}
+
+// Default boundaries for integral/float: max/infinity, lowest/-infinity, 0/NaN.
+// You may provide your own limits (e.g. to saturated_cast) so long as you
+// implement all of the static constexpr member functions in the class below.
+template <typename T>
+struct SaturationDefaultLimits : public std::numeric_limits<T> {
+ static constexpr T NaN() {
+ return std::numeric_limits<T>::has_quiet_NaN
+ ? std::numeric_limits<T>::quiet_NaN()
+ : T();
+ }
+ using std::numeric_limits<T>::max;
+ static constexpr T Overflow() {
+ return std::numeric_limits<T>::has_infinity
+ ? std::numeric_limits<T>::infinity()
+ : std::numeric_limits<T>::max();
+ }
+ using std::numeric_limits<T>::lowest;
+ static constexpr T Underflow() {
+ return std::numeric_limits<T>::has_infinity
+ ? std::numeric_limits<T>::infinity() * -1
+ : std::numeric_limits<T>::lowest();
+ }
+};
+
+template <typename Dst, template <typename> class S, typename Src>
+constexpr Dst saturated_cast_impl(Src value, RangeCheck constraint) {
+ // For some reason clang generates much better code when the branch is
+ // structured exactly this way, rather than a sequence of checks.
+ return !constraint.IsOverflowFlagSet()
+ ? (!constraint.IsUnderflowFlagSet() ? static_cast<Dst>(value)
+ : S<Dst>::Underflow())
+ // Skip this check for integral Src, which cannot be NaN.
+ : (std::is_integral<Src>::value || !constraint.IsUnderflowFlagSet()
+ ? S<Dst>::Overflow()
+ : S<Dst>::NaN());
+}
+
+// We can reduce the number of conditions and get slightly better performance
+// for normal signed and unsigned integer ranges. And in the specific case of
+// Arm, we can use the optimized saturation instructions.
+template <typename Dst, typename Src, typename Enable = void>
+struct SaturateFastOp {
+ static const bool is_supported = false;
+ static constexpr Dst Do(Src value) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<Dst>();
+ }
+};
+
+template <typename Dst, typename Src>
+struct SaturateFastOp<
+ Dst,
+ Src,
+ typename std::enable_if<std::is_integral<Src>::value &&
+ std::is_integral<Dst>::value &&
+ SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
+ static const bool is_supported = true;
+ static Dst Do(Src value) { return SaturateFastAsmOp<Dst, Src>::Do(value); }
+};
+
+template <typename Dst, typename Src>
+struct SaturateFastOp<
+ Dst,
+ Src,
+ typename std::enable_if<std::is_integral<Src>::value &&
+ std::is_integral<Dst>::value &&
+ !SaturateFastAsmOp<Dst, Src>::is_supported>::type> {
+ static const bool is_supported = true;
+ static Dst Do(Src value) {
+ // The exact order of the following is structured to hit the correct
+ // optimization heuristics across compilers. Do not change without
+ // checking the emitted code.
+ Dst saturated = CommonMaxOrMin<Dst, Src>(
+ IsMaxInRangeForNumericType<Dst, Src>() ||
+ (!IsMinInRangeForNumericType<Dst, Src>() && IsValueNegative(value)));
+ return BASE_NUMERICS_LIKELY(IsValueInRangeForNumericType<Dst>(value))
+ ? static_cast<Dst>(value)
+ : saturated;
+ }
+};
+
+// saturated_cast<> is analogous to static_cast<> for numeric types, except
+// that the specified numeric conversion will saturate by default rather than
+// overflow or underflow, and NaN assignment to an integral will return 0.
+// All boundary condition behaviors can be overriden with a custom handler.
+template <typename Dst,
+ template <typename> class SaturationHandler = SaturationDefaultLimits,
+ typename Src>
+constexpr Dst saturated_cast(Src value) {
+ using SrcType = typename UnderlyingType<Src>::type;
+ return !IsCompileTimeConstant(value) &&
+ SaturateFastOp<Dst, SrcType>::is_supported &&
+ std::is_same<SaturationHandler<Dst>,
+ SaturationDefaultLimits<Dst>>::value
+ ? SaturateFastOp<Dst, SrcType>::Do(static_cast<SrcType>(value))
+ : saturated_cast_impl<Dst, SaturationHandler, SrcType>(
+ static_cast<SrcType>(value),
+ DstRangeRelationToSrcRange<Dst, SaturationHandler, SrcType>(
+ static_cast<SrcType>(value)));
+}
+
+// strict_cast<> is analogous to static_cast<> for numeric types, except that
+// it will cause a compile failure if the destination type is not large enough
+// to contain any value in the source type. It performs no runtime checking.
+template <typename Dst, typename Src>
+constexpr Dst strict_cast(Src value) {
+ using SrcType = typename UnderlyingType<Src>::type;
+ static_assert(UnderlyingType<Src>::is_numeric, "Argument must be numeric.");
+ static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
+
+ // If you got here from a compiler error, it's because you tried to assign
+ // from a source type to a destination type that has insufficient range.
+ // The solution may be to change the destination type you're assigning to,
+ // and use one large enough to represent the source.
+ // Alternatively, you may be better served with the checked_cast<> or
+ // saturated_cast<> template functions for your particular use case.
+ static_assert(StaticDstRangeRelationToSrcRange<Dst, SrcType>::value ==
+ NUMERIC_RANGE_CONTAINED,
+ "The source type is out of range for the destination type. "
+ "Please see strict_cast<> comments for more information.");
+
+ return static_cast<Dst>(static_cast<SrcType>(value));
+}
+
+// Some wrappers to statically check that a type is in range.
+template <typename Dst, typename Src, class Enable = void>
+struct IsNumericRangeContained {
+ static const bool value = false;
+};
+
+template <typename Dst, typename Src>
+struct IsNumericRangeContained<
+ Dst,
+ Src,
+ typename std::enable_if<ArithmeticOrUnderlyingEnum<Dst>::value &&
+ ArithmeticOrUnderlyingEnum<Src>::value>::type> {
+ static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+ NUMERIC_RANGE_CONTAINED;
+};
+
+// StrictNumeric implements compile time range checking between numeric types by
+// wrapping assignment operations in a strict_cast. This class is intended to be
+// used for function arguments and return types, to ensure the destination type
+// can always contain the source type. This is essentially the same as enforcing
+// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied
+// incrementally at API boundaries, making it easier to convert code so that it
+// compiles cleanly with truncation warnings enabled.
+// This template should introduce no runtime overhead, but it also provides no
+// runtime checking of any of the associated mathematical operations. Use
+// CheckedNumeric for runtime range checks of the actual value being assigned.
+template <typename T>
+class StrictNumeric {
+ public:
+ using type = T;
+
+ constexpr StrictNumeric() : value_(0) {}
+
+ // Copy constructor.
+ template <typename Src>
+ constexpr StrictNumeric(const StrictNumeric<Src>& rhs)
+ : value_(strict_cast<T>(rhs.value_)) {}
+
+ // This is not an explicit constructor because we implicitly upgrade regular
+ // numerics to StrictNumerics to make them easier to use.
+ template <typename Src>
+ constexpr StrictNumeric(Src value) // NOLINT(runtime/explicit)
+ : value_(strict_cast<T>(value)) {}
+
+ // If you got here from a compiler error, it's because you tried to assign
+ // from a source type to a destination type that has insufficient range.
+ // The solution may be to change the destination type you're assigning to,
+ // and use one large enough to represent the source.
+ // If you're assigning from a CheckedNumeric<> class, you may be able to use
+ // the AssignIfValid() member function, specify a narrower destination type to
+ // the member value functions (e.g. val.template ValueOrDie<Dst>()), use one
+ // of the value helper functions (e.g. ValueOrDieForType<Dst>(val)).
+ // If you've encountered an _ambiguous overload_ you can use a static_cast<>
+ // to explicitly cast the result to the destination type.
+ // If none of that works, you may be better served with the checked_cast<> or
+ // saturated_cast<> template functions for your particular use case.
+ template <typename Dst,
+ typename std::enable_if<
+ IsNumericRangeContained<Dst, T>::value>::type* = nullptr>
+ constexpr operator Dst() const {
+ return static_cast<typename ArithmeticOrUnderlyingEnum<Dst>::type>(value_);
+ }
+
+ private:
+ const T value_;
+};
+
+// Convience wrapper returns a StrictNumeric from the provided arithmetic type.
+template <typename T>
+constexpr StrictNumeric<typename UnderlyingType<T>::type> MakeStrictNum(
+ const T value) {
+ return value;
+}
+
+#if !BASE_NUMERICS_DISABLE_OSTREAM_OPERATORS
+// Overload the ostream output operator to make logging work nicely.
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const StrictNumeric<T>& value) {
+ os << static_cast<T>(value);
+ return os;
+}
+#endif
+
+#define BASE_NUMERIC_COMPARISON_OPERATORS(CLASS, NAME, OP) \
+ template <typename L, typename R, \
+ typename std::enable_if< \
+ internal::Is##CLASS##Op<L, R>::value>::type* = nullptr> \
+ constexpr bool operator OP(const L lhs, const R rhs) { \
+ return SafeCompare<NAME, typename UnderlyingType<L>::type, \
+ typename UnderlyingType<R>::type>(lhs, rhs); \
+ }
+
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLess, <)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsLessOrEqual, <=)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreater, >)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsGreaterOrEqual, >=)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsEqual, ==)
+BASE_NUMERIC_COMPARISON_OPERATORS(Strict, IsNotEqual, !=)
+
+} // namespace internal
+
+using internal::as_signed;
+using internal::as_unsigned;
+using internal::checked_cast;
+using internal::strict_cast;
+using internal::saturated_cast;
+using internal::SafeUnsignedAbs;
+using internal::StrictNumeric;
+using internal::MakeStrictNum;
+using internal::IsValueInRangeForNumericType;
+using internal::IsTypeInRangeForNumericType;
+using internal::IsValueNegative;
+
+// Explicitly make a shorter size_t alias for convenience.
+using SizeT = StrictNumeric<size_t>;
+
+} // namespace base
+
+#endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/security/sandbox/chromium/base/numerics/safe_conversions_arm_impl.h b/security/sandbox/chromium/base/numerics/safe_conversions_arm_impl.h
new file mode 100644
index 0000000000..cf31072b9b
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/safe_conversions_arm_impl.h
@@ -0,0 +1,51 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_ARM_IMPL_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_ARM_IMPL_H_
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions_impl.h"
+
+namespace base {
+namespace internal {
+
+// Fast saturation to a destination type.
+template <typename Dst, typename Src>
+struct SaturateFastAsmOp {
+ static constexpr bool is_supported =
+ std::is_signed<Src>::value && std::is_integral<Dst>::value &&
+ std::is_integral<Src>::value &&
+ IntegerBitsPlusSign<Src>::value <= IntegerBitsPlusSign<int32_t>::value &&
+ IntegerBitsPlusSign<Dst>::value <= IntegerBitsPlusSign<int32_t>::value &&
+ !IsTypeInRangeForNumericType<Dst, Src>::value;
+
+ __attribute__((always_inline)) static Dst Do(Src value) {
+ int32_t src = value;
+ typename std::conditional<std::is_signed<Dst>::value, int32_t,
+ uint32_t>::type result;
+ if (std::is_signed<Dst>::value) {
+ asm("ssat %[dst], %[shift], %[src]"
+ : [dst] "=r"(result)
+ : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign<Dst>::value <= 32
+ ? IntegerBitsPlusSign<Dst>::value
+ : 32));
+ } else {
+ asm("usat %[dst], %[shift], %[src]"
+ : [dst] "=r"(result)
+ : [src] "r"(src), [shift] "n"(IntegerBitsPlusSign<Dst>::value < 32
+ ? IntegerBitsPlusSign<Dst>::value
+ : 31));
+ }
+ return static_cast<Dst>(result);
+ }
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_SAFE_CONVERSIONS_ARM_IMPL_H_
diff --git a/security/sandbox/chromium/base/numerics/safe_conversions_impl.h b/security/sandbox/chromium/base/numerics/safe_conversions_impl.h
new file mode 100644
index 0000000000..7c5ca68c3b
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/safe_conversions_impl.h
@@ -0,0 +1,851 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+
+#include <stdint.h>
+
+#include <limits>
+#include <type_traits>
+
+#if defined(__GNUC__) || defined(__clang__)
+#define BASE_NUMERICS_LIKELY(x) __builtin_expect(!!(x), 1)
+#define BASE_NUMERICS_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define BASE_NUMERICS_LIKELY(x) (x)
+#define BASE_NUMERICS_UNLIKELY(x) (x)
+#endif
+
+namespace base {
+namespace internal {
+
+// The std library doesn't provide a binary max_exponent for integers, however
+// we can compute an analog using std::numeric_limits<>::digits.
+template <typename NumericType>
+struct MaxExponent {
+ static const int value = std::is_floating_point<NumericType>::value
+ ? std::numeric_limits<NumericType>::max_exponent
+ : std::numeric_limits<NumericType>::digits + 1;
+};
+
+// The number of bits (including the sign) in an integer. Eliminates sizeof
+// hacks.
+template <typename NumericType>
+struct IntegerBitsPlusSign {
+ static const int value = std::numeric_limits<NumericType>::digits +
+ std::is_signed<NumericType>::value;
+};
+
+// Helper templates for integer manipulations.
+
+template <typename Integer>
+struct PositionOfSignBit {
+ static const size_t value = IntegerBitsPlusSign<Integer>::value - 1;
+};
+
+// Determines if a numeric value is negative without throwing compiler
+// warnings on: unsigned(value) < 0.
+template <typename T,
+ typename std::enable_if<std::is_signed<T>::value>::type* = nullptr>
+constexpr bool IsValueNegative(T value) {
+ static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
+ return value < 0;
+}
+
+template <typename T,
+ typename std::enable_if<!std::is_signed<T>::value>::type* = nullptr>
+constexpr bool IsValueNegative(T) {
+ static_assert(std::is_arithmetic<T>::value, "Argument must be numeric.");
+ return false;
+}
+
+// This performs a fast negation, returning a signed value. It works on unsigned
+// arguments, but probably doesn't do what you want for any unsigned value
+// larger than max / 2 + 1 (i.e. signed min cast to unsigned).
+template <typename T>
+constexpr typename std::make_signed<T>::type ConditionalNegate(
+ T x,
+ bool is_negative) {
+ static_assert(std::is_integral<T>::value, "Type must be integral");
+ using SignedT = typename std::make_signed<T>::type;
+ using UnsignedT = typename std::make_unsigned<T>::type;
+ return static_cast<SignedT>(
+ (static_cast<UnsignedT>(x) ^ -SignedT(is_negative)) + is_negative);
+}
+
+// This performs a safe, absolute value via unsigned overflow.
+template <typename T>
+constexpr typename std::make_unsigned<T>::type SafeUnsignedAbs(T value) {
+ static_assert(std::is_integral<T>::value, "Type must be integral");
+ using UnsignedT = typename std::make_unsigned<T>::type;
+ return IsValueNegative(value)
+ ? static_cast<UnsignedT>(0u - static_cast<UnsignedT>(value))
+ : static_cast<UnsignedT>(value);
+}
+
+// This allows us to switch paths on known compile-time constants.
+#if defined(__clang__) || defined(__GNUC__)
+constexpr bool CanDetectCompileTimeConstant() {
+ return true;
+}
+template <typename T>
+constexpr bool IsCompileTimeConstant(const T v) {
+ return __builtin_constant_p(v);
+}
+#else
+constexpr bool CanDetectCompileTimeConstant() {
+ return false;
+}
+template <typename T>
+constexpr bool IsCompileTimeConstant(const T) {
+ return false;
+}
+#endif
+template <typename T>
+constexpr bool MustTreatAsConstexpr(const T v) {
+ // Either we can't detect a compile-time constant, and must always use the
+ // constexpr path, or we know we have a compile-time constant.
+ return !CanDetectCompileTimeConstant() || IsCompileTimeConstant(v);
+}
+
+// Forces a crash, like a CHECK(false). Used for numeric boundary errors.
+// Also used in a constexpr template to trigger a compilation failure on
+// an error condition.
+struct CheckOnFailure {
+ template <typename T>
+ static T HandleFailure() {
+#if defined(_MSC_VER)
+ __debugbreak();
+#elif defined(__GNUC__) || defined(__clang__)
+ __builtin_trap();
+#else
+ ((void)(*(volatile char*)0 = 0));
+#endif
+ return T();
+ }
+};
+
+enum IntegerRepresentation {
+ INTEGER_REPRESENTATION_UNSIGNED,
+ INTEGER_REPRESENTATION_SIGNED
+};
+
+// A range for a given nunmeric Src type is contained for a given numeric Dst
+// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
+// numeric_limits<Src>::lowest() >= numeric_limits<Dst>::lowest() are true.
+// We implement this as template specializations rather than simple static
+// comparisons to ensure type correctness in our comparisons.
+enum NumericRangeRepresentation {
+ NUMERIC_RANGE_NOT_CONTAINED,
+ NUMERIC_RANGE_CONTAINED
+};
+
+// Helper templates to statically determine if our destination type can contain
+// maximum and minimum values represented by the source type.
+
+template <typename Dst,
+ typename Src,
+ IntegerRepresentation DstSign = std::is_signed<Dst>::value
+ ? INTEGER_REPRESENTATION_SIGNED
+ : INTEGER_REPRESENTATION_UNSIGNED,
+ IntegerRepresentation SrcSign = std::is_signed<Src>::value
+ ? INTEGER_REPRESENTATION_SIGNED
+ : INTEGER_REPRESENTATION_UNSIGNED>
+struct StaticDstRangeRelationToSrcRange;
+
+// Same sign: Dst is guaranteed to contain Src only if its range is equal or
+// larger.
+template <typename Dst, typename Src, IntegerRepresentation Sign>
+struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
+ static const NumericRangeRepresentation value =
+ MaxExponent<Dst>::value >= MaxExponent<Src>::value
+ ? NUMERIC_RANGE_CONTAINED
+ : NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+// Unsigned to signed: Dst is guaranteed to contain source only if its range is
+// larger.
+template <typename Dst, typename Src>
+struct StaticDstRangeRelationToSrcRange<Dst,
+ Src,
+ INTEGER_REPRESENTATION_SIGNED,
+ INTEGER_REPRESENTATION_UNSIGNED> {
+ static const NumericRangeRepresentation value =
+ MaxExponent<Dst>::value > MaxExponent<Src>::value
+ ? NUMERIC_RANGE_CONTAINED
+ : NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+// Signed to unsigned: Dst cannot be statically determined to contain Src.
+template <typename Dst, typename Src>
+struct StaticDstRangeRelationToSrcRange<Dst,
+ Src,
+ INTEGER_REPRESENTATION_UNSIGNED,
+ INTEGER_REPRESENTATION_SIGNED> {
+ static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+// This class wraps the range constraints as separate booleans so the compiler
+// can identify constants and eliminate unused code paths.
+class RangeCheck {
+ public:
+ constexpr RangeCheck(bool is_in_lower_bound, bool is_in_upper_bound)
+ : is_underflow_(!is_in_lower_bound), is_overflow_(!is_in_upper_bound) {}
+ constexpr RangeCheck() : is_underflow_(0), is_overflow_(0) {}
+ constexpr bool IsValid() const { return !is_overflow_ && !is_underflow_; }
+ constexpr bool IsInvalid() const { return is_overflow_ && is_underflow_; }
+ constexpr bool IsOverflow() const { return is_overflow_ && !is_underflow_; }
+ constexpr bool IsUnderflow() const { return !is_overflow_ && is_underflow_; }
+ constexpr bool IsOverflowFlagSet() const { return is_overflow_; }
+ constexpr bool IsUnderflowFlagSet() const { return is_underflow_; }
+ constexpr bool operator==(const RangeCheck rhs) const {
+ return is_underflow_ == rhs.is_underflow_ &&
+ is_overflow_ == rhs.is_overflow_;
+ }
+ constexpr bool operator!=(const RangeCheck rhs) const {
+ return !(*this == rhs);
+ }
+
+ private:
+ // Do not change the order of these member variables. The integral conversion
+ // optimization depends on this exact order.
+ const bool is_underflow_;
+ const bool is_overflow_;
+};
+
+// The following helper template addresses a corner case in range checks for
+// conversion from a floating-point type to an integral type of smaller range
+// but larger precision (e.g. float -> unsigned). The problem is as follows:
+// 1. Integral maximum is always one less than a power of two, so it must be
+// truncated to fit the mantissa of the floating point. The direction of
+// rounding is implementation defined, but by default it's always IEEE
+// floats, which round to nearest and thus result in a value of larger
+// magnitude than the integral value.
+// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX
+// // is 4294967295u.
+// 2. If the floating point value is equal to the promoted integral maximum
+// value, a range check will erroneously pass.
+// Example: (4294967296f <= 4294967295u) // This is true due to a precision
+// // loss in rounding up to float.
+// 3. When the floating point value is then converted to an integral, the
+// resulting value is out of range for the target integral type and
+// thus is implementation defined.
+// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0.
+// To fix this bug we manually truncate the maximum value when the destination
+// type is an integral of larger precision than the source floating-point type,
+// such that the resulting maximum is represented exactly as a floating point.
+template <typename Dst, typename Src, template <typename> class Bounds>
+struct NarrowingRange {
+ using SrcLimits = std::numeric_limits<Src>;
+ using DstLimits = typename std::numeric_limits<Dst>;
+
+ // Computes the mask required to make an accurate comparison between types.
+ static const int kShift =
+ (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
+ SrcLimits::digits < DstLimits::digits)
+ ? (DstLimits::digits - SrcLimits::digits)
+ : 0;
+ template <
+ typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+
+ // Masks out the integer bits that are beyond the precision of the
+ // intermediate type used for comparison.
+ static constexpr T Adjust(T value) {
+ static_assert(std::is_same<T, Dst>::value, "");
+ static_assert(kShift < DstLimits::digits, "");
+ return static_cast<T>(
+ ConditionalNegate(SafeUnsignedAbs(value) & ~((T(1) << kShift) - T(1)),
+ IsValueNegative(value)));
+ }
+
+ template <typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* =
+ nullptr>
+ static constexpr T Adjust(T value) {
+ static_assert(std::is_same<T, Dst>::value, "");
+ static_assert(kShift == 0, "");
+ return value;
+ }
+
+ static constexpr Dst max() { return Adjust(Bounds<Dst>::max()); }
+ static constexpr Dst lowest() { return Adjust(Bounds<Dst>::lowest()); }
+};
+
+template <typename Dst,
+ typename Src,
+ template <typename> class Bounds,
+ IntegerRepresentation DstSign = std::is_signed<Dst>::value
+ ? INTEGER_REPRESENTATION_SIGNED
+ : INTEGER_REPRESENTATION_UNSIGNED,
+ IntegerRepresentation SrcSign = std::is_signed<Src>::value
+ ? INTEGER_REPRESENTATION_SIGNED
+ : INTEGER_REPRESENTATION_UNSIGNED,
+ NumericRangeRepresentation DstRange =
+ StaticDstRangeRelationToSrcRange<Dst, Src>::value>
+struct DstRangeRelationToSrcRangeImpl;
+
+// The following templates are for ranges that must be verified at runtime. We
+// split it into checks based on signedness to avoid confusing casts and
+// compiler warnings on signed an unsigned comparisons.
+
+// Same sign narrowing: The range is contained for normal limits.
+template <typename Dst,
+ typename Src,
+ template <typename> class Bounds,
+ IntegerRepresentation DstSign,
+ IntegerRepresentation SrcSign>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+ Src,
+ Bounds,
+ DstSign,
+ SrcSign,
+ NUMERIC_RANGE_CONTAINED> {
+ static constexpr RangeCheck Check(Src value) {
+ using SrcLimits = std::numeric_limits<Src>;
+ using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+ return RangeCheck(
+ static_cast<Dst>(SrcLimits::lowest()) >= DstLimits::lowest() ||
+ static_cast<Dst>(value) >= DstLimits::lowest(),
+ static_cast<Dst>(SrcLimits::max()) <= DstLimits::max() ||
+ static_cast<Dst>(value) <= DstLimits::max());
+ }
+};
+
+// Signed to signed narrowing: Both the upper and lower boundaries may be
+// exceeded for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+ Src,
+ Bounds,
+ INTEGER_REPRESENTATION_SIGNED,
+ INTEGER_REPRESENTATION_SIGNED,
+ NUMERIC_RANGE_NOT_CONTAINED> {
+ static constexpr RangeCheck Check(Src value) {
+ using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+ return RangeCheck(value >= DstLimits::lowest(), value <= DstLimits::max());
+ }
+};
+
+// Unsigned to unsigned narrowing: Only the upper bound can be exceeded for
+// standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+ Src,
+ Bounds,
+ INTEGER_REPRESENTATION_UNSIGNED,
+ INTEGER_REPRESENTATION_UNSIGNED,
+ NUMERIC_RANGE_NOT_CONTAINED> {
+ static constexpr RangeCheck Check(Src value) {
+ using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+ return RangeCheck(
+ DstLimits::lowest() == Dst(0) || value >= DstLimits::lowest(),
+ value <= DstLimits::max());
+ }
+};
+
+// Unsigned to signed: Only the upper bound can be exceeded for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+ Src,
+ Bounds,
+ INTEGER_REPRESENTATION_SIGNED,
+ INTEGER_REPRESENTATION_UNSIGNED,
+ NUMERIC_RANGE_NOT_CONTAINED> {
+ static constexpr RangeCheck Check(Src value) {
+ using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+ using Promotion = decltype(Src() + Dst());
+ return RangeCheck(DstLimits::lowest() <= Dst(0) ||
+ static_cast<Promotion>(value) >=
+ static_cast<Promotion>(DstLimits::lowest()),
+ static_cast<Promotion>(value) <=
+ static_cast<Promotion>(DstLimits::max()));
+ }
+};
+
+// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
+// and any negative value exceeds the lower boundary for standard limits.
+template <typename Dst, typename Src, template <typename> class Bounds>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+ Src,
+ Bounds,
+ INTEGER_REPRESENTATION_UNSIGNED,
+ INTEGER_REPRESENTATION_SIGNED,
+ NUMERIC_RANGE_NOT_CONTAINED> {
+ static constexpr RangeCheck Check(Src value) {
+ using SrcLimits = std::numeric_limits<Src>;
+ using DstLimits = NarrowingRange<Dst, Src, Bounds>;
+ using Promotion = decltype(Src() + Dst());
+ return RangeCheck(
+ value >= Src(0) && (DstLimits::lowest() == 0 ||
+ static_cast<Dst>(value) >= DstLimits::lowest()),
+ static_cast<Promotion>(SrcLimits::max()) <=
+ static_cast<Promotion>(DstLimits::max()) ||
+ static_cast<Promotion>(value) <=
+ static_cast<Promotion>(DstLimits::max()));
+ }
+};
+
+// Simple wrapper for statically checking if a type's range is contained.
+template <typename Dst, typename Src>
+struct IsTypeInRangeForNumericType {
+ static const bool value = StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+ NUMERIC_RANGE_CONTAINED;
+};
+
+template <typename Dst,
+ template <typename> class Bounds = std::numeric_limits,
+ typename Src>
+constexpr RangeCheck DstRangeRelationToSrcRange(Src value) {
+ static_assert(std::is_arithmetic<Src>::value, "Argument must be numeric.");
+ static_assert(std::is_arithmetic<Dst>::value, "Result must be numeric.");
+ static_assert(Bounds<Dst>::lowest() < Bounds<Dst>::max(), "");
+ return DstRangeRelationToSrcRangeImpl<Dst, Src, Bounds>::Check(value);
+}
+
+// Integer promotion templates used by the portable checked integer arithmetic.
+template <size_t Size, bool IsSigned>
+struct IntegerForDigitsAndSign;
+
+#define INTEGER_FOR_DIGITS_AND_SIGN(I) \
+ template <> \
+ struct IntegerForDigitsAndSign<IntegerBitsPlusSign<I>::value, \
+ std::is_signed<I>::value> { \
+ using type = I; \
+ }
+
+INTEGER_FOR_DIGITS_AND_SIGN(int8_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint8_t);
+INTEGER_FOR_DIGITS_AND_SIGN(int16_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint16_t);
+INTEGER_FOR_DIGITS_AND_SIGN(int32_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint32_t);
+INTEGER_FOR_DIGITS_AND_SIGN(int64_t);
+INTEGER_FOR_DIGITS_AND_SIGN(uint64_t);
+#undef INTEGER_FOR_DIGITS_AND_SIGN
+
+// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
+// support 128-bit math, then the ArithmeticPromotion template below will need
+// to be updated (or more likely replaced with a decltype expression).
+static_assert(IntegerBitsPlusSign<intmax_t>::value == 64,
+ "Max integer size not supported for this toolchain.");
+
+template <typename Integer, bool IsSigned = std::is_signed<Integer>::value>
+struct TwiceWiderInteger {
+ using type =
+ typename IntegerForDigitsAndSign<IntegerBitsPlusSign<Integer>::value * 2,
+ IsSigned>::type;
+};
+
+enum ArithmeticPromotionCategory {
+ LEFT_PROMOTION, // Use the type of the left-hand argument.
+ RIGHT_PROMOTION // Use the type of the right-hand argument.
+};
+
+// Determines the type that can represent the largest positive value.
+template <typename Lhs,
+ typename Rhs,
+ ArithmeticPromotionCategory Promotion =
+ (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
+ ? LEFT_PROMOTION
+ : RIGHT_PROMOTION>
+struct MaxExponentPromotion;
+
+template <typename Lhs, typename Rhs>
+struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
+ using type = Lhs;
+};
+
+template <typename Lhs, typename Rhs>
+struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+ using type = Rhs;
+};
+
+// Determines the type that can represent the lowest arithmetic value.
+template <typename Lhs,
+ typename Rhs,
+ ArithmeticPromotionCategory Promotion =
+ std::is_signed<Lhs>::value
+ ? (std::is_signed<Rhs>::value
+ ? (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value
+ ? LEFT_PROMOTION
+ : RIGHT_PROMOTION)
+ : LEFT_PROMOTION)
+ : (std::is_signed<Rhs>::value
+ ? RIGHT_PROMOTION
+ : (MaxExponent<Lhs>::value < MaxExponent<Rhs>::value
+ ? LEFT_PROMOTION
+ : RIGHT_PROMOTION))>
+struct LowestValuePromotion;
+
+template <typename Lhs, typename Rhs>
+struct LowestValuePromotion<Lhs, Rhs, LEFT_PROMOTION> {
+ using type = Lhs;
+};
+
+template <typename Lhs, typename Rhs>
+struct LowestValuePromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+ using type = Rhs;
+};
+
+// Determines the type that is best able to represent an arithmetic result.
+template <
+ typename Lhs,
+ typename Rhs = Lhs,
+ bool is_intmax_type =
+ std::is_integral<typename MaxExponentPromotion<Lhs, Rhs>::type>::value&&
+ IntegerBitsPlusSign<typename MaxExponentPromotion<Lhs, Rhs>::type>::
+ value == IntegerBitsPlusSign<intmax_t>::value,
+ bool is_max_exponent =
+ StaticDstRangeRelationToSrcRange<
+ typename MaxExponentPromotion<Lhs, Rhs>::type,
+ Lhs>::value ==
+ NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange<
+ typename MaxExponentPromotion<Lhs, Rhs>::type,
+ Rhs>::value == NUMERIC_RANGE_CONTAINED>
+struct BigEnoughPromotion;
+
+// The side with the max exponent is big enough.
+template <typename Lhs, typename Rhs, bool is_intmax_type>
+struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
+ using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
+ static const bool is_contained = true;
+};
+
+// We can use a twice wider type to fit.
+template <typename Lhs, typename Rhs>
+struct BigEnoughPromotion<Lhs, Rhs, false, false> {
+ using type =
+ typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
+ std::is_signed<Lhs>::value ||
+ std::is_signed<Rhs>::value>::type;
+ static const bool is_contained = true;
+};
+
+// No type is large enough.
+template <typename Lhs, typename Rhs>
+struct BigEnoughPromotion<Lhs, Rhs, true, false> {
+ using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
+ static const bool is_contained = false;
+};
+
+// We can statically check if operations on the provided types can wrap, so we
+// can skip the checked operations if they're not needed. So, for an integer we
+// care if the destination type preserves the sign and is twice the width of
+// the source.
+template <typename T, typename Lhs, typename Rhs = Lhs>
+struct IsIntegerArithmeticSafe {
+ static const bool value =
+ !std::is_floating_point<T>::value &&
+ !std::is_floating_point<Lhs>::value &&
+ !std::is_floating_point<Rhs>::value &&
+ std::is_signed<T>::value >= std::is_signed<Lhs>::value &&
+ IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Lhs>::value) &&
+ std::is_signed<T>::value >= std::is_signed<Rhs>::value &&
+ IntegerBitsPlusSign<T>::value >= (2 * IntegerBitsPlusSign<Rhs>::value);
+};
+
+// Promotes to a type that can represent any possible result of a binary
+// arithmetic operation with the source types.
+template <typename Lhs,
+ typename Rhs,
+ bool is_promotion_possible = IsIntegerArithmeticSafe<
+ typename std::conditional<std::is_signed<Lhs>::value ||
+ std::is_signed<Rhs>::value,
+ intmax_t,
+ uintmax_t>::type,
+ typename MaxExponentPromotion<Lhs, Rhs>::type>::value>
+struct FastIntegerArithmeticPromotion;
+
+template <typename Lhs, typename Rhs>
+struct FastIntegerArithmeticPromotion<Lhs, Rhs, true> {
+ using type =
+ typename TwiceWiderInteger<typename MaxExponentPromotion<Lhs, Rhs>::type,
+ std::is_signed<Lhs>::value ||
+ std::is_signed<Rhs>::value>::type;
+ static_assert(IsIntegerArithmeticSafe<type, Lhs, Rhs>::value, "");
+ static const bool is_contained = true;
+};
+
+template <typename Lhs, typename Rhs>
+struct FastIntegerArithmeticPromotion<Lhs, Rhs, false> {
+ using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
+ static const bool is_contained = false;
+};
+
+// Extracts the underlying type from an enum.
+template <typename T, bool is_enum = std::is_enum<T>::value>
+struct ArithmeticOrUnderlyingEnum;
+
+template <typename T>
+struct ArithmeticOrUnderlyingEnum<T, true> {
+ using type = typename std::underlying_type<T>::type;
+ static const bool value = std::is_arithmetic<type>::value;
+};
+
+template <typename T>
+struct ArithmeticOrUnderlyingEnum<T, false> {
+ using type = T;
+ static const bool value = std::is_arithmetic<type>::value;
+};
+
+// The following are helper templates used in the CheckedNumeric class.
+template <typename T>
+class CheckedNumeric;
+
+template <typename T>
+class ClampedNumeric;
+
+template <typename T>
+class StrictNumeric;
+
+// Used to treat CheckedNumeric and arithmetic underlying types the same.
+template <typename T>
+struct UnderlyingType {
+ using type = typename ArithmeticOrUnderlyingEnum<T>::type;
+ static const bool is_numeric = std::is_arithmetic<type>::value;
+ static const bool is_checked = false;
+ static const bool is_clamped = false;
+ static const bool is_strict = false;
+};
+
+template <typename T>
+struct UnderlyingType<CheckedNumeric<T>> {
+ using type = T;
+ static const bool is_numeric = true;
+ static const bool is_checked = true;
+ static const bool is_clamped = false;
+ static const bool is_strict = false;
+};
+
+template <typename T>
+struct UnderlyingType<ClampedNumeric<T>> {
+ using type = T;
+ static const bool is_numeric = true;
+ static const bool is_checked = false;
+ static const bool is_clamped = true;
+ static const bool is_strict = false;
+};
+
+template <typename T>
+struct UnderlyingType<StrictNumeric<T>> {
+ using type = T;
+ static const bool is_numeric = true;
+ static const bool is_checked = false;
+ static const bool is_clamped = false;
+ static const bool is_strict = true;
+};
+
+template <typename L, typename R>
+struct IsCheckedOp {
+ static const bool value =
+ UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
+ (UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
+};
+
+template <typename L, typename R>
+struct IsClampedOp {
+ static const bool value =
+ UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
+ (UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped) &&
+ !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked);
+};
+
+template <typename L, typename R>
+struct IsStrictOp {
+ static const bool value =
+ UnderlyingType<L>::is_numeric && UnderlyingType<R>::is_numeric &&
+ (UnderlyingType<L>::is_strict || UnderlyingType<R>::is_strict) &&
+ !(UnderlyingType<L>::is_checked || UnderlyingType<R>::is_checked) &&
+ !(UnderlyingType<L>::is_clamped || UnderlyingType<R>::is_clamped);
+};
+
+// as_signed<> returns the supplied integral value (or integral castable
+// Numeric template) cast as a signed integral of equivalent precision.
+// I.e. it's mostly an alias for: static_cast<std::make_signed<T>::type>(t)
+template <typename Src>
+constexpr typename std::make_signed<
+ typename base::internal::UnderlyingType<Src>::type>::type
+as_signed(const Src value) {
+ static_assert(std::is_integral<decltype(as_signed(value))>::value,
+ "Argument must be a signed or unsigned integer type.");
+ return static_cast<decltype(as_signed(value))>(value);
+}
+
+// as_unsigned<> returns the supplied integral value (or integral castable
+// Numeric template) cast as an unsigned integral of equivalent precision.
+// I.e. it's mostly an alias for: static_cast<std::make_unsigned<T>::type>(t)
+template <typename Src>
+constexpr typename std::make_unsigned<
+ typename base::internal::UnderlyingType<Src>::type>::type
+as_unsigned(const Src value) {
+ static_assert(std::is_integral<decltype(as_unsigned(value))>::value,
+ "Argument must be a signed or unsigned integer type.");
+ return static_cast<decltype(as_unsigned(value))>(value);
+}
+
+template <typename L, typename R>
+constexpr bool IsLessImpl(const L lhs,
+ const R rhs,
+ const RangeCheck l_range,
+ const RangeCheck r_range) {
+ return l_range.IsUnderflow() || r_range.IsOverflow() ||
+ (l_range == r_range &&
+ static_cast<decltype(lhs + rhs)>(lhs) <
+ static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsLess {
+ static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+ "Types must be numeric.");
+ static constexpr bool Test(const L lhs, const R rhs) {
+ return IsLessImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+ DstRangeRelationToSrcRange<L>(rhs));
+ }
+};
+
+template <typename L, typename R>
+constexpr bool IsLessOrEqualImpl(const L lhs,
+ const R rhs,
+ const RangeCheck l_range,
+ const RangeCheck r_range) {
+ return l_range.IsUnderflow() || r_range.IsOverflow() ||
+ (l_range == r_range &&
+ static_cast<decltype(lhs + rhs)>(lhs) <=
+ static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsLessOrEqual {
+ static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+ "Types must be numeric.");
+ static constexpr bool Test(const L lhs, const R rhs) {
+ return IsLessOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+ DstRangeRelationToSrcRange<L>(rhs));
+ }
+};
+
+template <typename L, typename R>
+constexpr bool IsGreaterImpl(const L lhs,
+ const R rhs,
+ const RangeCheck l_range,
+ const RangeCheck r_range) {
+ return l_range.IsOverflow() || r_range.IsUnderflow() ||
+ (l_range == r_range &&
+ static_cast<decltype(lhs + rhs)>(lhs) >
+ static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsGreater {
+ static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+ "Types must be numeric.");
+ static constexpr bool Test(const L lhs, const R rhs) {
+ return IsGreaterImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+ DstRangeRelationToSrcRange<L>(rhs));
+ }
+};
+
+template <typename L, typename R>
+constexpr bool IsGreaterOrEqualImpl(const L lhs,
+ const R rhs,
+ const RangeCheck l_range,
+ const RangeCheck r_range) {
+ return l_range.IsOverflow() || r_range.IsUnderflow() ||
+ (l_range == r_range &&
+ static_cast<decltype(lhs + rhs)>(lhs) >=
+ static_cast<decltype(lhs + rhs)>(rhs));
+}
+
+template <typename L, typename R>
+struct IsGreaterOrEqual {
+ static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+ "Types must be numeric.");
+ static constexpr bool Test(const L lhs, const R rhs) {
+ return IsGreaterOrEqualImpl(lhs, rhs, DstRangeRelationToSrcRange<R>(lhs),
+ DstRangeRelationToSrcRange<L>(rhs));
+ }
+};
+
+template <typename L, typename R>
+struct IsEqual {
+ static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+ "Types must be numeric.");
+ static constexpr bool Test(const L lhs, const R rhs) {
+ return DstRangeRelationToSrcRange<R>(lhs) ==
+ DstRangeRelationToSrcRange<L>(rhs) &&
+ static_cast<decltype(lhs + rhs)>(lhs) ==
+ static_cast<decltype(lhs + rhs)>(rhs);
+ }
+};
+
+template <typename L, typename R>
+struct IsNotEqual {
+ static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+ "Types must be numeric.");
+ static constexpr bool Test(const L lhs, const R rhs) {
+ return DstRangeRelationToSrcRange<R>(lhs) !=
+ DstRangeRelationToSrcRange<L>(rhs) ||
+ static_cast<decltype(lhs + rhs)>(lhs) !=
+ static_cast<decltype(lhs + rhs)>(rhs);
+ }
+};
+
+// These perform the actual math operations on the CheckedNumerics.
+// Binary arithmetic operations.
+template <template <typename, typename> class C, typename L, typename R>
+constexpr bool SafeCompare(const L lhs, const R rhs) {
+ static_assert(std::is_arithmetic<L>::value && std::is_arithmetic<R>::value,
+ "Types must be numeric.");
+ using Promotion = BigEnoughPromotion<L, R>;
+ using BigType = typename Promotion::type;
+ return Promotion::is_contained
+ // Force to a larger type for speed if both are contained.
+ ? C<BigType, BigType>::Test(
+ static_cast<BigType>(static_cast<L>(lhs)),
+ static_cast<BigType>(static_cast<R>(rhs)))
+ // Let the template functions figure it out for mixed types.
+ : C<L, R>::Test(lhs, rhs);
+}
+
+template <typename Dst, typename Src>
+constexpr bool IsMaxInRangeForNumericType() {
+ return IsGreaterOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::max(),
+ std::numeric_limits<Src>::max());
+}
+
+template <typename Dst, typename Src>
+constexpr bool IsMinInRangeForNumericType() {
+ return IsLessOrEqual<Dst, Src>::Test(std::numeric_limits<Dst>::lowest(),
+ std::numeric_limits<Src>::lowest());
+}
+
+template <typename Dst, typename Src>
+constexpr Dst CommonMax() {
+ return !IsMaxInRangeForNumericType<Dst, Src>()
+ ? Dst(std::numeric_limits<Dst>::max())
+ : Dst(std::numeric_limits<Src>::max());
+}
+
+template <typename Dst, typename Src>
+constexpr Dst CommonMin() {
+ return !IsMinInRangeForNumericType<Dst, Src>()
+ ? Dst(std::numeric_limits<Dst>::lowest())
+ : Dst(std::numeric_limits<Src>::lowest());
+}
+
+// This is a wrapper to generate return the max or min for a supplied type.
+// If the argument is false, the returned value is the maximum. If true the
+// returned value is the minimum.
+template <typename Dst, typename Src = Dst>
+constexpr Dst CommonMaxOrMin(bool is_min) {
+ return is_min ? CommonMin<Dst, Src>() : CommonMax<Dst, Src>();
+}
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/security/sandbox/chromium/base/numerics/safe_math.h b/security/sandbox/chromium/base/numerics/safe_math.h
new file mode 100644
index 0000000000..e30be901f9
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/safe_math.h
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_H_
+#define BASE_NUMERICS_SAFE_MATH_H_
+
+#include "base/numerics/checked_math.h"
+#include "base/numerics/clamped_math.h"
+#include "base/numerics/safe_conversions.h"
+
+#endif // BASE_NUMERICS_SAFE_MATH_H_
diff --git a/security/sandbox/chromium/base/numerics/safe_math_arm_impl.h b/security/sandbox/chromium/base/numerics/safe_math_arm_impl.h
new file mode 100644
index 0000000000..ff86bd0b73
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/safe_math_arm_impl.h
@@ -0,0 +1,122 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions.h"
+
+namespace base {
+namespace internal {
+
+template <typename T, typename U>
+struct CheckedMulFastAsmOp {
+ static const bool is_supported =
+ FastIntegerArithmeticPromotion<T, U>::is_contained;
+
+ // The following is much more efficient than the Clang and GCC builtins for
+ // performing overflow-checked multiplication when a twice wider type is
+ // available. The below compiles down to 2-3 instructions, depending on the
+ // width of the types in use.
+ // As an example, an int32_t multiply compiles to:
+ // smull r0, r1, r0, r1
+ // cmp r1, r1, asr #31
+ // And an int16_t multiply compiles to:
+ // smulbb r1, r1, r0
+ // asr r2, r1, #16
+ // cmp r2, r1, asr #15
+ template <typename V>
+ __attribute__((always_inline)) static bool Do(T x, U y, V* result) {
+ using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+ Promotion presult;
+
+ presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
+ *result = static_cast<V>(presult);
+ return IsValueInRangeForNumericType<V>(presult);
+ }
+};
+
+template <typename T, typename U>
+struct ClampedAddFastAsmOp {
+ static const bool is_supported =
+ BigEnoughPromotion<T, U>::is_contained &&
+ IsTypeInRangeForNumericType<
+ int32_t,
+ typename BigEnoughPromotion<T, U>::type>::value;
+
+ template <typename V>
+ __attribute__((always_inline)) static V Do(T x, U y) {
+ // This will get promoted to an int, so let the compiler do whatever is
+ // clever and rely on the saturated cast to bounds check.
+ if (IsIntegerArithmeticSafe<int, T, U>::value)
+ return saturated_cast<V>(x + y);
+
+ int32_t result;
+ int32_t x_i32 = checked_cast<int32_t>(x);
+ int32_t y_i32 = checked_cast<int32_t>(y);
+
+ asm("qadd %[result], %[first], %[second]"
+ : [result] "=r"(result)
+ : [first] "r"(x_i32), [second] "r"(y_i32));
+ return saturated_cast<V>(result);
+ }
+};
+
+template <typename T, typename U>
+struct ClampedSubFastAsmOp {
+ static const bool is_supported =
+ BigEnoughPromotion<T, U>::is_contained &&
+ IsTypeInRangeForNumericType<
+ int32_t,
+ typename BigEnoughPromotion<T, U>::type>::value;
+
+ template <typename V>
+ __attribute__((always_inline)) static V Do(T x, U y) {
+ // This will get promoted to an int, so let the compiler do whatever is
+ // clever and rely on the saturated cast to bounds check.
+ if (IsIntegerArithmeticSafe<int, T, U>::value)
+ return saturated_cast<V>(x - y);
+
+ int32_t result;
+ int32_t x_i32 = checked_cast<int32_t>(x);
+ int32_t y_i32 = checked_cast<int32_t>(y);
+
+ asm("qsub %[result], %[first], %[second]"
+ : [result] "=r"(result)
+ : [first] "r"(x_i32), [second] "r"(y_i32));
+ return saturated_cast<V>(result);
+ }
+};
+
+template <typename T, typename U>
+struct ClampedMulFastAsmOp {
+ static const bool is_supported = CheckedMulFastAsmOp<T, U>::is_supported;
+
+ template <typename V>
+ __attribute__((always_inline)) static V Do(T x, U y) {
+ // Use the CheckedMulFastAsmOp for full-width 32-bit values, because
+ // it's fewer instructions than promoting and then saturating.
+ if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
+ !IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
+ V result;
+ if (CheckedMulFastAsmOp<T, U>::Do(x, y, &result))
+ return result;
+ return CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
+ }
+
+ assert((FastIntegerArithmeticPromotion<T, U>::is_contained));
+ using Promotion = typename FastIntegerArithmeticPromotion<T, U>::type;
+ return saturated_cast<V>(static_cast<Promotion>(x) *
+ static_cast<Promotion>(y));
+ }
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_SAFE_MATH_ARM_IMPL_H_
diff --git a/security/sandbox/chromium/base/numerics/safe_math_clang_gcc_impl.h b/security/sandbox/chromium/base/numerics/safe_math_clang_gcc_impl.h
new file mode 100644
index 0000000000..1760338b08
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/safe_math_clang_gcc_impl.h
@@ -0,0 +1,157 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
+
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions.h"
+
+#if !defined(__native_client__) && (defined(__ARMEL__) || defined(__arch64__))
+#include "base/numerics/safe_math_arm_impl.h"
+#define BASE_HAS_ASSEMBLER_SAFE_MATH (1)
+#else
+#define BASE_HAS_ASSEMBLER_SAFE_MATH (0)
+#endif
+
+namespace base {
+namespace internal {
+
+// These are the non-functioning boilerplate implementations of the optimized
+// safe math routines.
+#if !BASE_HAS_ASSEMBLER_SAFE_MATH
+template <typename T, typename U>
+struct CheckedMulFastAsmOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr bool Do(T, U, V*) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<bool>();
+ }
+};
+
+template <typename T, typename U>
+struct ClampedAddFastAsmOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr V Do(T, U) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<V>();
+ }
+};
+
+template <typename T, typename U>
+struct ClampedSubFastAsmOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr V Do(T, U) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<V>();
+ }
+};
+
+template <typename T, typename U>
+struct ClampedMulFastAsmOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr V Do(T, U) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<V>();
+ }
+};
+#endif // BASE_HAS_ASSEMBLER_SAFE_MATH
+#undef BASE_HAS_ASSEMBLER_SAFE_MATH
+
+template <typename T, typename U>
+struct CheckedAddFastOp {
+ static const bool is_supported = true;
+ template <typename V>
+ __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
+ return !__builtin_add_overflow(x, y, result);
+ }
+};
+
+template <typename T, typename U>
+struct CheckedSubFastOp {
+ static const bool is_supported = true;
+ template <typename V>
+ __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
+ return !__builtin_sub_overflow(x, y, result);
+ }
+};
+
+template <typename T, typename U>
+struct CheckedMulFastOp {
+#if defined(__clang__)
+ // TODO(jschuh): Get the Clang runtime library issues sorted out so we can
+ // support full-width, mixed-sign multiply builtins.
+ // https://crbug.com/613003
+ // We can support intptr_t, uintptr_t, or a smaller common type.
+ static const bool is_supported =
+ (IsTypeInRangeForNumericType<intptr_t, T>::value &&
+ IsTypeInRangeForNumericType<intptr_t, U>::value) ||
+ (IsTypeInRangeForNumericType<uintptr_t, T>::value &&
+ IsTypeInRangeForNumericType<uintptr_t, U>::value);
+#else
+ static const bool is_supported = true;
+#endif
+ template <typename V>
+ __attribute__((always_inline)) static constexpr bool Do(T x, U y, V* result) {
+ return CheckedMulFastAsmOp<T, U>::is_supported
+ ? CheckedMulFastAsmOp<T, U>::Do(x, y, result)
+ : !__builtin_mul_overflow(x, y, result);
+ }
+};
+
+template <typename T, typename U>
+struct ClampedAddFastOp {
+ static const bool is_supported = ClampedAddFastAsmOp<T, U>::is_supported;
+ template <typename V>
+ __attribute__((always_inline)) static V Do(T x, U y) {
+ return ClampedAddFastAsmOp<T, U>::template Do<V>(x, y);
+ }
+};
+
+template <typename T, typename U>
+struct ClampedSubFastOp {
+ static const bool is_supported = ClampedSubFastAsmOp<T, U>::is_supported;
+ template <typename V>
+ __attribute__((always_inline)) static V Do(T x, U y) {
+ return ClampedSubFastAsmOp<T, U>::template Do<V>(x, y);
+ }
+};
+
+template <typename T, typename U>
+struct ClampedMulFastOp {
+ static const bool is_supported = ClampedMulFastAsmOp<T, U>::is_supported;
+ template <typename V>
+ __attribute__((always_inline)) static V Do(T x, U y) {
+ return ClampedMulFastAsmOp<T, U>::template Do<V>(x, y);
+ }
+};
+
+template <typename T>
+struct ClampedNegFastOp {
+ static const bool is_supported = std::is_signed<T>::value;
+ __attribute__((always_inline)) static T Do(T value) {
+ // Use this when there is no assembler path available.
+ if (!ClampedSubFastAsmOp<T, T>::is_supported) {
+ T result;
+ return !__builtin_sub_overflow(T(0), value, &result)
+ ? result
+ : std::numeric_limits<T>::max();
+ }
+
+ // Fallback to the normal subtraction path.
+ return ClampedSubFastOp<T, T>::template Do<T>(T(0), value);
+ }
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_SAFE_MATH_CLANG_GCC_IMPL_H_
diff --git a/security/sandbox/chromium/base/numerics/safe_math_shared_impl.h b/security/sandbox/chromium/base/numerics/safe_math_shared_impl.h
new file mode 100644
index 0000000000..3556b1ea81
--- /dev/null
+++ b/security/sandbox/chromium/base/numerics/safe_math_shared_impl.h
@@ -0,0 +1,240 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cassert>
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+#include <type_traits>
+
+#include "base/numerics/safe_conversions.h"
+
+#ifdef __asmjs__
+// Optimized safe math instructions are incompatible with asmjs.
+#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
+// Where available use builtin math overflow support on Clang and GCC.
+#elif !defined(__native_client__) && \
+ ((defined(__clang__) && \
+ ((__clang_major__ > 3) || \
+ (__clang_major__ == 3 && __clang_minor__ >= 4))) || \
+ (defined(__GNUC__) && __GNUC__ >= 5))
+#include "base/numerics/safe_math_clang_gcc_impl.h"
+#define BASE_HAS_OPTIMIZED_SAFE_MATH (1)
+#else
+#define BASE_HAS_OPTIMIZED_SAFE_MATH (0)
+#endif
+
+namespace base {
+namespace internal {
+
+// These are the non-functioning boilerplate implementations of the optimized
+// safe math routines.
+#if !BASE_HAS_OPTIMIZED_SAFE_MATH
+template <typename T, typename U>
+struct CheckedAddFastOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr bool Do(T, U, V*) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<bool>();
+ }
+};
+
+template <typename T, typename U>
+struct CheckedSubFastOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr bool Do(T, U, V*) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<bool>();
+ }
+};
+
+template <typename T, typename U>
+struct CheckedMulFastOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr bool Do(T, U, V*) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<bool>();
+ }
+};
+
+template <typename T, typename U>
+struct ClampedAddFastOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr V Do(T, U) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<V>();
+ }
+};
+
+template <typename T, typename U>
+struct ClampedSubFastOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr V Do(T, U) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<V>();
+ }
+};
+
+template <typename T, typename U>
+struct ClampedMulFastOp {
+ static const bool is_supported = false;
+ template <typename V>
+ static constexpr V Do(T, U) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<V>();
+ }
+};
+
+template <typename T>
+struct ClampedNegFastOp {
+ static const bool is_supported = false;
+ static constexpr T Do(T) {
+ // Force a compile failure if instantiated.
+ return CheckOnFailure::template HandleFailure<T>();
+ }
+};
+#endif // BASE_HAS_OPTIMIZED_SAFE_MATH
+#undef BASE_HAS_OPTIMIZED_SAFE_MATH
+
+// This is used for UnsignedAbs, where we need to support floating-point
+// template instantiations even though we don't actually support the operations.
+// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
+// so the float versions will not compile.
+template <typename Numeric,
+ bool IsInteger = std::is_integral<Numeric>::value,
+ bool IsFloat = std::is_floating_point<Numeric>::value>
+struct UnsignedOrFloatForSize;
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, true, false> {
+ using type = typename std::make_unsigned<Numeric>::type;
+};
+
+template <typename Numeric>
+struct UnsignedOrFloatForSize<Numeric, false, true> {
+ using type = Numeric;
+};
+
+// Wrap the unary operations to allow SFINAE when instantiating integrals versus
+// floating points. These don't perform any overflow checking. Rather, they
+// exhibit well-defined overflow semantics and rely on the caller to detect
+// if an overflow occured.
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr T NegateWrapper(T value) {
+ using UnsignedT = typename std::make_unsigned<T>::type;
+ // This will compile to a NEG on Intel, and is normal negation on ARM.
+ return static_cast<T>(UnsignedT(0) - static_cast<UnsignedT>(value));
+}
+
+template <
+ typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T NegateWrapper(T value) {
+ return -value;
+}
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr typename std::make_unsigned<T>::type InvertWrapper(T value) {
+ return ~value;
+}
+
+template <typename T,
+ typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
+constexpr T AbsWrapper(T value) {
+ return static_cast<T>(SafeUnsignedAbs(value));
+}
+
+template <
+ typename T,
+ typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
+constexpr T AbsWrapper(T value) {
+ return value < 0 ? -value : value;
+}
+
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+struct MathWrapper {
+ using math = M<typename UnderlyingType<L>::type,
+ typename UnderlyingType<R>::type,
+ void>;
+ using type = typename math::result_type;
+};
+
+// These variadic templates work out the return types.
+// TODO(jschuh): Rip all this out once we have C++14 non-trailing auto support.
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R,
+ typename... Args>
+struct ResultType;
+
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R>
+struct ResultType<M, L, R> {
+ using type = typename MathWrapper<M, L, R>::type;
+};
+
+template <template <typename, typename, typename> class M,
+ typename L,
+ typename R,
+ typename... Args>
+struct ResultType {
+ using type =
+ typename ResultType<M, typename ResultType<M, L, R>::type, Args...>::type;
+};
+
+// The following macros are just boilerplate for the standard arithmetic
+// operator overloads and variadic function templates. A macro isn't the nicest
+// solution, but it beats rewriting these over and over again.
+#define BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME) \
+ template <typename L, typename R, typename... Args> \
+ constexpr CLASS##Numeric< \
+ typename ResultType<CLASS##OP_NAME##Op, L, R, Args...>::type> \
+ CL_ABBR##OP_NAME(const L lhs, const R rhs, const Args... args) { \
+ return CL_ABBR##MathOp<CLASS##OP_NAME##Op, L, R, Args...>(lhs, rhs, \
+ args...); \
+ }
+
+#define BASE_NUMERIC_ARITHMETIC_OPERATORS(CLASS, CL_ABBR, OP_NAME, OP, CMP_OP) \
+ /* Binary arithmetic operator for all CLASS##Numeric operations. */ \
+ template <typename L, typename R, \
+ typename std::enable_if<Is##CLASS##Op<L, R>::value>::type* = \
+ nullptr> \
+ constexpr CLASS##Numeric< \
+ typename MathWrapper<CLASS##OP_NAME##Op, L, R>::type> \
+ operator OP(const L lhs, const R rhs) { \
+ return decltype(lhs OP rhs)::template MathOp<CLASS##OP_NAME##Op>(lhs, \
+ rhs); \
+ } \
+ /* Assignment arithmetic operator implementation from CLASS##Numeric. */ \
+ template <typename L> \
+ template <typename R> \
+ constexpr CLASS##Numeric<L>& CLASS##Numeric<L>::operator CMP_OP( \
+ const R rhs) { \
+ return MathOp<CLASS##OP_NAME##Op>(rhs); \
+ } \
+ /* Variadic arithmetic functions that return CLASS##Numeric. */ \
+ BASE_NUMERIC_ARITHMETIC_VARIADIC(CLASS, CL_ABBR, OP_NAME)
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_NUMERICS_SAFE_MATH_SHARED_IMPL_H_
diff --git a/security/sandbox/chromium/base/optional.h b/security/sandbox/chromium/base/optional.h
new file mode 100644
index 0000000000..36ae36fc98
--- /dev/null
+++ b/security/sandbox/chromium/base/optional.h
@@ -0,0 +1,937 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OPTIONAL_H_
+#define BASE_OPTIONAL_H_
+
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/template_util.h"
+
+namespace base {
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
+struct nullopt_t {
+ constexpr explicit nullopt_t(int) {}
+};
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/optional/nullopt
+constexpr nullopt_t nullopt(0);
+
+// Forward declaration, which is refered by following helpers.
+template <typename T>
+class Optional;
+
+namespace internal {
+
+template <typename T, bool = std::is_trivially_destructible<T>::value>
+struct OptionalStorageBase {
+ // Initializing |empty_| here instead of using default member initializing
+ // to avoid errors in g++ 4.8.
+ constexpr OptionalStorageBase() : empty_('\0') {}
+
+ template <class... Args>
+ constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
+ : is_populated_(true), value_(std::forward<Args>(args)...) {}
+
+ // When T is not trivially destructible we must call its
+ // destructor before deallocating its memory.
+ // Note that this hides the (implicitly declared) move constructor, which
+ // would be used for constexpr move constructor in OptionalStorage<T>.
+ // It is needed iff T is trivially move constructible. However, the current
+ // is_trivially_{copy,move}_constructible implementation requires
+ // is_trivially_destructible (which looks a bug, cf:
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51452 and
+ // http://cplusplus.github.io/LWG/lwg-active.html#2116), so it is not
+ // necessary for this case at the moment. Please see also the destructor
+ // comment in "is_trivially_destructible = true" specialization below.
+ ~OptionalStorageBase() {
+ if (is_populated_)
+ value_.~T();
+ }
+
+ template <class... Args>
+ void Init(Args&&... args) {
+ DCHECK(!is_populated_);
+ ::new (&value_) T(std::forward<Args>(args)...);
+ is_populated_ = true;
+ }
+
+ bool is_populated_ = false;
+ union {
+ // |empty_| exists so that the union will always be initialized, even when
+ // it doesn't contain a value. Union members must be initialized for the
+ // constructor to be 'constexpr'.
+ char empty_;
+ T value_;
+ };
+};
+
+template <typename T>
+struct OptionalStorageBase<T, true /* trivially destructible */> {
+ // Initializing |empty_| here instead of using default member initializing
+ // to avoid errors in g++ 4.8.
+ constexpr OptionalStorageBase() : empty_('\0') {}
+
+ template <class... Args>
+ constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
+ : is_populated_(true), value_(std::forward<Args>(args)...) {}
+
+ // When T is trivially destructible (i.e. its destructor does nothing) there
+ // is no need to call it. Implicitly defined destructor is trivial, because
+ // both members (bool and union containing only variants which are trivially
+ // destructible) are trivially destructible.
+ // Explicitly-defaulted destructor is also trivial, but do not use it here,
+ // because it hides the implicit move constructor. It is needed to implement
+ // constexpr move constructor in OptionalStorage iff T is trivially move
+ // constructible. Note that, if T is trivially move constructible, the move
+ // constructor of OptionalStorageBase<T> is also implicitly defined and it is
+ // trivially move constructor. If T is not trivially move constructible,
+ // "not declaring move constructor without destructor declaration" here means
+ // "delete move constructor", which works because any move constructor of
+ // OptionalStorage will not refer to it in that case.
+
+ template <class... Args>
+ void Init(Args&&... args) {
+ DCHECK(!is_populated_);
+ ::new (&value_) T(std::forward<Args>(args)...);
+ is_populated_ = true;
+ }
+
+ bool is_populated_ = false;
+ union {
+ // |empty_| exists so that the union will always be initialized, even when
+ // it doesn't contain a value. Union members must be initialized for the
+ // constructor to be 'constexpr'.
+ char empty_;
+ T value_;
+ };
+};
+
+// Implement conditional constexpr copy and move constructors. These are
+// constexpr if is_trivially_{copy,move}_constructible<T>::value is true
+// respectively. If each is true, the corresponding constructor is defined as
+// "= default;", which generates a constexpr constructor (In this case,
+// the condition of constexpr-ness is satisfied because the base class also has
+// compiler generated constexpr {copy,move} constructors). Note that
+// placement-new is prohibited in constexpr.
+template <typename T,
+ bool = is_trivially_copy_constructible<T>::value,
+ bool = std::is_trivially_move_constructible<T>::value>
+struct OptionalStorage : OptionalStorageBase<T> {
+ // This is no trivially {copy,move} constructible case. Other cases are
+ // defined below as specializations.
+
+ // Accessing the members of template base class requires explicit
+ // declaration.
+ using OptionalStorageBase<T>::is_populated_;
+ using OptionalStorageBase<T>::value_;
+ using OptionalStorageBase<T>::Init;
+
+ // Inherit constructors (specifically, the in_place constructor).
+ using OptionalStorageBase<T>::OptionalStorageBase;
+
+ // User defined constructor deletes the default constructor.
+ // Define it explicitly.
+ OptionalStorage() = default;
+
+ OptionalStorage(const OptionalStorage& other) {
+ if (other.is_populated_)
+ Init(other.value_);
+ }
+
+ OptionalStorage(OptionalStorage&& other) noexcept(
+ std::is_nothrow_move_constructible<T>::value) {
+ if (other.is_populated_)
+ Init(std::move(other.value_));
+ }
+};
+
+template <typename T>
+struct OptionalStorage<T,
+ true /* trivially copy constructible */,
+ false /* trivially move constructible */>
+ : OptionalStorageBase<T> {
+ using OptionalStorageBase<T>::is_populated_;
+ using OptionalStorageBase<T>::value_;
+ using OptionalStorageBase<T>::Init;
+ using OptionalStorageBase<T>::OptionalStorageBase;
+
+ OptionalStorage() = default;
+ OptionalStorage(const OptionalStorage& other) = default;
+
+ OptionalStorage(OptionalStorage&& other) noexcept(
+ std::is_nothrow_move_constructible<T>::value) {
+ if (other.is_populated_)
+ Init(std::move(other.value_));
+ }
+};
+
+template <typename T>
+struct OptionalStorage<T,
+ false /* trivially copy constructible */,
+ true /* trivially move constructible */>
+ : OptionalStorageBase<T> {
+ using OptionalStorageBase<T>::is_populated_;
+ using OptionalStorageBase<T>::value_;
+ using OptionalStorageBase<T>::Init;
+ using OptionalStorageBase<T>::OptionalStorageBase;
+
+ OptionalStorage() = default;
+ OptionalStorage(OptionalStorage&& other) = default;
+
+ OptionalStorage(const OptionalStorage& other) {
+ if (other.is_populated_)
+ Init(other.value_);
+ }
+};
+
+template <typename T>
+struct OptionalStorage<T,
+ true /* trivially copy constructible */,
+ true /* trivially move constructible */>
+ : OptionalStorageBase<T> {
+ // If both trivially {copy,move} constructible are true, it is not necessary
+ // to use user-defined constructors. So, just inheriting constructors
+ // from the base class works.
+ using OptionalStorageBase<T>::OptionalStorageBase;
+};
+
+// Base class to support conditionally usable copy-/move- constructors
+// and assign operators.
+template <typename T>
+class OptionalBase {
+ // This class provides implementation rather than public API, so everything
+ // should be hidden. Often we use composition, but we cannot in this case
+ // because of C++ language restriction.
+ protected:
+ constexpr OptionalBase() = default;
+ constexpr OptionalBase(const OptionalBase& other) = default;
+ constexpr OptionalBase(OptionalBase&& other) = default;
+
+ template <class... Args>
+ constexpr explicit OptionalBase(in_place_t, Args&&... args)
+ : storage_(in_place, std::forward<Args>(args)...) {}
+
+ // Implementation of converting constructors.
+ template <typename U>
+ explicit OptionalBase(const OptionalBase<U>& other) {
+ if (other.storage_.is_populated_)
+ storage_.Init(other.storage_.value_);
+ }
+
+ template <typename U>
+ explicit OptionalBase(OptionalBase<U>&& other) {
+ if (other.storage_.is_populated_)
+ storage_.Init(std::move(other.storage_.value_));
+ }
+
+ ~OptionalBase() = default;
+
+ OptionalBase& operator=(const OptionalBase& other) {
+ CopyAssign(other);
+ return *this;
+ }
+
+ OptionalBase& operator=(OptionalBase&& other) noexcept(
+ std::is_nothrow_move_assignable<T>::value&&
+ std::is_nothrow_move_constructible<T>::value) {
+ MoveAssign(std::move(other));
+ return *this;
+ }
+
+ template <typename U>
+ void CopyAssign(const OptionalBase<U>& other) {
+ if (other.storage_.is_populated_)
+ InitOrAssign(other.storage_.value_);
+ else
+ FreeIfNeeded();
+ }
+
+ template <typename U>
+ void MoveAssign(OptionalBase<U>&& other) {
+ if (other.storage_.is_populated_)
+ InitOrAssign(std::move(other.storage_.value_));
+ else
+ FreeIfNeeded();
+ }
+
+ template <typename U>
+ void InitOrAssign(U&& value) {
+ if (storage_.is_populated_)
+ storage_.value_ = std::forward<U>(value);
+ else
+ storage_.Init(std::forward<U>(value));
+ }
+
+ void FreeIfNeeded() {
+ if (!storage_.is_populated_)
+ return;
+ storage_.value_.~T();
+ storage_.is_populated_ = false;
+ }
+
+ // For implementing conversion, allow access to other typed OptionalBase
+ // class.
+ template <typename U>
+ friend class OptionalBase;
+
+ OptionalStorage<T> storage_;
+};
+
+// The following {Copy,Move}{Constructible,Assignable} structs are helpers to
+// implement constructor/assign-operator overloading. Specifically, if T is
+// is not movable but copyable, Optional<T>'s move constructor should not
+// participate in overload resolution. This inheritance trick implements that.
+template <bool is_copy_constructible>
+struct CopyConstructible {};
+
+template <>
+struct CopyConstructible<false> {
+ constexpr CopyConstructible() = default;
+ constexpr CopyConstructible(const CopyConstructible&) = delete;
+ constexpr CopyConstructible(CopyConstructible&&) = default;
+ CopyConstructible& operator=(const CopyConstructible&) = default;
+ CopyConstructible& operator=(CopyConstructible&&) = default;
+};
+
+template <bool is_move_constructible>
+struct MoveConstructible {};
+
+template <>
+struct MoveConstructible<false> {
+ constexpr MoveConstructible() = default;
+ constexpr MoveConstructible(const MoveConstructible&) = default;
+ constexpr MoveConstructible(MoveConstructible&&) = delete;
+ MoveConstructible& operator=(const MoveConstructible&) = default;
+ MoveConstructible& operator=(MoveConstructible&&) = default;
+};
+
+template <bool is_copy_assignable>
+struct CopyAssignable {};
+
+template <>
+struct CopyAssignable<false> {
+ constexpr CopyAssignable() = default;
+ constexpr CopyAssignable(const CopyAssignable&) = default;
+ constexpr CopyAssignable(CopyAssignable&&) = default;
+ CopyAssignable& operator=(const CopyAssignable&) = delete;
+ CopyAssignable& operator=(CopyAssignable&&) = default;
+};
+
+template <bool is_move_assignable>
+struct MoveAssignable {};
+
+template <>
+struct MoveAssignable<false> {
+ constexpr MoveAssignable() = default;
+ constexpr MoveAssignable(const MoveAssignable&) = default;
+ constexpr MoveAssignable(MoveAssignable&&) = default;
+ MoveAssignable& operator=(const MoveAssignable&) = default;
+ MoveAssignable& operator=(MoveAssignable&&) = delete;
+};
+
+// Helper to conditionally enable converting constructors and assign operators.
+template <typename T, typename U>
+struct IsConvertibleFromOptional
+ : std::integral_constant<
+ bool,
+ std::is_constructible<T, Optional<U>&>::value ||
+ std::is_constructible<T, const Optional<U>&>::value ||
+ std::is_constructible<T, Optional<U>&&>::value ||
+ std::is_constructible<T, const Optional<U>&&>::value ||
+ std::is_convertible<Optional<U>&, T>::value ||
+ std::is_convertible<const Optional<U>&, T>::value ||
+ std::is_convertible<Optional<U>&&, T>::value ||
+ std::is_convertible<const Optional<U>&&, T>::value> {};
+
+template <typename T, typename U>
+struct IsAssignableFromOptional
+ : std::integral_constant<
+ bool,
+ IsConvertibleFromOptional<T, U>::value ||
+ std::is_assignable<T&, Optional<U>&>::value ||
+ std::is_assignable<T&, const Optional<U>&>::value ||
+ std::is_assignable<T&, Optional<U>&&>::value ||
+ std::is_assignable<T&, const Optional<U>&&>::value> {};
+
+// Forward compatibility for C++17.
+// Introduce one more deeper nested namespace to avoid leaking using std::swap.
+namespace swappable_impl {
+using std::swap;
+
+struct IsSwappableImpl {
+ // Tests if swap can be called. Check<T&>(0) returns true_type iff swap
+ // is available for T. Otherwise, Check's overload resolution falls back
+ // to Check(...) declared below thanks to SFINAE, so returns false_type.
+ template <typename T>
+ static auto Check(int)
+ -> decltype(swap(std::declval<T>(), std::declval<T>()), std::true_type());
+
+ template <typename T>
+ static std::false_type Check(...);
+};
+} // namespace swappable_impl
+
+template <typename T>
+struct IsSwappable : decltype(swappable_impl::IsSwappableImpl::Check<T&>(0)) {};
+
+// Forward compatibility for C++20.
+template <typename T>
+using RemoveCvRefT = std::remove_cv_t<std::remove_reference_t<T>>;
+
+} // namespace internal
+
+// On Windows, by default, empty-base class optimization does not work,
+// which means even if the base class is empty struct, it still consumes one
+// byte for its body. __declspec(empty_bases) enables the optimization.
+// cf)
+// https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/
+#ifdef OS_WIN
+#define OPTIONAL_DECLSPEC_EMPTY_BASES __declspec(empty_bases)
+#else
+#define OPTIONAL_DECLSPEC_EMPTY_BASES
+#endif
+
+// base::Optional is a Chromium version of the C++17 optional class:
+// std::optional documentation:
+// http://en.cppreference.com/w/cpp/utility/optional
+// Chromium documentation:
+// https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md
+//
+// These are the differences between the specification and the implementation:
+// - Constructors do not use 'constexpr' as it is a C++14 extension.
+// - 'constexpr' might be missing in some places for reasons specified locally.
+// - No exceptions are thrown, because they are banned from Chromium.
+// Marked noexcept for only move constructor and move assign operators.
+// - All the non-members are in the 'base' namespace instead of 'std'.
+//
+// Note that T cannot have a constructor T(Optional<T>) etc. Optional<T> checks
+// T's constructor (specifically via IsConvertibleFromOptional), and in the
+// check whether T can be constructible from Optional<T>, which is recursive
+// so it does not work. As of Feb 2018, std::optional C++17 implementation in
+// both clang and gcc has same limitation. MSVC SFINAE looks to have different
+// behavior, but anyway it reports an error, too.
+template <typename T>
+class OPTIONAL_DECLSPEC_EMPTY_BASES Optional
+ : public internal::OptionalBase<T>,
+ public internal::CopyConstructible<std::is_copy_constructible<T>::value>,
+ public internal::MoveConstructible<std::is_move_constructible<T>::value>,
+ public internal::CopyAssignable<std::is_copy_constructible<T>::value &&
+ std::is_copy_assignable<T>::value>,
+ public internal::MoveAssignable<std::is_move_constructible<T>::value &&
+ std::is_move_assignable<T>::value> {
+ private:
+ // Disable some versions of T that are ill-formed.
+ // See: https://timsong-cpp.github.io/cppwp/n4659/optional#syn-1
+ static_assert(
+ !std::is_same<internal::RemoveCvRefT<T>, in_place_t>::value,
+ "instantiation of base::Optional with in_place_t is ill-formed");
+ static_assert(!std::is_same<internal::RemoveCvRefT<T>, nullopt_t>::value,
+ "instantiation of base::Optional with nullopt_t is ill-formed");
+ static_assert(
+ !std::is_reference<T>::value,
+ "instantiation of base::Optional with a reference type is ill-formed");
+ // See: https://timsong-cpp.github.io/cppwp/n4659/optional#optional-3
+ static_assert(std::is_destructible<T>::value,
+ "instantiation of base::Optional with a non-destructible type "
+ "is ill-formed");
+ // Arrays are explicitly disallowed because for arrays of known bound
+ // is_destructible is of undefined value.
+ // See: https://en.cppreference.com/w/cpp/types/is_destructible
+ static_assert(
+ !std::is_array<T>::value,
+ "instantiation of base::Optional with an array type is ill-formed");
+
+ public:
+#undef OPTIONAL_DECLSPEC_EMPTY_BASES
+ using value_type = T;
+
+ // Defer default/copy/move constructor implementation to OptionalBase.
+ constexpr Optional() = default;
+ constexpr Optional(const Optional& other) = default;
+ constexpr Optional(Optional&& other) noexcept(
+ std::is_nothrow_move_constructible<T>::value) = default;
+
+ constexpr Optional(nullopt_t) {} // NOLINT(runtime/explicit)
+
+ // Converting copy constructor. "explicit" only if
+ // std::is_convertible<const U&, T>::value is false. It is implemented by
+ // declaring two almost same constructors, but that condition in enable_if_t
+ // is different, so that either one is chosen, thanks to SFINAE.
+ template <
+ typename U,
+ std::enable_if_t<std::is_constructible<T, const U&>::value &&
+ !internal::IsConvertibleFromOptional<T, U>::value &&
+ std::is_convertible<const U&, T>::value,
+ bool> = false>
+ Optional(const Optional<U>& other) : internal::OptionalBase<T>(other) {}
+
+ template <
+ typename U,
+ std::enable_if_t<std::is_constructible<T, const U&>::value &&
+ !internal::IsConvertibleFromOptional<T, U>::value &&
+ !std::is_convertible<const U&, T>::value,
+ bool> = false>
+ explicit Optional(const Optional<U>& other)
+ : internal::OptionalBase<T>(other) {}
+
+ // Converting move constructor. Similar to converting copy constructor,
+ // declaring two (explicit and non-explicit) constructors.
+ template <
+ typename U,
+ std::enable_if_t<std::is_constructible<T, U&&>::value &&
+ !internal::IsConvertibleFromOptional<T, U>::value &&
+ std::is_convertible<U&&, T>::value,
+ bool> = false>
+ Optional(Optional<U>&& other) : internal::OptionalBase<T>(std::move(other)) {}
+
+ template <
+ typename U,
+ std::enable_if_t<std::is_constructible<T, U&&>::value &&
+ !internal::IsConvertibleFromOptional<T, U>::value &&
+ !std::is_convertible<U&&, T>::value,
+ bool> = false>
+ explicit Optional(Optional<U>&& other)
+ : internal::OptionalBase<T>(std::move(other)) {}
+
+ template <class... Args>
+ constexpr explicit Optional(in_place_t, Args&&... args)
+ : internal::OptionalBase<T>(in_place, std::forward<Args>(args)...) {}
+
+ template <
+ class U,
+ class... Args,
+ class = std::enable_if_t<std::is_constructible<value_type,
+ std::initializer_list<U>&,
+ Args...>::value>>
+ constexpr explicit Optional(in_place_t,
+ std::initializer_list<U> il,
+ Args&&... args)
+ : internal::OptionalBase<T>(in_place, il, std::forward<Args>(args)...) {}
+
+ // Forward value constructor. Similar to converting constructors,
+ // conditionally explicit.
+ template <
+ typename U = value_type,
+ std::enable_if_t<
+ std::is_constructible<T, U&&>::value &&
+ !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
+ !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
+ std::is_convertible<U&&, T>::value,
+ bool> = false>
+ constexpr Optional(U&& value)
+ : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
+
+ template <
+ typename U = value_type,
+ std::enable_if_t<
+ std::is_constructible<T, U&&>::value &&
+ !std::is_same<internal::RemoveCvRefT<U>, in_place_t>::value &&
+ !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
+ !std::is_convertible<U&&, T>::value,
+ bool> = false>
+ constexpr explicit Optional(U&& value)
+ : internal::OptionalBase<T>(in_place, std::forward<U>(value)) {}
+
+ ~Optional() = default;
+
+ // Defer copy-/move- assign operator implementation to OptionalBase.
+ Optional& operator=(const Optional& other) = default;
+ Optional& operator=(Optional&& other) noexcept(
+ std::is_nothrow_move_assignable<T>::value&&
+ std::is_nothrow_move_constructible<T>::value) = default;
+
+ Optional& operator=(nullopt_t) {
+ FreeIfNeeded();
+ return *this;
+ }
+
+ // Perfect-forwarded assignment.
+ template <typename U>
+ std::enable_if_t<
+ !std::is_same<internal::RemoveCvRefT<U>, Optional<T>>::value &&
+ std::is_constructible<T, U>::value &&
+ std::is_assignable<T&, U>::value &&
+ (!std::is_scalar<T>::value ||
+ !std::is_same<std::decay_t<U>, T>::value),
+ Optional&>
+ operator=(U&& value) {
+ InitOrAssign(std::forward<U>(value));
+ return *this;
+ }
+
+ // Copy assign the state of other.
+ template <typename U>
+ std::enable_if_t<!internal::IsAssignableFromOptional<T, U>::value &&
+ std::is_constructible<T, const U&>::value &&
+ std::is_assignable<T&, const U&>::value,
+ Optional&>
+ operator=(const Optional<U>& other) {
+ CopyAssign(other);
+ return *this;
+ }
+
+ // Move assign the state of other.
+ template <typename U>
+ std::enable_if_t<!internal::IsAssignableFromOptional<T, U>::value &&
+ std::is_constructible<T, U>::value &&
+ std::is_assignable<T&, U>::value,
+ Optional&>
+ operator=(Optional<U>&& other) {
+ MoveAssign(std::move(other));
+ return *this;
+ }
+
+ constexpr const T* operator->() const {
+ CHECK(storage_.is_populated_);
+ return &storage_.value_;
+ }
+
+ constexpr T* operator->() {
+ CHECK(storage_.is_populated_);
+ return &storage_.value_;
+ }
+
+ constexpr const T& operator*() const & {
+ CHECK(storage_.is_populated_);
+ return storage_.value_;
+ }
+
+ constexpr T& operator*() & {
+ CHECK(storage_.is_populated_);
+ return storage_.value_;
+ }
+
+ constexpr const T&& operator*() const && {
+ CHECK(storage_.is_populated_);
+ return std::move(storage_.value_);
+ }
+
+ constexpr T&& operator*() && {
+ CHECK(storage_.is_populated_);
+ return std::move(storage_.value_);
+ }
+
+ constexpr explicit operator bool() const { return storage_.is_populated_; }
+
+ constexpr bool has_value() const { return storage_.is_populated_; }
+
+ constexpr T& value() & {
+ CHECK(storage_.is_populated_);
+ return storage_.value_;
+ }
+
+ constexpr const T& value() const & {
+ CHECK(storage_.is_populated_);
+ return storage_.value_;
+ }
+
+ constexpr T&& value() && {
+ CHECK(storage_.is_populated_);
+ return std::move(storage_.value_);
+ }
+
+ constexpr const T&& value() const && {
+ CHECK(storage_.is_populated_);
+ return std::move(storage_.value_);
+ }
+
+ template <class U>
+ constexpr T value_or(U&& default_value) const& {
+ // TODO(mlamouri): add the following assert when possible:
+ // static_assert(std::is_copy_constructible<T>::value,
+ // "T must be copy constructible");
+ static_assert(std::is_convertible<U, T>::value,
+ "U must be convertible to T");
+ return storage_.is_populated_
+ ? storage_.value_
+ : static_cast<T>(std::forward<U>(default_value));
+ }
+
+ template <class U>
+ constexpr T value_or(U&& default_value) && {
+ // TODO(mlamouri): add the following assert when possible:
+ // static_assert(std::is_move_constructible<T>::value,
+ // "T must be move constructible");
+ static_assert(std::is_convertible<U, T>::value,
+ "U must be convertible to T");
+ return storage_.is_populated_
+ ? std::move(storage_.value_)
+ : static_cast<T>(std::forward<U>(default_value));
+ }
+
+ void swap(Optional& other) {
+ if (!storage_.is_populated_ && !other.storage_.is_populated_)
+ return;
+
+ if (storage_.is_populated_ != other.storage_.is_populated_) {
+ if (storage_.is_populated_) {
+ other.storage_.Init(std::move(storage_.value_));
+ FreeIfNeeded();
+ } else {
+ storage_.Init(std::move(other.storage_.value_));
+ other.FreeIfNeeded();
+ }
+ return;
+ }
+
+ DCHECK(storage_.is_populated_ && other.storage_.is_populated_);
+ using std::swap;
+ swap(**this, *other);
+ }
+
+ void reset() { FreeIfNeeded(); }
+
+ template <class... Args>
+ T& emplace(Args&&... args) {
+ FreeIfNeeded();
+ storage_.Init(std::forward<Args>(args)...);
+ return storage_.value_;
+ }
+
+ template <class U, class... Args>
+ std::enable_if_t<
+ std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value,
+ T&>
+ emplace(std::initializer_list<U> il, Args&&... args) {
+ FreeIfNeeded();
+ storage_.Init(il, std::forward<Args>(args)...);
+ return storage_.value_;
+ }
+
+ private:
+ // Accessing template base class's protected member needs explicit
+ // declaration to do so.
+ using internal::OptionalBase<T>::CopyAssign;
+ using internal::OptionalBase<T>::FreeIfNeeded;
+ using internal::OptionalBase<T>::InitOrAssign;
+ using internal::OptionalBase<T>::MoveAssign;
+ using internal::OptionalBase<T>::storage_;
+};
+
+// Here after defines comparation operators. The definition follows
+// http://en.cppreference.com/w/cpp/utility/optional/operator_cmp
+// while bool() casting is replaced by has_value() to meet the chromium
+// style guide.
+template <class T, class U>
+constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
+ if (lhs.has_value() != rhs.has_value())
+ return false;
+ if (!lhs.has_value())
+ return true;
+ return *lhs == *rhs;
+}
+
+template <class T, class U>
+constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
+ if (lhs.has_value() != rhs.has_value())
+ return true;
+ if (!lhs.has_value())
+ return false;
+ return *lhs != *rhs;
+}
+
+template <class T, class U>
+constexpr bool operator<(const Optional<T>& lhs, const Optional<U>& rhs) {
+ if (!rhs.has_value())
+ return false;
+ if (!lhs.has_value())
+ return true;
+ return *lhs < *rhs;
+}
+
+template <class T, class U>
+constexpr bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs) {
+ if (!lhs.has_value())
+ return true;
+ if (!rhs.has_value())
+ return false;
+ return *lhs <= *rhs;
+}
+
+template <class T, class U>
+constexpr bool operator>(const Optional<T>& lhs, const Optional<U>& rhs) {
+ if (!lhs.has_value())
+ return false;
+ if (!rhs.has_value())
+ return true;
+ return *lhs > *rhs;
+}
+
+template <class T, class U>
+constexpr bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs) {
+ if (!rhs.has_value())
+ return true;
+ if (!lhs.has_value())
+ return false;
+ return *lhs >= *rhs;
+}
+
+template <class T>
+constexpr bool operator==(const Optional<T>& opt, nullopt_t) {
+ return !opt;
+}
+
+template <class T>
+constexpr bool operator==(nullopt_t, const Optional<T>& opt) {
+ return !opt;
+}
+
+template <class T>
+constexpr bool operator!=(const Optional<T>& opt, nullopt_t) {
+ return opt.has_value();
+}
+
+template <class T>
+constexpr bool operator!=(nullopt_t, const Optional<T>& opt) {
+ return opt.has_value();
+}
+
+template <class T>
+constexpr bool operator<(const Optional<T>& opt, nullopt_t) {
+ return false;
+}
+
+template <class T>
+constexpr bool operator<(nullopt_t, const Optional<T>& opt) {
+ return opt.has_value();
+}
+
+template <class T>
+constexpr bool operator<=(const Optional<T>& opt, nullopt_t) {
+ return !opt;
+}
+
+template <class T>
+constexpr bool operator<=(nullopt_t, const Optional<T>& opt) {
+ return true;
+}
+
+template <class T>
+constexpr bool operator>(const Optional<T>& opt, nullopt_t) {
+ return opt.has_value();
+}
+
+template <class T>
+constexpr bool operator>(nullopt_t, const Optional<T>& opt) {
+ return false;
+}
+
+template <class T>
+constexpr bool operator>=(const Optional<T>& opt, nullopt_t) {
+ return true;
+}
+
+template <class T>
+constexpr bool operator>=(nullopt_t, const Optional<T>& opt) {
+ return !opt;
+}
+
+template <class T, class U>
+constexpr bool operator==(const Optional<T>& opt, const U& value) {
+ return opt.has_value() ? *opt == value : false;
+}
+
+template <class T, class U>
+constexpr bool operator==(const U& value, const Optional<T>& opt) {
+ return opt.has_value() ? value == *opt : false;
+}
+
+template <class T, class U>
+constexpr bool operator!=(const Optional<T>& opt, const U& value) {
+ return opt.has_value() ? *opt != value : true;
+}
+
+template <class T, class U>
+constexpr bool operator!=(const U& value, const Optional<T>& opt) {
+ return opt.has_value() ? value != *opt : true;
+}
+
+template <class T, class U>
+constexpr bool operator<(const Optional<T>& opt, const U& value) {
+ return opt.has_value() ? *opt < value : true;
+}
+
+template <class T, class U>
+constexpr bool operator<(const U& value, const Optional<T>& opt) {
+ return opt.has_value() ? value < *opt : false;
+}
+
+template <class T, class U>
+constexpr bool operator<=(const Optional<T>& opt, const U& value) {
+ return opt.has_value() ? *opt <= value : true;
+}
+
+template <class T, class U>
+constexpr bool operator<=(const U& value, const Optional<T>& opt) {
+ return opt.has_value() ? value <= *opt : false;
+}
+
+template <class T, class U>
+constexpr bool operator>(const Optional<T>& opt, const U& value) {
+ return opt.has_value() ? *opt > value : false;
+}
+
+template <class T, class U>
+constexpr bool operator>(const U& value, const Optional<T>& opt) {
+ return opt.has_value() ? value > *opt : true;
+}
+
+template <class T, class U>
+constexpr bool operator>=(const Optional<T>& opt, const U& value) {
+ return opt.has_value() ? *opt >= value : false;
+}
+
+template <class T, class U>
+constexpr bool operator>=(const U& value, const Optional<T>& opt) {
+ return opt.has_value() ? value >= *opt : true;
+}
+
+template <class T>
+constexpr Optional<std::decay_t<T>> make_optional(T&& value) {
+ return Optional<std::decay_t<T>>(std::forward<T>(value));
+}
+
+template <class T, class... Args>
+constexpr Optional<T> make_optional(Args&&... args) {
+ return Optional<T>(in_place, std::forward<Args>(args)...);
+}
+
+template <class T, class U, class... Args>
+constexpr Optional<T> make_optional(std::initializer_list<U> il,
+ Args&&... args) {
+ return Optional<T>(in_place, il, std::forward<Args>(args)...);
+}
+
+// Partial specialization for a function template is not allowed. Also, it is
+// not allowed to add overload function to std namespace, while it is allowed
+// to specialize the template in std. Thus, swap() (kind of) overloading is
+// defined in base namespace, instead.
+template <class T>
+std::enable_if_t<std::is_move_constructible<T>::value &&
+ internal::IsSwappable<T>::value>
+swap(Optional<T>& lhs, Optional<T>& rhs) {
+ lhs.swap(rhs);
+}
+
+} // namespace base
+
+namespace std {
+
+template <class T>
+struct hash<base::Optional<T>> {
+ size_t operator()(const base::Optional<T>& opt) const {
+ return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
+ }
+};
+
+} // namespace std
+
+#endif // BASE_OPTIONAL_H_
diff --git a/security/sandbox/chromium/base/os_compat_android.h b/security/sandbox/chromium/base/os_compat_android.h
new file mode 100644
index 0000000000..e33b1f7ac3
--- /dev/null
+++ b/security/sandbox/chromium/base/os_compat_android.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_OS_COMPAT_ANDROID_H_
+#define BASE_OS_COMPAT_ANDROID_H_
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utime.h>
+
+// Not implemented in Bionic.
+extern "C" int futimes(int fd, const struct timeval tv[2]);
+
+// Not exposed or implemented in Bionic.
+extern "C" char* mkdtemp(char* path);
+
+// Android has no timegm().
+extern "C" time_t timegm(struct tm* const t);
+
+#endif // BASE_OS_COMPAT_ANDROID_H_
diff --git a/security/sandbox/chromium/base/path_service.h b/security/sandbox/chromium/base/path_service.h
new file mode 100644
index 0000000000..9b4715f073
--- /dev/null
+++ b/security/sandbox/chromium/base/path_service.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PATH_SERVICE_H_
+#define BASE_PATH_SERVICE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/base_paths.h"
+#include "base/gtest_prod_util.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+class ScopedPathOverride;
+
+// The path service is a global table mapping keys to file system paths. It is
+// OK to use this service from multiple threads.
+//
+class BASE_EXPORT PathService {
+ public:
+ // Retrieves a path to a special directory or file and places it into the
+ // string pointed to by 'path'. If you ask for a directory it is guaranteed
+ // to NOT have a path separator at the end. For example, "c:\windows\temp"
+ // Directories are also guaranteed to exist when this function succeeds.
+ //
+ // Returns true if the directory or file was successfully retrieved. On
+ // failure, 'path' will not be changed.
+ static bool Get(int key, FilePath* path);
+
+ // Overrides the path to a special directory or file. This cannot be used to
+ // change the value of DIR_CURRENT, but that should be obvious. Also, if the
+ // path specifies a directory that does not exist, the directory will be
+ // created by this method. This method returns true if successful.
+ //
+ // If the given path is relative, then it will be resolved against
+ // DIR_CURRENT.
+ //
+ // WARNING: Consumers of PathService::Get may expect paths to be constant
+ // over the lifetime of the app, so this method should be used with caution.
+ //
+ // Unit tests generally should use ScopedPathOverride instead. Overrides from
+ // one test should not carry over to another.
+ static bool Override(int key, const FilePath& path);
+
+ // This function does the same as PathService::Override but it takes extra
+ // parameters:
+ // - |is_absolute| indicates that |path| has already been expanded into an
+ // absolute path, otherwise MakeAbsoluteFilePath() will be used. This is
+ // useful to override paths that may not exist yet, since MakeAbsoluteFilePath
+ // fails for those. Note that MakeAbsoluteFilePath also expands symbolic
+ // links, even if path.IsAbsolute() is already true.
+ // - |create| guides whether the directory to be overriden must
+ // be created in case it doesn't exist already.
+ static bool OverrideAndCreateIfNeeded(int key,
+ const FilePath& path,
+ bool is_absolute,
+ bool create);
+
+ // To extend the set of supported keys, you can register a path provider,
+ // which is just a function mirroring PathService::Get. The ProviderFunc
+ // returns false if it cannot provide a non-empty path for the given key.
+ // Otherwise, true is returned.
+ //
+ // WARNING: This function could be called on any thread from which the
+ // PathService is used, so a the ProviderFunc MUST BE THREADSAFE.
+ //
+ typedef bool (*ProviderFunc)(int, FilePath*);
+
+ // Call to register a path provider. You must specify the range "[key_start,
+ // key_end)" of supported path keys.
+ static void RegisterProvider(ProviderFunc provider,
+ int key_start,
+ int key_end);
+
+ // Disable internal cache.
+ static void DisableCache();
+
+ private:
+ friend class ScopedPathOverride;
+ FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
+
+ // Removes an override for a special directory or file. Returns true if there
+ // was an override to remove or false if none was present.
+ // NOTE: This function is intended to be used by tests only!
+ static bool RemoveOverride(int key);
+};
+
+} // namespace base
+
+#endif // BASE_PATH_SERVICE_H_
diff --git a/security/sandbox/chromium/base/posix/can_lower_nice_to.cc b/security/sandbox/chromium/base/posix/can_lower_nice_to.cc
new file mode 100644
index 0000000000..b1686dcae1
--- /dev/null
+++ b/security/sandbox/chromium/base/posix/can_lower_nice_to.cc
@@ -0,0 +1,60 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/posix/can_lower_nice_to.h"
+
+#include <limits.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "build/build_config.h"
+
+// Not defined on AIX by default.
+#if defined(OS_AIX)
+#if defined(RLIMIT_NICE)
+#error Assumption about OS_AIX is incorrect
+#endif
+#define RLIMIT_NICE 20
+#endif
+
+namespace base {
+namespace internal {
+
+bool CanLowerNiceTo(int nice_value) {
+ // On a POSIX system, the nice value of a thread can be lowered 1. by the root
+ // user, 2. by a user with the CAP_SYS_NICE permission or 3. by any user if
+ // the target value is within the range allowed by RLIMIT_NICE.
+
+ // 1. Check for root user.
+ if (geteuid() == 0)
+ return true;
+
+ // 2. Skip checking the CAP_SYS_NICE permission because it would require
+ // libcap.so.
+
+ // 3. Check whether the target value is within the range allowed by
+ // RLIMIT_NICE.
+ //
+ // NZERO should be defined in <limits.h> per POSIX, and should be at least 20.
+ // (NZERO-1) is the highest possible niceness value (i.e. lowest priority).
+ // Most platforms use NZERO=20.
+ //
+ // RLIMIT_NICE tells us how much we can reduce niceness (increase priority) if
+ // we start at NZERO. For example, if NZERO is 20 and the rlimit is 30, we can
+ // lower niceness anywhere within the [-10, 19] range (20 - 30 = -10).
+ //
+ // So, we are allowed to reduce niceness to a minimum of NZERO - rlimit:
+ struct rlimit rlim;
+ if (getrlimit(RLIMIT_NICE, &rlim) != 0)
+ return false;
+ const int lowest_nice_allowed = NZERO - static_cast<int>(rlim.rlim_cur);
+
+ // And lowering niceness to |nice_value| is allowed if it is greater than or
+ // equal to the limit:
+ return nice_value >= lowest_nice_allowed;
+}
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/posix/can_lower_nice_to.h b/security/sandbox/chromium/base/posix/can_lower_nice_to.h
new file mode 100644
index 0000000000..aa8f02e9f7
--- /dev/null
+++ b/security/sandbox/chromium/base/posix/can_lower_nice_to.h
@@ -0,0 +1,19 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POSIX_CAN_LOWER_NICE_TO_H_
+#define BASE_POSIX_CAN_LOWER_NICE_TO_H_
+
+namespace base {
+namespace internal {
+
+// Returns true if lowering the nice value of a process or thread to
+// |nice_value| using setpriority() or nice() should succeed. Note: A lower nice
+// value means a higher priority.
+bool CanLowerNiceTo(int nice_value);
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_POSIX_CAN_LOWER_NICE_TO_H_
diff --git a/security/sandbox/chromium/base/posix/eintr_wrapper.h b/security/sandbox/chromium/base/posix/eintr_wrapper.h
new file mode 100644
index 0000000000..0e6e437953
--- /dev/null
+++ b/security/sandbox/chromium/base/posix/eintr_wrapper.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+// To prevent long-lasting loops (which would likely be a bug, such as a signal
+// that should be masked) to go unnoticed, there is a limit after which the
+// caller will nonetheless see an EINTR in Debug builds.
+//
+// On Windows and Fuchsia, this wrapper macro does nothing because there are no
+// signals.
+//
+// Don't wrap close calls in HANDLE_EINTR. Use IGNORE_EINTR if the return
+// value of close is significant. See http://crbug.com/269623.
+
+#ifndef BASE_POSIX_EINTR_WRAPPER_H_
+#define BASE_POSIX_EINTR_WRAPPER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+
+#include <errno.h>
+
+#if defined(NDEBUG)
+
+#define HANDLE_EINTR(x) ({ \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ } while (eintr_wrapper_result == -1 && errno == EINTR); \
+ eintr_wrapper_result; \
+})
+
+#else
+
+#define HANDLE_EINTR(x) ({ \
+ int eintr_wrapper_counter = 0; \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ } while (eintr_wrapper_result == -1 && errno == EINTR && \
+ eintr_wrapper_counter++ < 100); \
+ eintr_wrapper_result; \
+})
+
+#endif // NDEBUG
+
+#define IGNORE_EINTR(x) ({ \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ if (eintr_wrapper_result == -1 && errno == EINTR) { \
+ eintr_wrapper_result = 0; \
+ } \
+ } while (0); \
+ eintr_wrapper_result; \
+})
+
+#else // !OS_POSIX
+
+#define HANDLE_EINTR(x) (x)
+#define IGNORE_EINTR(x) (x)
+
+#endif // !OS_POSIX
+
+#endif // BASE_POSIX_EINTR_WRAPPER_H_
diff --git a/security/sandbox/chromium/base/posix/safe_strerror.cc b/security/sandbox/chromium/base/posix/safe_strerror.cc
new file mode 100644
index 0000000000..aef5742d33
--- /dev/null
+++ b/security/sandbox/chromium/base/posix/safe_strerror.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(__ANDROID__)
+// Post-L versions of bionic define the GNU-specific strerror_r if _GNU_SOURCE
+// is defined, but the symbol is renamed to __gnu_strerror_r which only exists
+// on those later versions. To preserve ABI compatibility with older versions,
+// undefine _GNU_SOURCE and use the POSIX version.
+#undef _GNU_SOURCE
+#endif
+
+#include "base/posix/safe_strerror.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "build/build_config.h"
+
+namespace base {
+
+#if defined(__GLIBC__) || defined(OS_NACL)
+#define USE_HISTORICAL_STRERRO_R 1
+#else
+#define USE_HISTORICAL_STRERRO_R 0
+#endif
+
+#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
+// GCC will complain about the unused second wrap function unless we tell it
+// that we meant for them to be potentially unused, which is exactly what this
+// attribute is for.
+#define POSSIBLY_UNUSED __attribute__((unused))
+#else
+#define POSSIBLY_UNUSED
+#endif
+
+#if USE_HISTORICAL_STRERRO_R
+// glibc has two strerror_r functions: a historical GNU-specific one that
+// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
+// that returns int. This wraps the GNU-specific one.
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+ char *(*strerror_r_ptr)(int, char *, size_t),
+ int err,
+ char *buf,
+ size_t len) {
+ // GNU version.
+ char *rc = (*strerror_r_ptr)(err, buf, len);
+ if (rc != buf) {
+ // glibc did not use buf and returned a static string instead. Copy it
+ // into buf.
+ buf[0] = '\0';
+ strncat(buf, rc, len - 1);
+ }
+ // The GNU version never fails. Unknown errors get an "unknown error" message.
+ // The result is always null terminated.
+}
+#endif // USE_HISTORICAL_STRERRO_R
+
+// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
+// does not define the behaviour for some of the edge cases, so we wrap it to
+// guarantee that they are handled. This is compiled on all POSIX platforms, but
+// it will only be used on Linux if the POSIX strerror_r implementation is
+// being used (see below).
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+ int (*strerror_r_ptr)(int, char *, size_t),
+ int err,
+ char *buf,
+ size_t len) {
+ int old_errno = errno;
+ // Have to cast since otherwise we get an error if this is the GNU version
+ // (but in such a scenario this function is never called). Sadly we can't use
+ // C++-style casts because the appropriate one is reinterpret_cast but it's
+ // considered illegal to reinterpret_cast a type to itself, so we get an
+ // error in the opposite case.
+ int result = (*strerror_r_ptr)(err, buf, len);
+ if (result == 0) {
+ // POSIX is vague about whether the string will be terminated, although
+ // it indirectly implies that typically ERANGE will be returned, instead
+ // of truncating the string. We play it safe by always terminating the
+ // string explicitly.
+ buf[len - 1] = '\0';
+ } else {
+ // Error. POSIX is vague about whether the return value is itself a system
+ // error code or something else. On Linux currently it is -1 and errno is
+ // set. On BSD-derived systems it is a system error and errno is unchanged.
+ // We try and detect which case it is so as to put as much useful info as
+ // we can into our message.
+ int strerror_error; // The error encountered in strerror
+ int new_errno = errno;
+ if (new_errno != old_errno) {
+ // errno was changed, so probably the return value is just -1 or something
+ // else that doesn't provide any info, and errno is the error.
+ strerror_error = new_errno;
+ } else {
+ // Either the error from strerror_r was the same as the previous value, or
+ // errno wasn't used. Assume the latter.
+ strerror_error = result;
+ }
+ // snprintf truncates and always null-terminates.
+ snprintf(buf,
+ len,
+ "Error %d while retrieving error %d",
+ strerror_error,
+ err);
+ }
+ errno = old_errno;
+}
+
+void safe_strerror_r(int err, char *buf, size_t len) {
+ if (buf == nullptr || len <= 0) {
+ return;
+ }
+ // If using glibc (i.e., Linux), the compiler will automatically select the
+ // appropriate overloaded function based on the function type of strerror_r.
+ // The other one will be elided from the translation unit since both are
+ // static.
+ wrap_posix_strerror_r(&strerror_r, err, buf, len);
+}
+
+std::string safe_strerror(int err) {
+ const int buffer_size = 256;
+ char buf[buffer_size];
+ safe_strerror_r(err, buf, sizeof(buf));
+ return std::string(buf);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/posix/safe_strerror.h b/security/sandbox/chromium/base/posix/safe_strerror.h
new file mode 100644
index 0000000000..2945312910
--- /dev/null
+++ b/security/sandbox/chromium/base/posix/safe_strerror.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POSIX_SAFE_STRERROR_H_
+#define BASE_POSIX_SAFE_STRERROR_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// BEFORE using anything from this file, first look at PLOG and friends in
+// logging.h and use them instead if applicable.
+//
+// This file declares safe, portable alternatives to the POSIX strerror()
+// function. strerror() is inherently unsafe in multi-threaded apps and should
+// never be used. Doing so can cause crashes. Additionally, the thread-safe
+// alternative strerror_r varies in semantics across platforms. Use these
+// functions instead.
+
+// Thread-safe strerror function with dependable semantics that never fails.
+// It will write the string form of error "err" to buffer buf of length len.
+// If there is an error calling the OS's strerror_r() function then a message to
+// that effect will be printed into buf, truncating if necessary. The final
+// result is always null-terminated. The value of errno is never changed.
+//
+// Use this instead of strerror_r().
+BASE_EXPORT void safe_strerror_r(int err, char *buf, size_t len);
+
+// Calls safe_strerror_r with a buffer of suitable size and returns the result
+// in a C++ string.
+//
+// Use this instead of strerror(). Note though that safe_strerror_r will be
+// more robust in the case of heap corruption errors, since it doesn't need to
+// allocate a string.
+BASE_EXPORT std::string safe_strerror(int err);
+
+} // namespace base
+
+#endif // BASE_POSIX_SAFE_STRERROR_H_
diff --git a/security/sandbox/chromium/base/process/environment_internal.cc b/security/sandbox/chromium/base/process/environment_internal.cc
new file mode 100644
index 0000000000..357140fa6f
--- /dev/null
+++ b/security/sandbox/chromium/base/process/environment_internal.cc
@@ -0,0 +1,128 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/environment_internal.h"
+
+#include <stddef.h>
+
+#include <vector>
+
+namespace base {
+namespace internal {
+
+namespace {
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA) || defined(OS_WIN)
+// Parses a null-terminated input string of an environment block. The key is
+// placed into the given string, and the total length of the line, including
+// the terminating null, is returned.
+size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
+ NativeEnvironmentString* key) {
+ // Skip to the equals or end of the string, this is the key.
+ size_t cur = 0;
+ while (input[cur] && input[cur] != '=')
+ cur++;
+ *key = NativeEnvironmentString(&input[0], cur);
+
+ // Now just skip to the end of the string.
+ while (input[cur])
+ cur++;
+ return cur + 1;
+}
+#endif
+
+} // namespace
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+
+std::unique_ptr<char* []> AlterEnvironment(const char* const* const env,
+ const EnvironmentMap& changes) {
+ std::string value_storage; // Holds concatenated null-terminated strings.
+ std::vector<size_t> result_indices; // Line indices into value_storage.
+
+ // First build up all of the unchanged environment strings. These are
+ // null-terminated of the form "key=value".
+ std::string key;
+ for (size_t i = 0; env[i]; i++) {
+ size_t line_length = ParseEnvLine(env[i], &key);
+
+ // Keep only values not specified in the change vector.
+ auto found_change = changes.find(key);
+ if (found_change == changes.end()) {
+ result_indices.push_back(value_storage.size());
+ value_storage.append(env[i], line_length);
+ }
+ }
+
+ // Now append all modified and new values.
+ for (const auto& i : changes) {
+ if (!i.second.empty()) {
+ result_indices.push_back(value_storage.size());
+ value_storage.append(i.first);
+ value_storage.push_back('=');
+ value_storage.append(i.second);
+ value_storage.push_back(0);
+ }
+ }
+
+ size_t pointer_count_required =
+ result_indices.size() + 1 + // Null-terminated array of pointers.
+ (value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer.
+ std::unique_ptr<char*[]> result(new char*[pointer_count_required]);
+
+ // The string storage goes after the array of pointers.
+ char* storage_data =
+ reinterpret_cast<char*>(&result.get()[result_indices.size() + 1]);
+ if (!value_storage.empty())
+ memcpy(storage_data, value_storage.data(), value_storage.size());
+
+ // Fill array of pointers at the beginning of the result.
+ for (size_t i = 0; i < result_indices.size(); i++)
+ result[i] = &storage_data[result_indices[i]];
+ result[result_indices.size()] = 0; // Null terminator.
+
+ return result;
+}
+
+#elif defined(OS_WIN)
+
+NativeEnvironmentString AlterEnvironment(const wchar_t* env,
+ const EnvironmentMap& changes) {
+ NativeEnvironmentString result;
+
+ // First build up all of the unchanged environment strings.
+ const wchar_t* ptr = env;
+ while (*ptr) {
+ std::wstring key;
+ size_t line_length = ParseEnvLine(ptr, &key);
+
+ // Keep only values not specified in the change vector.
+ if (changes.find(key) == changes.end()) {
+ result.append(ptr, line_length);
+ }
+ ptr += line_length;
+ }
+
+ // Now append all modified and new values.
+ for (const auto& i : changes) {
+ // Windows environment blocks cannot handle keys or values with NULs.
+ CHECK_EQ(std::wstring::npos, i.first.find(L'\0'));
+ CHECK_EQ(std::wstring::npos, i.second.find(L'\0'));
+ if (!i.second.empty()) {
+ result += i.first;
+ result.push_back('=');
+ result += i.second;
+ result.push_back('\0');
+ }
+ }
+
+ // Add the terminating NUL.
+ result.push_back('\0');
+ return result;
+}
+
+#endif // OS_POSIX || OS_FUCHSIA
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/process/environment_internal.h b/security/sandbox/chromium/base/process/environment_internal.h
new file mode 100644
index 0000000000..31338f1320
--- /dev/null
+++ b/security/sandbox/chromium/base/process/environment_internal.h
@@ -0,0 +1,52 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains internal routines that are called by other files in
+// base/process/.
+
+#ifndef BASE_PROCESS_ENVIRONMENT_INTERNAL_H_
+#define BASE_PROCESS_ENVIRONMENT_INTERNAL_H_
+
+#include <memory>
+
+#include "base/environment.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace internal {
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+// Returns a modified environment vector constructed from the given environment
+// and the list of changes given in |changes|. Each key in the environment is
+// matched against the first element of the pairs. In the event of a match, the
+// value is replaced by the second of the pair, unless the second is empty, in
+// which case the key-value is removed.
+//
+// This POSIX version takes and returns a POSIX-style environment block, which
+// is a null-terminated list of pointers to null-terminated strings. The
+// returned array will have appended to it the storage for the array itself so
+// there is only one pointer to manage, but this means that you can't copy the
+// array without keeping the original around.
+BASE_EXPORT std::unique_ptr<char*[]> AlterEnvironment(
+ const char* const* env,
+ const EnvironmentMap& changes);
+#elif defined(OS_WIN)
+// Returns a modified environment vector constructed from the given environment
+// and the list of changes given in |changes|. Each key in the environment is
+// matched against the first element of the pairs. In the event of a match, the
+// value is replaced by the second of the pair, unless the second is empty, in
+// which case the key-value is removed.
+//
+// This Windows version takes and returns a Windows-style environment block,
+// which is a string containing several null-terminated strings followed by an
+// extra terminating null character. So, e.g., the environment A=1 B=2 is
+// represented as L"A=1\0B=2\0\0".
+BASE_EXPORT NativeEnvironmentString
+AlterEnvironment(const wchar_t* env, const EnvironmentMap& changes);
+#endif // OS_*
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_PROCESS_ENVIRONMENT_INTERNAL_H_
diff --git a/security/sandbox/chromium/base/process/kill.h b/security/sandbox/chromium/base/process/kill.h
new file mode 100644
index 0000000000..70a04d97e5
--- /dev/null
+++ b/security/sandbox/chromium/base/process/kill.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains routines to kill processes and get the exit code and
+// termination status.
+
+#ifndef BASE_PROCESS_KILL_H_
+#define BASE_PROCESS_KILL_H_
+
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class ProcessFilter;
+
+#if defined(OS_WIN)
+namespace win {
+
+// See definition in sandbox/win/src/sandbox_types.h
+const DWORD kSandboxFatalMemoryExceeded = 7012;
+
+// Exit codes with special meanings on Windows.
+const DWORD kNormalTerminationExitCode = 0;
+const DWORD kDebuggerInactiveExitCode = 0xC0000354;
+const DWORD kKeyboardInterruptExitCode = 0xC000013A;
+const DWORD kDebuggerTerminatedExitCode = 0x40010004;
+const DWORD kStatusInvalidImageHashExitCode = 0xC0000428;
+
+// This exit code is used by the Windows task manager when it kills a
+// process. It's value is obviously not that unique, and it's
+// surprising to me that the task manager uses this value, but it
+// seems to be common practice on Windows to test for it as an
+// indication that the task manager has killed something if the
+// process goes away.
+const DWORD kProcessKilledExitCode = 1;
+
+} // namespace win
+
+#endif // OS_WIN
+
+// Return status values from GetTerminationStatus. Don't use these as
+// exit code arguments to KillProcess*(), use platform/application
+// specific values instead.
+enum TerminationStatus {
+ // clang-format off
+ TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status
+ TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status
+ TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill
+ TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault
+ TERMINATION_STATUS_STILL_RUNNING, // child hasn't exited yet
+#if defined(OS_CHROMEOS)
+ // Used for the case when oom-killer kills a process on ChromeOS.
+ TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM,
+#endif
+#if defined(OS_ANDROID)
+ // On Android processes are spawned from the system Zygote and we do not get
+ // the termination status. We can't know if the termination was a crash or an
+ // oom kill for sure, but we can use status of the strong process bindings as
+ // a hint.
+ TERMINATION_STATUS_OOM_PROTECTED, // child was protected from oom kill
+#endif
+ TERMINATION_STATUS_LAUNCH_FAILED, // child process never launched
+ TERMINATION_STATUS_OOM, // Process died due to oom
+#if defined(OS_WIN)
+ // On Windows, the OS terminated process due to code integrity failure.
+ TERMINATION_STATUS_INTEGRITY_FAILURE,
+#endif
+ TERMINATION_STATUS_MAX_ENUM
+ // clang-format on
+};
+
+// Attempts to kill all the processes on the current machine that were launched
+// from the given executable name, ending them with the given exit code. If
+// filter is non-null, then only processes selected by the filter are killed.
+// Returns true if all processes were able to be killed off, false if at least
+// one couldn't be killed.
+BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name,
+ int exit_code,
+ const ProcessFilter* filter);
+
+#if defined(OS_POSIX)
+// Attempts to kill the process group identified by |process_group_id|. Returns
+// true on success.
+BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id);
+#endif // defined(OS_POSIX)
+
+// Get the termination status of the process by interpreting the
+// circumstances of the child process' death. |exit_code| is set to
+// the status returned by waitpid() on POSIX, and from GetExitCodeProcess() on
+// Windows, and may not be null. Note that on Linux, this function
+// will only return a useful result the first time it is called after
+// the child exits (because it will reap the child and the information
+// will no longer be available).
+BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle,
+ int* exit_code);
+
+#if defined(OS_POSIX)
+// Send a kill signal to the process and then wait for the process to exit
+// and get the termination status.
+//
+// This is used in situations where it is believed that the process is dead
+// or dying (because communication with the child process has been cut).
+// In order to avoid erroneously returning that the process is still running
+// because the kernel is still cleaning it up, this will wait for the process
+// to terminate. In order to avoid the risk of hanging while waiting for the
+// process to terminate, send a SIGKILL to the process before waiting for the
+// termination status.
+//
+// Note that it is not an option to call WaitForExitCode and then
+// GetTerminationStatus as the child will be reaped when WaitForExitCode
+// returns, and this information will be lost.
+//
+BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus(
+ ProcessHandle handle, int* exit_code);
+
+#if defined(OS_LINUX)
+// Spawns a thread to wait asynchronously for the child |process| to exit
+// and then reaps it.
+BASE_EXPORT void EnsureProcessGetsReaped(Process process);
+#endif // defined(OS_LINUX)
+#endif // defined(OS_POSIX)
+
+// Registers |process| to be asynchronously monitored for termination, forcibly
+// terminated if necessary, and reaped on exit. The caller should have signalled
+// |process| to exit before calling this API. The API will allow a couple of
+// seconds grace period before forcibly terminating |process|.
+// TODO(https://crbug.com/806451): The Mac implementation currently blocks the
+// calling thread for up to two seconds.
+BASE_EXPORT void EnsureProcessTerminated(Process process);
+
+// These are only sparingly used, and not needed on Fuchsia. They could be
+// implemented if necessary.
+#if !defined(OS_FUCHSIA)
+// Wait for all the processes based on the named executable to exit. If filter
+// is non-null, then only processes selected by the filter are waited on.
+// Returns after all processes have exited or wait_milliseconds have expired.
+// Returns true if all the processes exited, false otherwise.
+BASE_EXPORT bool WaitForProcessesToExit(
+ const FilePath::StringType& executable_name,
+ base::TimeDelta wait,
+ const ProcessFilter* filter);
+
+// Waits a certain amount of time (can be 0) for all the processes with a given
+// executable name to exit, then kills off any of them that are still around.
+// If filter is non-null, then only processes selected by the filter are waited
+// on. Killed processes are ended with the given exit code. Returns false if
+// any processes needed to be killed, true if they all exited cleanly within
+// the wait_milliseconds delay.
+BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name,
+ base::TimeDelta wait,
+ int exit_code,
+ const ProcessFilter* filter);
+#endif // !defined(OS_FUCHSIA)
+
+} // namespace base
+
+#endif // BASE_PROCESS_KILL_H_
diff --git a/security/sandbox/chromium/base/process/memory.h b/security/sandbox/chromium/base/process/memory.h
new file mode 100644
index 0000000000..ddbb9d957c
--- /dev/null
+++ b/security/sandbox/chromium/base/process/memory.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_MEMORY_H_
+#define BASE_PROCESS_MEMORY_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Enables 'terminate on heap corruption' flag. Helps protect against heap
+// overflow. Has no effect if the OS doesn't provide the necessary facility.
+BASE_EXPORT void EnableTerminationOnHeapCorruption();
+
+// Turns on process termination if memory runs out.
+BASE_EXPORT void EnableTerminationOnOutOfMemory();
+
+// Terminates process. Should be called only for out of memory errors.
+// Crash reporting classifies such crashes as OOM.
+BASE_EXPORT void TerminateBecauseOutOfMemory(size_t size);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_AIX)
+BASE_EXPORT extern size_t g_oom_size;
+
+// The maximum allowed value for the OOM score.
+const int kMaxOomScore = 1000;
+
+// This adjusts /proc/<pid>/oom_score_adj so the Linux OOM killer will
+// prefer to kill certain process types over others. The range for the
+// adjustment is [-1000, 1000], with [0, 1000] being user accessible.
+// If the Linux system doesn't support the newer oom_score_adj range
+// of [0, 1000], then we revert to using the older oom_adj, and
+// translate the given value into [0, 15]. Some aliasing of values
+// may occur in that case, of course.
+BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score);
+#endif
+
+namespace internal {
+// Returns true if address-space was released. Some configurations reserve part
+// of the process address-space for special allocations (e.g. WASM).
+bool ReleaseAddressSpaceReservation();
+} // namespace internal
+
+#if defined(OS_WIN)
+namespace win {
+
+// Custom Windows exception code chosen to indicate an out of memory error.
+// See https://msdn.microsoft.com/en-us/library/het71c37.aspx.
+// "To make sure that you do not define a code that conflicts with an existing
+// exception code" ... "The resulting error code should therefore have the
+// highest four bits set to hexadecimal E."
+// 0xe0000008 was chosen arbitrarily, as 0x00000008 is ERROR_NOT_ENOUGH_MEMORY.
+const DWORD kOomExceptionCode = 0xe0000008;
+
+} // namespace win
+#endif
+
+namespace internal {
+
+// Handles out of memory, with the failed allocation |size|, or 0 when it is not
+// known.
+BASE_EXPORT void OnNoMemoryInternal(size_t size);
+
+} // namespace internal
+
+// Special allocator functions for callers that want to check for OOM.
+// These will not abort if the allocation fails even if
+// EnableTerminationOnOutOfMemory has been called.
+// This can be useful for huge and/or unpredictable size memory allocations.
+// Please only use this if you really handle the case when the allocation
+// fails. Doing otherwise would risk security.
+// These functions may still crash on OOM when running under memory tools,
+// specifically ASan and other sanitizers.
+// Return value tells whether the allocation succeeded. If it fails |result| is
+// set to NULL, otherwise it holds the memory address.
+BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedMalloc(size_t size,
+ void** result);
+BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedCalloc(size_t num_items,
+ size_t size,
+ void** result);
+
+} // namespace base
+
+#endif // BASE_PROCESS_MEMORY_H_
diff --git a/security/sandbox/chromium/base/process/process.h b/security/sandbox/chromium/base/process/process.h
new file mode 100644
index 0000000000..d6f8d83e36
--- /dev/null
+++ b/security/sandbox/chromium/base/process/process.h
@@ -0,0 +1,223 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_PROCESS_H_
+#define BASE_PROCESS_PROCESS_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+#if defined(OS_FUCHSIA)
+#include <lib/zx/process.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/feature_list.h"
+#include "base/process/port_provider_mac.h"
+#endif
+
+namespace base {
+
+#if defined(OS_MACOSX)
+extern const Feature kMacAllowBackgroundingProcesses;
+#endif
+
+// Provides a move-only encapsulation of a process.
+//
+// This object is not tied to the lifetime of the underlying process: the
+// process may be killed and this object may still around, and it will still
+// claim to be valid. The actual behavior in that case is OS dependent like so:
+//
+// Windows: The underlying ProcessHandle will be valid after the process dies
+// and can be used to gather some information about that process, but most
+// methods will obviously fail.
+//
+// POSIX: The underlying ProcessHandle is not guaranteed to remain valid after
+// the process dies, and it may be reused by the system, which means that it may
+// end up pointing to the wrong process.
+class BASE_EXPORT Process {
+ public:
+ // On Windows, this takes ownership of |handle|. On POSIX, this does not take
+ // ownership of |handle|.
+ explicit Process(ProcessHandle handle = kNullProcessHandle);
+
+ Process(Process&& other);
+
+ // The destructor does not terminate the process.
+ ~Process();
+
+ Process& operator=(Process&& other);
+
+ // Returns an object for the current process.
+ static Process Current();
+
+ // Returns a Process for the given |pid|.
+ static Process Open(ProcessId pid);
+
+ // Returns a Process for the given |pid|. On Windows the handle is opened
+ // with more access rights and must only be used by trusted code (can read the
+ // address space and duplicate handles).
+ static Process OpenWithExtraPrivileges(ProcessId pid);
+
+#if defined(OS_WIN)
+ // Returns a Process for the given |pid|, using some |desired_access|.
+ // See ::OpenProcess documentation for valid |desired_access|.
+ static Process OpenWithAccess(ProcessId pid, DWORD desired_access);
+#endif
+
+ // Creates an object from a |handle| owned by someone else.
+ // Don't use this for new code. It is only intended to ease the migration to
+ // a strict ownership model.
+ // TODO(rvargas) crbug.com/417532: Remove this code.
+ static Process DeprecatedGetProcessFromHandle(ProcessHandle handle);
+
+ // Returns true if processes can be backgrounded.
+ static bool CanBackgroundProcesses();
+
+ // Terminates the current process immediately with |exit_code|.
+ [[noreturn]] static void TerminateCurrentProcessImmediately(int exit_code);
+
+ // Returns true if this objects represents a valid process.
+ bool IsValid() const;
+
+ // Returns a handle for this process. There is no guarantee about when that
+ // handle becomes invalid because this object retains ownership.
+ ProcessHandle Handle() const;
+
+ // Returns a second object that represents this process.
+ Process Duplicate() const;
+
+ // Get the PID for this process.
+ ProcessId Pid() const;
+
+#if !defined(OS_ANDROID)
+ // Get the creation time for this process. Since the Pid can be reused after a
+ // process dies, it is useful to use both the Pid and the creation time to
+ // uniquely identify a process.
+ //
+ // Not available on Android because /proc/stat/ cannot be accessed on O+.
+ // https://issuetracker.google.com/issues/37140047
+ Time CreationTime() const;
+#endif // !defined(OS_ANDROID)
+
+ // Returns true if this process is the current process.
+ bool is_current() const;
+
+ // Close the process handle. This will not terminate the process.
+ void Close();
+
+ // Returns true if this process is still running. This is only safe on Windows
+ // (and maybe Fuchsia?), because the ProcessHandle will keep the zombie
+ // process information available until itself has been released. But on Posix,
+ // the OS may reuse the ProcessId.
+#if defined(OS_WIN)
+ bool IsRunning() const {
+ return !WaitForExitWithTimeout(base::TimeDelta(), nullptr);
+ }
+#endif
+
+ // Terminates the process with extreme prejudice. The given |exit_code| will
+ // be the exit code of the process. If |wait| is true, this method will wait
+ // for up to one minute for the process to actually terminate.
+ // Returns true if the process terminates within the allowed time.
+ // NOTE: On POSIX |exit_code| is ignored.
+ bool Terminate(int exit_code, bool wait) const;
+
+ // Waits for the process to exit. Returns true on success.
+ // On POSIX, if the process has been signaled then |exit_code| is set to -1.
+ // On Linux this must be a child process, however on Mac and Windows it can be
+ // any process.
+ // NOTE: |exit_code| is optional, nullptr can be passed if the exit code is
+ // not required.
+ bool WaitForExit(int* exit_code) const;
+
+ // Same as WaitForExit() but only waits for up to |timeout|.
+ // NOTE: |exit_code| is optional, nullptr can be passed if the exit code
+ // is not required.
+ bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const;
+
+ // Indicates that the process has exited with the specified |exit_code|.
+ // This should be called if process exit is observed outside of this class.
+ // (i.e. Not because Terminate or WaitForExit, above, was called.)
+ // Note that nothing prevents this being called multiple times for a dead
+ // process though that should be avoided.
+ void Exited(int exit_code) const;
+
+#if defined(OS_MACOSX)
+ // The Mac needs a Mach port in order to manipulate a process's priority,
+ // and there's no good way to get that from base given the pid. These Mac
+ // variants of the IsProcessBackgrounded and SetProcessBackgrounded API take
+ // a port provider for this reason. See crbug.com/460102
+ //
+ // A process is backgrounded when its task priority is
+ // |TASK_BACKGROUND_APPLICATION|.
+ //
+ // Returns true if the port_provider can locate a task port for the process
+ // and it is backgrounded. If port_provider is null, returns false.
+ bool IsProcessBackgrounded(PortProvider* port_provider) const;
+
+ // Set the process as backgrounded. If value is
+ // true, the priority of the associated task will be set to
+ // TASK_BACKGROUND_APPLICATION. If value is false, the
+ // priority of the process will be set to TASK_FOREGROUND_APPLICATION.
+ //
+ // Returns true if the priority was changed, false otherwise. If
+ // |port_provider| is null, this is a no-op and it returns false.
+ bool SetProcessBackgrounded(PortProvider* port_provider, bool value);
+#else
+ // A process is backgrounded when it's priority is lower than normal.
+ // Return true if this process is backgrounded, false otherwise.
+ bool IsProcessBackgrounded() const;
+
+ // Set a process as backgrounded. If value is true, the priority of the
+ // process will be lowered. If value is false, the priority of the process
+ // will be made "normal" - equivalent to default process priority.
+ // Returns true if the priority was changed, false otherwise.
+ bool SetProcessBackgrounded(bool value);
+#endif // defined(OS_MACOSX)
+ // Returns an integer representing the priority of a process. The meaning
+ // of this value is OS dependent.
+ int GetPriority() const;
+
+#if defined(OS_CHROMEOS)
+ // Get the PID in its PID namespace.
+ // If the process is not in a PID namespace or /proc/<pid>/status does not
+ // report NSpid, kNullProcessId is returned.
+ ProcessId GetPidInNamespace() const;
+#endif
+
+ private:
+#if defined(OS_WIN)
+ win::ScopedHandle process_;
+#elif defined(OS_FUCHSIA)
+ zx::process process_;
+#else
+ ProcessHandle process_;
+#endif
+
+#if defined(OS_WIN) || defined(OS_FUCHSIA)
+ bool is_current_process_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(Process);
+};
+
+#if defined(OS_CHROMEOS)
+// Exposed for testing.
+// Given the contents of the /proc/<pid>/cgroup file, determine whether the
+// process is backgrounded or not.
+BASE_EXPORT bool IsProcessBackgroundedCGroup(
+ const StringPiece& cgroup_contents);
+#endif // defined(OS_CHROMEOS)
+
+} // namespace base
+
+#endif // BASE_PROCESS_PROCESS_H_
diff --git a/security/sandbox/chromium/base/process/process_handle.h b/security/sandbox/chromium/base/process/process_handle.h
new file mode 100644
index 0000000000..94f7006119
--- /dev/null
+++ b/security/sandbox/chromium/base/process/process_handle.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_PROCESS_HANDLE_H_
+#define BASE_PROCESS_PROCESS_HANDLE_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_types.h"
+#endif
+
+#if defined(OS_FUCHSIA)
+#include <zircon/types.h>
+#endif
+
+namespace base {
+
+// ProcessHandle is a platform specific type which represents the underlying OS
+// handle to a process.
+// ProcessId is a number which identifies the process in the OS.
+#if defined(OS_WIN)
+typedef HANDLE ProcessHandle;
+typedef DWORD ProcessId;
+typedef HANDLE UserTokenHandle;
+const ProcessHandle kNullProcessHandle = NULL;
+const ProcessId kNullProcessId = 0;
+#elif defined(OS_FUCHSIA)
+typedef zx_handle_t ProcessHandle;
+typedef zx_koid_t ProcessId;
+const ProcessHandle kNullProcessHandle = ZX_HANDLE_INVALID;
+const ProcessId kNullProcessId = ZX_KOID_INVALID;
+#elif defined(OS_POSIX)
+// On POSIX, our ProcessHandle will just be the PID.
+typedef pid_t ProcessHandle;
+typedef pid_t ProcessId;
+const ProcessHandle kNullProcessHandle = 0;
+const ProcessId kNullProcessId = 0;
+#endif // defined(OS_WIN)
+
+// To print ProcessIds portably use CrPRIdPid (based on PRIuS and friends from
+// C99 and format_macros.h) like this:
+// base::StringPrintf("PID is %" CrPRIdPid ".\n", pid);
+#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#define CrPRIdPid "ld"
+#else
+#define CrPRIdPid "d"
+#endif
+
+class UniqueProcId {
+ public:
+ explicit UniqueProcId(ProcessId value) : value_(value) {}
+ UniqueProcId(const UniqueProcId& other) = default;
+ UniqueProcId& operator=(const UniqueProcId& other) = default;
+
+ // Returns the process PID. WARNING: On some platforms, the pid may not be
+ // valid within the current process sandbox.
+ ProcessId GetUnsafeValue() const { return value_; }
+
+ bool operator==(const UniqueProcId& other) const {
+ return value_ == other.value_;
+ }
+
+ bool operator!=(const UniqueProcId& other) const {
+ return value_ != other.value_;
+ }
+
+ bool operator<(const UniqueProcId& other) const {
+ return value_ < other.value_;
+ }
+
+ bool operator<=(const UniqueProcId& other) const {
+ return value_ <= other.value_;
+ }
+
+ bool operator>(const UniqueProcId& other) const {
+ return value_ > other.value_;
+ }
+
+ bool operator>=(const UniqueProcId& other) const {
+ return value_ >= other.value_;
+ }
+
+ private:
+ ProcessId value_;
+};
+
+std::ostream& operator<<(std::ostream& os, const UniqueProcId& obj);
+
+// Returns the id of the current process.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes (use GetUniqueIdForProcess if uniqueness is required).
+BASE_EXPORT ProcessId GetCurrentProcId();
+
+// Returns a unique ID for the current process. The ID will be unique across all
+// currently running processes within the chrome session, but IDs of terminated
+// processes may be reused.
+BASE_EXPORT UniqueProcId GetUniqueIdForProcess();
+
+#if defined(OS_LINUX)
+// When a process is started in a different PID namespace from the browser
+// process, this function must be called with the process's PID in the browser's
+// PID namespace in order to initialize its unique ID. Not thread safe.
+// WARNING: To avoid inconsistent results from GetUniqueIdForProcess, this
+// should only be called very early after process startup - ideally as soon
+// after process creation as possible.
+BASE_EXPORT void InitUniqueIdForProcessInPidNamespace(
+ ProcessId pid_outside_of_namespace);
+#endif
+
+// Returns the ProcessHandle of the current process.
+BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
+
+// Returns the process ID for the specified process. This is functionally the
+// same as Windows' GetProcessId(), but works on versions of Windows before Win
+// XP SP1 as well.
+// DEPRECATED. New code should be using Process::Pid() instead.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes.
+BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
+
+#if !defined(OS_FUCHSIA)
+// Returns the ID for the parent of the given process. Not available on Fuchsia.
+// Returning a negative value indicates an error, such as if the |process| does
+// not exist. Returns 0 when |process| has no parent process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+#endif // !defined(OS_FUCHSIA)
+
+#if defined(OS_POSIX)
+// Returns the path to the executable of the given process.
+BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
+#endif
+
+} // namespace base
+
+#endif // BASE_PROCESS_PROCESS_HANDLE_H_
diff --git a/security/sandbox/chromium/base/process/process_handle_win.cc b/security/sandbox/chromium/base/process/process_handle_win.cc
new file mode 100644
index 0000000000..ccc759039d
--- /dev/null
+++ b/security/sandbox/chromium/base/process/process_handle_win.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <windows.h>
+#include <tlhelp32.h>
+
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+ProcessId GetCurrentProcId() {
+ return ::GetCurrentProcessId();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+ return ::GetCurrentProcess();
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+ if (process == base::kNullProcessHandle)
+ return 0;
+ // This returns 0 if we have insufficient rights to query the process handle.
+ // Invalid handles or non-process handles will cause a hard failure.
+ ProcessId result = GetProcessId(process);
+ CHECK(result != 0 || GetLastError() != ERROR_INVALID_HANDLE)
+ << "process handle = " << process;
+ return result;
+}
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+ ProcessId child_pid = GetProcId(process);
+ PROCESSENTRY32 process_entry;
+ process_entry.dwSize = sizeof(PROCESSENTRY32);
+
+ win::ScopedHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+ if (snapshot.IsValid() && Process32First(snapshot.Get(), &process_entry)) {
+ do {
+ if (process_entry.th32ProcessID == child_pid)
+ return process_entry.th32ParentProcessID;
+ } while (Process32Next(snapshot.Get(), &process_entry));
+ }
+
+ // TODO(zijiehe): To match other platforms, -1 (UINT32_MAX) should be returned
+ // if |child_id| cannot be found in the |snapshot|.
+ return 0u;
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/rand_util.h b/security/sandbox/chromium/base/rand_util.h
new file mode 100644
index 0000000000..45e4283223
--- /dev/null
+++ b/security/sandbox/chromium/base/rand_util.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_RAND_UTIL_H_
+#define BASE_RAND_UTIL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Returns a random number in range [0, UINT64_MAX]. Thread-safe.
+BASE_EXPORT uint64_t RandUint64();
+
+// Returns a random number between min and max (inclusive). Thread-safe.
+BASE_EXPORT int RandInt(int min, int max);
+
+// Returns a random number in range [0, range). Thread-safe.
+BASE_EXPORT uint64_t RandGenerator(uint64_t range);
+
+// Returns a random double in range [0, 1). Thread-safe.
+BASE_EXPORT double RandDouble();
+
+// Given input |bits|, convert with maximum precision to a double in
+// the range [0, 1). Thread-safe.
+BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64_t bits);
+
+// Fills |output_length| bytes of |output| with random data. Thread-safe.
+//
+// Although implementations are required to use a cryptographically secure
+// random number source, code outside of base/ that relies on this should use
+// crypto::RandBytes instead to ensure the requirement is easily discoverable.
+BASE_EXPORT void RandBytes(void* output, size_t output_length);
+
+// Fills a string of length |length| with random data and returns it.
+// |length| should be nonzero. Thread-safe.
+//
+// Note that this is a variation of |RandBytes| with a different return type.
+// The returned string is likely not ASCII/UTF-8. Use with care.
+//
+// Although implementations are required to use a cryptographically secure
+// random number source, code outside of base/ that relies on this should use
+// crypto::RandBytes instead to ensure the requirement is easily discoverable.
+BASE_EXPORT std::string RandBytesAsString(size_t length);
+
+// An STL UniformRandomBitGenerator backed by RandUint64.
+// TODO(tzik): Consider replacing this with a faster implementation.
+class RandomBitGenerator {
+ public:
+ using result_type = uint64_t;
+ static constexpr result_type min() { return 0; }
+ static constexpr result_type max() { return UINT64_MAX; }
+ result_type operator()() const { return RandUint64(); }
+
+ RandomBitGenerator() = default;
+ ~RandomBitGenerator() = default;
+};
+
+// Shuffles [first, last) randomly. Thread-safe.
+template <typename Itr>
+void RandomShuffle(Itr first, Itr last) {
+ std::shuffle(first, last, RandomBitGenerator());
+}
+
+#if defined(OS_POSIX)
+BASE_EXPORT int GetUrandomFD();
+#endif
+
+} // namespace base
+
+#endif // BASE_RAND_UTIL_H_
diff --git a/security/sandbox/chromium/base/rand_util_win.cc b/security/sandbox/chromium/base/rand_util_win.cc
new file mode 100644
index 0000000000..193a3f63a3
--- /dev/null
+++ b/security/sandbox/chromium/base/rand_util_win.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <windows.h>
+#include <stddef.h>
+#include <stdint.h>
+
+// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the
+// "Community Additions" comment on MSDN here:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
+#define SystemFunction036 NTAPI SystemFunction036
+#include <ntsecapi.h>
+#undef SystemFunction036
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+
+namespace base {
+
+void RandBytes(void* output, size_t output_length) {
+ char* output_ptr = static_cast<char*>(output);
+ while (output_length > 0) {
+ const ULONG output_bytes_this_pass = static_cast<ULONG>(std::min(
+ output_length, static_cast<size_t>(std::numeric_limits<ULONG>::max())));
+ const bool success =
+ RtlGenRandom(output_ptr, output_bytes_this_pass) != FALSE;
+ CHECK(success);
+ output_length -= output_bytes_this_pass;
+ output_ptr += output_bytes_this_pass;
+ }
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/scoped_clear_last_error.h b/security/sandbox/chromium/base/scoped_clear_last_error.h
new file mode 100644
index 0000000000..b19f0436ae
--- /dev/null
+++ b/security/sandbox/chromium/base/scoped_clear_last_error.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_CLEAR_LAST_ERROR_H_
+#define BASE_SCOPED_CLEAR_LAST_ERROR_H_
+
+#include <errno.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace internal {
+
+// ScopedClearLastError stores and resets the value of thread local error codes
+// (errno, GetLastError()), and restores them in the destructor. This is useful
+// to avoid side effects on these values in instrumentation functions that
+// interact with the OS.
+
+// Common implementation of ScopedClearLastError for all platforms. Use
+// ScopedClearLastError instead.
+class BASE_EXPORT ScopedClearLastErrorBase {
+ public:
+ ScopedClearLastErrorBase() : last_errno_(errno) { errno = 0; }
+ ~ScopedClearLastErrorBase() { errno = last_errno_; }
+
+ private:
+ const int last_errno_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedClearLastErrorBase);
+};
+
+#if defined(OS_WIN)
+
+// Windows specific implementation of ScopedClearLastError.
+class BASE_EXPORT ScopedClearLastError : public ScopedClearLastErrorBase {
+ public:
+ ScopedClearLastError();
+ ~ScopedClearLastError();
+
+ private:
+ unsigned int last_system_error_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedClearLastError);
+};
+
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+
+using ScopedClearLastError = ScopedClearLastErrorBase;
+
+#endif // defined(OS_WIN)
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_SCOPED_CLEAR_LAST_ERROR_H_
diff --git a/security/sandbox/chromium/base/scoped_clear_last_error_win.cc b/security/sandbox/chromium/base/scoped_clear_last_error_win.cc
new file mode 100644
index 0000000000..cdf996359e
--- /dev/null
+++ b/security/sandbox/chromium/base/scoped_clear_last_error_win.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_clear_last_error.h"
+
+#include <windows.h>
+
+namespace base {
+namespace internal {
+
+ScopedClearLastError::ScopedClearLastError()
+ : last_system_error_(::GetLastError()) {
+ ::SetLastError(0);
+}
+
+ScopedClearLastError::~ScopedClearLastError() {
+ ::SetLastError(last_system_error_);
+}
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/sequence_checker.h b/security/sandbox/chromium/base/sequence_checker.h
new file mode 100644
index 0000000000..60ffd75a4f
--- /dev/null
+++ b/security/sandbox/chromium/base/sequence_checker.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCE_CHECKER_H_
+#define BASE_SEQUENCE_CHECKER_H_
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/sequence_checker_impl.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+// SequenceChecker is a helper class used to help verify that some methods of a
+// class are called sequentially (for thread-safety). It supports thread safety
+// annotations (see base/thread_annotations.h).
+//
+// Use the macros below instead of the SequenceChecker directly so that the
+// unused member doesn't result in an extra byte (four when padded) per
+// instance in production.
+//
+// This class is much prefered to ThreadChecker for thread-safety checks.
+// ThreadChecker should only be used for classes that are truly thread-affine
+// (use thread-local-storage or a third-party API that does).
+//
+// Usage:
+// class MyClass {
+// public:
+// MyClass() {
+// // It's sometimes useful to detach on construction for objects that are
+// // constructed in one place and forever after used from another
+// // sequence.
+// DETACH_FROM_SEQUENCE(my_sequence_checker_);
+// }
+//
+// ~MyClass() {
+// // SequenceChecker doesn't automatically check it's destroyed on origin
+// // sequence for the same reason it's sometimes detached in the
+// // constructor. It's okay to destroy off sequence if the owner
+// // otherwise knows usage on the associated sequence is done. If you're
+// // not detaching in the constructor, you probably want to explicitly
+// // check in the destructor.
+// DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
+// }
+// void MyMethod() {
+// DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
+// ... (do stuff) ...
+// MyOtherMethod();
+// }
+//
+// void MyOtherMethod()
+// VALID_CONTEXT_REQUIRED(my_sequence_checker_) {
+// foo_ = 42;
+// }
+//
+// private:
+// // GUARDED_BY_CONTEXT() enforces that this member is only
+// // accessed from a scope that invokes DCHECK_CALLED_ON_VALID_SEQUENCE()
+// // or from a function annotated with VALID_CONTEXT_REQUIRED(). A
+// // DCHECK build will not compile if the member is accessed and these
+// // conditions are not met.
+// int foo_ GUARDED_BY_CONTEXT(my_sequence_checker_);
+//
+// SEQUENCE_CHECKER(my_sequence_checker_);
+// }
+
+#define SEQUENCE_CHECKER_INTERNAL_CONCAT2(a, b) a##b
+#define SEQUENCE_CHECKER_INTERNAL_CONCAT(a, b) \
+ SEQUENCE_CHECKER_INTERNAL_CONCAT2(a, b)
+#define SEQUENCE_CHECKER_INTERNAL_UID(prefix) \
+ SEQUENCE_CHECKER_INTERNAL_CONCAT(prefix, __LINE__)
+
+#if DCHECK_IS_ON()
+#define SEQUENCE_CHECKER(name) base::SequenceChecker name
+#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) \
+ base::ScopedValidateSequenceChecker SEQUENCE_CHECKER_INTERNAL_UID( \
+ scoped_validate_sequence_checker_)(name, ##__VA_ARGS__);
+#define DETACH_FROM_SEQUENCE(name) (name).DetachFromSequence()
+#else // DCHECK_IS_ON()
+#if __OBJC__ && defined(OS_IOS) && !HAS_FEATURE(objc_cxx_static_assert)
+// TODO(thakis): Remove this branch once Xcode's clang has clang r356148.
+#define SEQUENCE_CHECKER(name)
+#else
+#define SEQUENCE_CHECKER(name) static_assert(true, "")
+#endif
+#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) EAT_STREAM_PARAMETERS
+#define DETACH_FROM_SEQUENCE(name)
+#endif // DCHECK_IS_ON()
+
+namespace base {
+
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the SequenceChecker class (through the
+// above macros) to get the right version for your build configuration.
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE SequenceCheckerDoNothing {
+ public:
+ SequenceCheckerDoNothing() = default;
+
+ // Moving between matching sequences is allowed to help classes with
+ // SequenceCheckers that want a default move-construct/assign.
+ SequenceCheckerDoNothing(SequenceCheckerDoNothing&& other) = default;
+ SequenceCheckerDoNothing& operator=(SequenceCheckerDoNothing&& other) =
+ default;
+
+ bool CalledOnValidSequence() const WARN_UNUSED_RESULT { return true; }
+ void DetachFromSequence() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SequenceCheckerDoNothing);
+};
+
+#if DCHECK_IS_ON()
+class SequenceChecker : public SequenceCheckerImpl {
+};
+#else
+class SequenceChecker : public SequenceCheckerDoNothing {
+};
+#endif // DCHECK_IS_ON()
+
+class SCOPED_LOCKABLE ScopedValidateSequenceChecker {
+ public:
+ explicit ScopedValidateSequenceChecker(const SequenceChecker& checker)
+ EXCLUSIVE_LOCK_FUNCTION(checker) {
+ DCHECK(checker.CalledOnValidSequence());
+ }
+
+ explicit ScopedValidateSequenceChecker(const SequenceChecker& checker,
+ const StringPiece& msg)
+ EXCLUSIVE_LOCK_FUNCTION(checker) {
+ DCHECK(checker.CalledOnValidSequence()) << msg;
+ }
+
+ ~ScopedValidateSequenceChecker() UNLOCK_FUNCTION() {}
+
+ private:
+};
+
+} // namespace base
+
+#endif // BASE_SEQUENCE_CHECKER_H_
diff --git a/security/sandbox/chromium/base/sequence_checker_impl.h b/security/sandbox/chromium/base/sequence_checker_impl.h
new file mode 100644
index 0000000000..ea0fbb5bfa
--- /dev/null
+++ b/security/sandbox/chromium/base/sequence_checker_impl.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCE_CHECKER_IMPL_H_
+#define BASE_SEQUENCE_CHECKER_IMPL_H_
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+
+namespace base {
+
+// Real implementation of SequenceChecker for use in debug mode or for temporary
+// use in release mode (e.g. to CHECK on a threading issue seen only in the
+// wild).
+//
+// Note: You should almost always use the SequenceChecker class to get the right
+// version for your build configuration.
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE BASE_EXPORT SequenceCheckerImpl {
+ public:
+ SequenceCheckerImpl();
+ ~SequenceCheckerImpl();
+
+ // Allow move construct/assign. This must be called on |other|'s associated
+ // sequence and assignment can only be made into a SequenceCheckerImpl which
+ // is detached or already associated with the current sequence. This isn't
+ // thread-safe (|this| and |other| shouldn't be in use while this move is
+ // performed). If the assignment was legal, the resulting SequenceCheckerImpl
+ // will be bound to the current sequence and |other| will be detached.
+ SequenceCheckerImpl(SequenceCheckerImpl&& other);
+ SequenceCheckerImpl& operator=(SequenceCheckerImpl&& other);
+
+ // Returns true if called in sequence with previous calls to this method and
+ // the constructor.
+ bool CalledOnValidSequence() const WARN_UNUSED_RESULT;
+
+ // Unbinds the checker from the currently associated sequence. The checker
+ // will be re-bound on the next call to CalledOnValidSequence().
+ void DetachFromSequence();
+
+ private:
+ class Core;
+
+ // Calls straight to ThreadLocalStorage::HasBeenDestroyed(). Exposed purely
+ // for 'friend' to work.
+ static bool HasThreadLocalStorageBeenDestroyed();
+
+ mutable Lock lock_;
+ mutable std::unique_ptr<Core> core_ GUARDED_BY(lock_);
+
+ DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl);
+};
+
+} // namespace base
+
+#endif // BASE_SEQUENCE_CHECKER_IMPL_H_
diff --git a/security/sandbox/chromium/base/sequence_token.h b/security/sandbox/chromium/base/sequence_token.h
new file mode 100644
index 0000000000..6e7d191ae8
--- /dev/null
+++ b/security/sandbox/chromium/base/sequence_token.h
@@ -0,0 +1,115 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCE_TOKEN_H_
+#define BASE_SEQUENCE_TOKEN_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+
+// A token that identifies a series of sequenced tasks (i.e. tasks that run one
+// at a time in posting order).
+class BASE_EXPORT SequenceToken {
+ public:
+ // Instantiates an invalid SequenceToken.
+ SequenceToken() = default;
+
+ // Explicitly allow copy.
+ SequenceToken(const SequenceToken& other) = default;
+ SequenceToken& operator=(const SequenceToken& other) = default;
+
+ // An invalid SequenceToken is not equal to any other SequenceToken, including
+ // other invalid SequenceTokens.
+ bool operator==(const SequenceToken& other) const;
+ bool operator!=(const SequenceToken& other) const;
+
+ // Returns true if this is a valid SequenceToken.
+ bool IsValid() const;
+
+ // Returns the integer uniquely representing this SequenceToken. This method
+ // should only be used for tracing and debugging.
+ int ToInternalValue() const;
+
+ // Returns a valid SequenceToken which isn't equal to any previously returned
+ // SequenceToken.
+ static SequenceToken Create();
+
+ // Returns the SequenceToken associated with the task running on the current
+ // thread, as determined by the active ScopedSetSequenceTokenForCurrentThread
+ // if any.
+ static SequenceToken GetForCurrentThread();
+
+ private:
+ explicit SequenceToken(int token) : token_(token) {}
+
+ static constexpr int kInvalidSequenceToken = -1;
+ int token_ = kInvalidSequenceToken;
+};
+
+// A token that identifies a task.
+//
+// This is used by ThreadCheckerImpl to determine whether calls to
+// CalledOnValidThread() come from the same task and hence are deterministically
+// single-threaded (vs. calls coming from different sequenced or parallel tasks,
+// which may or may not run on the same thread).
+class BASE_EXPORT TaskToken {
+ public:
+ // Instantiates an invalid TaskToken.
+ TaskToken() = default;
+
+ // Explicitly allow copy.
+ TaskToken(const TaskToken& other) = default;
+ TaskToken& operator=(const TaskToken& other) = default;
+
+ // An invalid TaskToken is not equal to any other TaskToken, including
+ // other invalid TaskTokens.
+ bool operator==(const TaskToken& other) const;
+ bool operator!=(const TaskToken& other) const;
+
+ // Returns true if this is a valid TaskToken.
+ bool IsValid() const;
+
+ // In the scope of a ScopedSetSequenceTokenForCurrentThread, returns a valid
+ // TaskToken which isn't equal to any TaskToken returned in the scope of a
+ // different ScopedSetSequenceTokenForCurrentThread. Otherwise, returns an
+ // invalid TaskToken.
+ static TaskToken GetForCurrentThread();
+
+ private:
+ friend class ScopedSetSequenceTokenForCurrentThread;
+
+ explicit TaskToken(int token) : token_(token) {}
+
+ // Returns a valid TaskToken which isn't equal to any previously returned
+ // TaskToken. This is private as it only meant to be instantiated by
+ // ScopedSetSequenceTokenForCurrentThread.
+ static TaskToken Create();
+
+ static constexpr int kInvalidTaskToken = -1;
+ int token_ = kInvalidTaskToken;
+};
+
+// Instantiate this in the scope where a single task runs.
+class BASE_EXPORT ScopedSetSequenceTokenForCurrentThread {
+ public:
+ // Throughout the lifetime of the constructed object,
+ // SequenceToken::GetForCurrentThread() will return |sequence_token| and
+ // TaskToken::GetForCurrentThread() will return a TaskToken which is not equal
+ // to any TaskToken returned in the scope of another
+ // ScopedSetSequenceTokenForCurrentThread.
+ ScopedSetSequenceTokenForCurrentThread(const SequenceToken& sequence_token);
+ ~ScopedSetSequenceTokenForCurrentThread();
+
+ private:
+ const SequenceToken sequence_token_;
+ const TaskToken task_token_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSetSequenceTokenForCurrentThread);
+};
+
+} // namespace base
+
+#endif // BASE_SEQUENCE_TOKEN_H_
diff --git a/security/sandbox/chromium/base/sequenced_task_runner.h b/security/sandbox/chromium/base/sequenced_task_runner.h
new file mode 100644
index 0000000000..976f87ff2a
--- /dev/null
+++ b/security/sandbox/chromium/base/sequenced_task_runner.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCED_TASK_RUNNER_H_
+#define BASE_SEQUENCED_TASK_RUNNER_H_
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/task_runner.h"
+
+namespace base {
+
+// A SequencedTaskRunner is a subclass of TaskRunner that provides
+// additional guarantees on the order that tasks are started, as well
+// as guarantees on when tasks are in sequence, i.e. one task finishes
+// before the other one starts.
+//
+// Summary
+// -------
+// Non-nested tasks with the same delay will run one by one in FIFO
+// order.
+//
+// Detailed guarantees
+// -------------------
+//
+// SequencedTaskRunner also adds additional methods for posting
+// non-nestable tasks. In general, an implementation of TaskRunner
+// may expose task-running methods which are themselves callable from
+// within tasks. A non-nestable task is one that is guaranteed to not
+// be run from within an already-running task. Conversely, a nestable
+// task (the default) is a task that can be run from within an
+// already-running task.
+//
+// The guarantees of SequencedTaskRunner are as follows:
+//
+// - Given two tasks T2 and T1, T2 will start after T1 starts if:
+//
+// * T2 is posted after T1; and
+// * T2 has equal or higher delay than T1; and
+// * T2 is non-nestable or T1 is nestable.
+//
+// - If T2 will start after T1 starts by the above guarantee, then
+// T2 will start after T1 finishes and is destroyed if:
+//
+// * T2 is non-nestable, or
+// * T1 doesn't call any task-running methods.
+//
+// - If T2 will start after T1 finishes by the above guarantee, then
+// all memory changes in T1 and T1's destruction will be visible
+// to T2.
+//
+// - If T2 runs nested within T1 via a call to the task-running
+// method M, then all memory changes in T1 up to the call to M
+// will be visible to T2, and all memory changes in T2 will be
+// visible to T1 from the return from M.
+//
+// Note that SequencedTaskRunner does not guarantee that tasks are run
+// on a single dedicated thread, although the above guarantees provide
+// most (but not all) of the same guarantees. If you do need to
+// guarantee that tasks are run on a single dedicated thread, see
+// SingleThreadTaskRunner (in single_thread_task_runner.h).
+//
+// Some corollaries to the above guarantees, assuming the tasks in
+// question don't call any task-running methods:
+//
+// - Tasks posted via PostTask are run in FIFO order.
+//
+// - Tasks posted via PostNonNestableTask are run in FIFO order.
+//
+// - Tasks posted with the same delay and the same nestable state
+// are run in FIFO order.
+//
+// - A list of tasks with the same nestable state posted in order of
+// non-decreasing delay is run in FIFO order.
+//
+// - A list of tasks posted in order of non-decreasing delay with at
+// most a single change in nestable state from nestable to
+// non-nestable is run in FIFO order. (This is equivalent to the
+// statement of the first guarantee above.)
+//
+// Some theoretical implementations of SequencedTaskRunner:
+//
+// - A SequencedTaskRunner that wraps a regular TaskRunner but makes
+// sure that only one task at a time is posted to the TaskRunner,
+// with appropriate memory barriers in between tasks.
+//
+// - A SequencedTaskRunner that, for each task, spawns a joinable
+// thread to run that task and immediately quit, and then
+// immediately joins that thread.
+//
+// - A SequencedTaskRunner that stores the list of posted tasks and
+// has a method Run() that runs each runnable task in FIFO order
+// that can be called from any thread, but only if another
+// (non-nested) Run() call isn't already happening.
+class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
+ public:
+ // The two PostNonNestable*Task methods below are like their
+ // nestable equivalents in TaskRunner, but they guarantee that the
+ // posted task will not run nested within an already-running task.
+ //
+ // A simple corollary is that posting a task as non-nestable can
+ // only delay when the task gets run. That is, posting a task as
+ // non-nestable may not affect when the task gets run, or it could
+ // make it run later than it normally would, but it won't make it
+ // run earlier than it normally would.
+
+ // TODO(akalin): Get rid of the boolean return value for the methods
+ // below.
+
+ bool PostNonNestableTask(const Location& from_here, OnceClosure task);
+
+ virtual bool PostNonNestableDelayedTask(const Location& from_here,
+ OnceClosure task,
+ base::TimeDelta delay) = 0;
+
+ // Submits a non-nestable task to delete the given object. Returns
+ // true if the object may be deleted at some point in the future,
+ // and false if the object definitely will not be deleted.
+ template <class T>
+ bool DeleteSoon(const Location& from_here, const T* object) {
+ return DeleteOrReleaseSoonInternal(from_here, &DeleteHelper<T>::DoDelete,
+ object);
+ }
+
+ template <class T>
+ bool DeleteSoon(const Location& from_here, std::unique_ptr<T> object) {
+ return DeleteSoon(from_here, object.release());
+ }
+
+ // Submits a non-nestable task to release the given object.
+ //
+ // ReleaseSoon makes sure that the object it the scoped_refptr points to gets
+ // properly released on the correct thread.
+ // We apply ReleaseSoon to the rvalue as the side-effects can be unclear to
+ // the caller if an lvalue is used. That being so, the scoped_refptr should
+ // always be std::move'd.
+ // Example use:
+ //
+ // scoped_refptr<T> foo_scoped_refptr;
+ // ...
+ // task_runner->ReleaseSoon(std::move(foo_scoped_refptr));
+ template <class T>
+ void ReleaseSoon(const Location& from_here, scoped_refptr<T>&& object) {
+ if (!object)
+ return;
+
+ DeleteOrReleaseSoonInternal(from_here, &ReleaseHelper<T>::DoRelease,
+ object.release());
+ }
+
+ // Returns true iff tasks posted to this TaskRunner are sequenced
+ // with this call.
+ //
+ // In particular:
+ // - Returns true if this is a SequencedTaskRunner to which the
+ // current task was posted.
+ // - Returns true if this is a SequencedTaskRunner bound to the
+ // same sequence as the SequencedTaskRunner to which the current
+ // task was posted.
+ // - Returns true if this is a SingleThreadTaskRunner bound to
+ // the current thread.
+ virtual bool RunsTasksInCurrentSequence() const = 0;
+
+ protected:
+ ~SequencedTaskRunner() override = default;
+
+ private:
+ bool DeleteOrReleaseSoonInternal(const Location& from_here,
+ void (*deleter)(const void*),
+ const void* object);
+};
+
+// Sample usage with std::unique_ptr :
+// std::unique_ptr<Foo, base::OnTaskRunnerDeleter> ptr(
+// new Foo, base::OnTaskRunnerDeleter(my_task_runner));
+//
+// For RefCounted see base::RefCountedDeleteOnSequence.
+struct BASE_EXPORT OnTaskRunnerDeleter {
+ explicit OnTaskRunnerDeleter(scoped_refptr<SequencedTaskRunner> task_runner);
+ ~OnTaskRunnerDeleter();
+
+ OnTaskRunnerDeleter(OnTaskRunnerDeleter&&);
+ OnTaskRunnerDeleter& operator=(OnTaskRunnerDeleter&&);
+
+ // For compatibility with std:: deleters.
+ template <typename T>
+ void operator()(const T* ptr) {
+ if (ptr)
+ task_runner_->DeleteSoon(FROM_HERE, ptr);
+ }
+
+ scoped_refptr<SequencedTaskRunner> task_runner_;
+};
+
+} // namespace base
+
+#endif // BASE_SEQUENCED_TASK_RUNNER_H_
diff --git a/security/sandbox/chromium/base/sequenced_task_runner_helpers.h b/security/sandbox/chromium/base/sequenced_task_runner_helpers.h
new file mode 100644
index 0000000000..18ec0e26f5
--- /dev/null
+++ b/security/sandbox/chromium/base/sequenced_task_runner_helpers.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
+#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
+
+namespace base {
+
+class SequencedTaskRunner;
+
+// Template helpers which use function indirection to erase T from the
+// function signature while still remembering it so we can call the
+// correct destructor/release function.
+//
+// We use this trick so we don't need to include bind.h in a header
+// file like sequenced_task_runner.h. We also wrap the helpers in a
+// templated class to make it easier for users of DeleteSoon to
+// declare the helper as a friend.
+template <class T>
+class DeleteHelper {
+ private:
+ static void DoDelete(const void* object) {
+ delete static_cast<const T*>(object);
+ }
+
+ friend class SequencedTaskRunner;
+};
+
+template <class T>
+class ReleaseHelper {
+ private:
+ static void DoRelease(const void* object) {
+ static_cast<const T*>(object)->Release();
+ }
+
+ friend class SequencedTaskRunner;
+};
+
+} // namespace base
+
+#endif // BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
diff --git a/security/sandbox/chromium/base/single_thread_task_runner.h b/security/sandbox/chromium/base/single_thread_task_runner.h
new file mode 100644
index 0000000000..4d6938ed6c
--- /dev/null
+++ b/security/sandbox/chromium/base/single_thread_task_runner.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SINGLE_THREAD_TASK_RUNNER_H_
+#define BASE_SINGLE_THREAD_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/sequenced_task_runner.h"
+
+namespace base {
+
+// A SingleThreadTaskRunner is a SequencedTaskRunner with one more
+// guarantee; namely, that all tasks are run on a single dedicated
+// thread. Most use cases require only a SequencedTaskRunner, unless
+// there is a specific need to run tasks on only a single thread.
+//
+// SingleThreadTaskRunner implementations might:
+// - Post tasks to an existing thread's MessageLoop (see
+// MessageLoop::task_runner()).
+// - Create their own worker thread and MessageLoop to post tasks to.
+// - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
+// be processed. This allows TaskRunner-oriented code run on threads
+// running other kinds of message loop, e.g. Jingle threads.
+class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner {
+ public:
+ // A more explicit alias to RunsTasksInCurrentSequence().
+ bool BelongsToCurrentThread() const { return RunsTasksInCurrentSequence(); }
+
+ protected:
+ ~SingleThreadTaskRunner() override = default;
+};
+
+} // namespace base
+
+#endif // BASE_SINGLE_THREAD_TASK_RUNNER_H_
diff --git a/security/sandbox/chromium/base/stl_util.h b/security/sandbox/chromium/base/stl_util.h
new file mode 100644
index 0000000000..83d86ad90d
--- /dev/null
+++ b/security/sandbox/chromium/base/stl_util.h
@@ -0,0 +1,681 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Derived from google3/util/gtl/stl_util.h
+
+#ifndef BASE_STL_UTIL_H_
+#define BASE_STL_UTIL_H_
+
+#include <algorithm>
+#include <deque>
+#include <forward_list>
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/template_util.h"
+
+namespace base {
+
+namespace internal {
+
+// Calls erase on iterators of matching elements.
+template <typename Container, typename Predicate>
+void IterateAndEraseIf(Container& container, Predicate pred) {
+ for (auto it = container.begin(); it != container.end();) {
+ if (pred(*it))
+ it = container.erase(it);
+ else
+ ++it;
+ }
+}
+
+template <typename Iter>
+constexpr bool IsRandomAccessIter =
+ std::is_same<typename std::iterator_traits<Iter>::iterator_category,
+ std::random_access_iterator_tag>::value;
+
+// Utility type traits used for specializing base::Contains() below.
+template <typename Container, typename Element, typename = void>
+struct HasFindWithNpos : std::false_type {};
+
+template <typename Container, typename Element>
+struct HasFindWithNpos<
+ Container,
+ Element,
+ void_t<decltype(std::declval<const Container&>().find(
+ std::declval<const Element&>()) != Container::npos)>>
+ : std::true_type {};
+
+template <typename Container, typename Element, typename = void>
+struct HasFindWithEnd : std::false_type {};
+
+template <typename Container, typename Element>
+struct HasFindWithEnd<Container,
+ Element,
+ void_t<decltype(std::declval<const Container&>().find(
+ std::declval<const Element&>()) !=
+ std::declval<const Container&>().end())>>
+ : std::true_type {};
+
+template <typename Container, typename Element, typename = void>
+struct HasContains : std::false_type {};
+
+template <typename Container, typename Element>
+struct HasContains<Container,
+ Element,
+ void_t<decltype(std::declval<const Container&>().contains(
+ std::declval<const Element&>()))>> : std::true_type {};
+
+} // namespace internal
+
+// C++14 implementation of C++17's std::size():
+// http://en.cppreference.com/w/cpp/iterator/size
+template <typename Container>
+constexpr auto size(const Container& c) -> decltype(c.size()) {
+ return c.size();
+}
+
+template <typename T, size_t N>
+constexpr size_t size(const T (&array)[N]) noexcept {
+ return N;
+}
+
+// C++14 implementation of C++17's std::empty():
+// http://en.cppreference.com/w/cpp/iterator/empty
+template <typename Container>
+constexpr auto empty(const Container& c) -> decltype(c.empty()) {
+ return c.empty();
+}
+
+template <typename T, size_t N>
+constexpr bool empty(const T (&array)[N]) noexcept {
+ return false;
+}
+
+template <typename T>
+constexpr bool empty(std::initializer_list<T> il) noexcept {
+ return il.size() == 0;
+}
+
+// C++14 implementation of C++17's std::data():
+// http://en.cppreference.com/w/cpp/iterator/data
+template <typename Container>
+constexpr auto data(Container& c) -> decltype(c.data()) {
+ return c.data();
+}
+
+// std::basic_string::data() had no mutable overload prior to C++17 [1].
+// Hence this overload is provided.
+// Note: str[0] is safe even for empty strings, as they are guaranteed to be
+// null-terminated [2].
+//
+// [1] http://en.cppreference.com/w/cpp/string/basic_string/data
+// [2] http://en.cppreference.com/w/cpp/string/basic_string/operator_at
+template <typename CharT, typename Traits, typename Allocator>
+CharT* data(std::basic_string<CharT, Traits, Allocator>& str) {
+ return std::addressof(str[0]);
+}
+
+template <typename Container>
+constexpr auto data(const Container& c) -> decltype(c.data()) {
+ return c.data();
+}
+
+template <typename T, size_t N>
+constexpr T* data(T (&array)[N]) noexcept {
+ return array;
+}
+
+template <typename T>
+constexpr const T* data(std::initializer_list<T> il) noexcept {
+ return il.begin();
+}
+
+// std::array::data() was not constexpr prior to C++17 [1].
+// Hence these overloads are provided.
+//
+// [1] https://en.cppreference.com/w/cpp/container/array/data
+template <typename T, size_t N>
+constexpr T* data(std::array<T, N>& array) noexcept {
+ return !array.empty() ? &array[0] : nullptr;
+}
+
+template <typename T, size_t N>
+constexpr const T* data(const std::array<T, N>& array) noexcept {
+ return !array.empty() ? &array[0] : nullptr;
+}
+
+// C++14 implementation of C++17's std::as_const():
+// https://en.cppreference.com/w/cpp/utility/as_const
+template <typename T>
+constexpr std::add_const_t<T>& as_const(T& t) noexcept {
+ return t;
+}
+
+template <typename T>
+void as_const(const T&& t) = delete;
+
+// Returns a const reference to the underlying container of a container adapter.
+// Works for std::priority_queue, std::queue, and std::stack.
+template <class A>
+const typename A::container_type& GetUnderlyingContainer(const A& adapter) {
+ struct ExposedAdapter : A {
+ using A::c;
+ };
+ return adapter.*&ExposedAdapter::c;
+}
+
+// Clears internal memory of an STL object.
+// STL clear()/reserve(0) does not always free internal memory allocated
+// This function uses swap/destructor to ensure the internal memory is freed.
+template<class T>
+void STLClearObject(T* obj) {
+ T tmp;
+ tmp.swap(*obj);
+ // Sometimes "T tmp" allocates objects with memory (arena implementation?).
+ // Hence using additional reserve(0) even if it doesn't always work.
+ obj->reserve(0);
+}
+
+// Counts the number of instances of val in a container.
+template <typename Container, typename T>
+typename std::iterator_traits<
+ typename Container::const_iterator>::difference_type
+STLCount(const Container& container, const T& val) {
+ return std::count(container.begin(), container.end(), val);
+}
+
+// General purpose implementation to check if |container| contains |value|.
+template <typename Container,
+ typename Value,
+ std::enable_if_t<
+ !internal::HasFindWithNpos<Container, Value>::value &&
+ !internal::HasFindWithEnd<Container, Value>::value &&
+ !internal::HasContains<Container, Value>::value>* = nullptr>
+bool Contains(const Container& container, const Value& value) {
+ using std::begin;
+ using std::end;
+ return std::find(begin(container), end(container), value) != end(container);
+}
+
+// Specialized Contains() implementation for when |container| has a find()
+// member function and a static npos member, but no contains() member function.
+template <typename Container,
+ typename Value,
+ std::enable_if_t<internal::HasFindWithNpos<Container, Value>::value &&
+ !internal::HasContains<Container, Value>::value>* =
+ nullptr>
+bool Contains(const Container& container, const Value& value) {
+ return container.find(value) != Container::npos;
+}
+
+// Specialized Contains() implementation for when |container| has a find()
+// and end() member function, but no contains() member function.
+template <typename Container,
+ typename Value,
+ std::enable_if_t<internal::HasFindWithEnd<Container, Value>::value &&
+ !internal::HasContains<Container, Value>::value>* =
+ nullptr>
+bool Contains(const Container& container, const Value& value) {
+ return container.find(value) != container.end();
+}
+
+// Specialized Contains() implementation for when |container| has a contains()
+// member function.
+template <
+ typename Container,
+ typename Value,
+ std::enable_if_t<internal::HasContains<Container, Value>::value>* = nullptr>
+bool Contains(const Container& container, const Value& value) {
+ return container.contains(value);
+}
+
+// O(1) implementation of const casting an iterator for any sequence,
+// associative or unordered associative container in the STL.
+//
+// Reference: https://stackoverflow.com/a/10669041
+template <typename Container,
+ typename ConstIter,
+ std::enable_if_t<!internal::IsRandomAccessIter<ConstIter>>* = nullptr>
+constexpr auto ConstCastIterator(Container& c, ConstIter it) {
+ return c.erase(it, it);
+}
+
+// Explicit overload for std::forward_list where erase() is named erase_after().
+template <typename T, typename Allocator>
+constexpr auto ConstCastIterator(
+ std::forward_list<T, Allocator>& c,
+ typename std::forward_list<T, Allocator>::const_iterator it) {
+// The erase_after(it, it) trick used below does not work for libstdc++ [1],
+// thus we need a different way.
+// TODO(crbug.com/972541): Remove this workaround once libstdc++ is fixed on all
+// platforms.
+//
+// [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90857
+#if defined(__GLIBCXX__)
+ return c.insert_after(it, {});
+#else
+ return c.erase_after(it, it);
+#endif
+}
+
+// Specialized O(1) const casting for random access iterators. This is
+// necessary, because erase() is either not available (e.g. array-like
+// containers), or has O(n) complexity (e.g. std::deque or std::vector).
+template <typename Container,
+ typename ConstIter,
+ std::enable_if_t<internal::IsRandomAccessIter<ConstIter>>* = nullptr>
+constexpr auto ConstCastIterator(Container& c, ConstIter it) {
+ using std::begin;
+ using std::cbegin;
+ return begin(c) + (it - cbegin(c));
+}
+
+namespace internal {
+
+template <typename Map, typename Key, typename Value>
+std::pair<typename Map::iterator, bool> InsertOrAssignImpl(Map& map,
+ Key&& key,
+ Value&& value) {
+ auto lower = map.lower_bound(key);
+ if (lower != map.end() && !map.key_comp()(key, lower->first)) {
+ // key already exists, perform assignment.
+ lower->second = std::forward<Value>(value);
+ return {lower, false};
+ }
+
+ // key did not yet exist, insert it.
+ return {map.emplace_hint(lower, std::forward<Key>(key),
+ std::forward<Value>(value)),
+ true};
+}
+
+template <typename Map, typename Key, typename Value>
+typename Map::iterator InsertOrAssignImpl(Map& map,
+ typename Map::const_iterator hint,
+ Key&& key,
+ Value&& value) {
+ auto&& key_comp = map.key_comp();
+ if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
+ if (hint == map.end() || key_comp(key, hint->first)) {
+ // *(hint - 1) < key < *hint => key did not exist and hint is correct.
+ return map.emplace_hint(hint, std::forward<Key>(key),
+ std::forward<Value>(value));
+ }
+
+ if (!key_comp(hint->first, key)) {
+ // key == *hint => key already exists and hint is correct.
+ auto mutable_hint = ConstCastIterator(map, hint);
+ mutable_hint->second = std::forward<Value>(value);
+ return mutable_hint;
+ }
+ }
+
+ // hint was not helpful, dispatch to hintless version.
+ return InsertOrAssignImpl(map, std::forward<Key>(key),
+ std::forward<Value>(value))
+ .first;
+}
+
+template <typename Map, typename Key, typename... Args>
+std::pair<typename Map::iterator, bool> TryEmplaceImpl(Map& map,
+ Key&& key,
+ Args&&... args) {
+ auto lower = map.lower_bound(key);
+ if (lower != map.end() && !map.key_comp()(key, lower->first)) {
+ // key already exists, do nothing.
+ return {lower, false};
+ }
+
+ // key did not yet exist, insert it.
+ return {map.emplace_hint(lower, std::piecewise_construct,
+ std::forward_as_tuple(std::forward<Key>(key)),
+ std::forward_as_tuple(std::forward<Args>(args)...)),
+ true};
+}
+
+template <typename Map, typename Key, typename... Args>
+typename Map::iterator TryEmplaceImpl(Map& map,
+ typename Map::const_iterator hint,
+ Key&& key,
+ Args&&... args) {
+ auto&& key_comp = map.key_comp();
+ if ((hint == map.begin() || key_comp(std::prev(hint)->first, key))) {
+ if (hint == map.end() || key_comp(key, hint->first)) {
+ // *(hint - 1) < key < *hint => key did not exist and hint is correct.
+ return map.emplace_hint(
+ hint, std::piecewise_construct,
+ std::forward_as_tuple(std::forward<Key>(key)),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ }
+
+ if (!key_comp(hint->first, key)) {
+ // key == *hint => no-op, return correct hint.
+ return ConstCastIterator(map, hint);
+ }
+ }
+
+ // hint was not helpful, dispatch to hintless version.
+ return TryEmplaceImpl(map, std::forward<Key>(key),
+ std::forward<Args>(args)...)
+ .first;
+}
+
+} // namespace internal
+
+// Implementation of C++17's std::map::insert_or_assign as a free function.
+template <typename Map, typename Value>
+std::pair<typename Map::iterator, bool>
+InsertOrAssign(Map& map, const typename Map::key_type& key, Value&& value) {
+ return internal::InsertOrAssignImpl(map, key, std::forward<Value>(value));
+}
+
+template <typename Map, typename Value>
+std::pair<typename Map::iterator, bool>
+InsertOrAssign(Map& map, typename Map::key_type&& key, Value&& value) {
+ return internal::InsertOrAssignImpl(map, std::move(key),
+ std::forward<Value>(value));
+}
+
+// Implementation of C++17's std::map::insert_or_assign with hint as a free
+// function.
+template <typename Map, typename Value>
+typename Map::iterator InsertOrAssign(Map& map,
+ typename Map::const_iterator hint,
+ const typename Map::key_type& key,
+ Value&& value) {
+ return internal::InsertOrAssignImpl(map, hint, key,
+ std::forward<Value>(value));
+}
+
+template <typename Map, typename Value>
+typename Map::iterator InsertOrAssign(Map& map,
+ typename Map::const_iterator hint,
+ typename Map::key_type&& key,
+ Value&& value) {
+ return internal::InsertOrAssignImpl(map, hint, std::move(key),
+ std::forward<Value>(value));
+}
+
+// Implementation of C++17's std::map::try_emplace as a free function.
+template <typename Map, typename... Args>
+std::pair<typename Map::iterator, bool>
+TryEmplace(Map& map, const typename Map::key_type& key, Args&&... args) {
+ return internal::TryEmplaceImpl(map, key, std::forward<Args>(args)...);
+}
+
+template <typename Map, typename... Args>
+std::pair<typename Map::iterator, bool> TryEmplace(Map& map,
+ typename Map::key_type&& key,
+ Args&&... args) {
+ return internal::TryEmplaceImpl(map, std::move(key),
+ std::forward<Args>(args)...);
+}
+
+// Implementation of C++17's std::map::try_emplace with hint as a free
+// function.
+template <typename Map, typename... Args>
+typename Map::iterator TryEmplace(Map& map,
+ typename Map::const_iterator hint,
+ const typename Map::key_type& key,
+ Args&&... args) {
+ return internal::TryEmplaceImpl(map, hint, key, std::forward<Args>(args)...);
+}
+
+template <typename Map, typename... Args>
+typename Map::iterator TryEmplace(Map& map,
+ typename Map::const_iterator hint,
+ typename Map::key_type&& key,
+ Args&&... args) {
+ return internal::TryEmplaceImpl(map, hint, std::move(key),
+ std::forward<Args>(args)...);
+}
+
+// Returns true if the container is sorted.
+template <typename Container>
+bool STLIsSorted(const Container& cont) {
+ return std::is_sorted(std::begin(cont), std::end(cont));
+}
+
+// Returns a new ResultType containing the difference of two sorted containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
+ DCHECK(STLIsSorted(a1));
+ DCHECK(STLIsSorted(a2));
+ ResultType difference;
+ std::set_difference(a1.begin(), a1.end(),
+ a2.begin(), a2.end(),
+ std::inserter(difference, difference.end()));
+ return difference;
+}
+
+// Returns a new ResultType containing the union of two sorted containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
+ DCHECK(STLIsSorted(a1));
+ DCHECK(STLIsSorted(a2));
+ ResultType result;
+ std::set_union(a1.begin(), a1.end(),
+ a2.begin(), a2.end(),
+ std::inserter(result, result.end()));
+ return result;
+}
+
+// Returns a new ResultType containing the intersection of two sorted
+// containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
+ DCHECK(STLIsSorted(a1));
+ DCHECK(STLIsSorted(a2));
+ ResultType result;
+ std::set_intersection(a1.begin(), a1.end(),
+ a2.begin(), a2.end(),
+ std::inserter(result, result.end()));
+ return result;
+}
+
+// Returns true if the sorted container |a1| contains all elements of the sorted
+// container |a2|.
+template <typename Arg1, typename Arg2>
+bool STLIncludes(const Arg1& a1, const Arg2& a2) {
+ DCHECK(STLIsSorted(a1));
+ DCHECK(STLIsSorted(a2));
+ return std::includes(a1.begin(), a1.end(),
+ a2.begin(), a2.end());
+}
+
+// Erase/EraseIf are based on library fundamentals ts v2 erase/erase_if
+// http://en.cppreference.com/w/cpp/experimental/lib_extensions_2
+// They provide a generic way to erase elements from a container.
+// The functions here implement these for the standard containers until those
+// functions are available in the C++ standard.
+// For Chromium containers overloads should be defined in their own headers
+// (like standard containers).
+// Note: there is no std::erase for standard associative containers so we don't
+// have it either.
+
+template <typename CharT, typename Traits, typename Allocator, typename Value>
+void Erase(std::basic_string<CharT, Traits, Allocator>& container,
+ const Value& value) {
+ container.erase(std::remove(container.begin(), container.end(), value),
+ container.end());
+}
+
+template <typename CharT, typename Traits, typename Allocator, class Predicate>
+void EraseIf(std::basic_string<CharT, Traits, Allocator>& container,
+ Predicate pred) {
+ container.erase(std::remove_if(container.begin(), container.end(), pred),
+ container.end());
+}
+
+template <class T, class Allocator, class Value>
+void Erase(std::deque<T, Allocator>& container, const Value& value) {
+ container.erase(std::remove(container.begin(), container.end(), value),
+ container.end());
+}
+
+template <class T, class Allocator, class Predicate>
+void EraseIf(std::deque<T, Allocator>& container, Predicate pred) {
+ container.erase(std::remove_if(container.begin(), container.end(), pred),
+ container.end());
+}
+
+template <class T, class Allocator, class Value>
+void Erase(std::vector<T, Allocator>& container, const Value& value) {
+ container.erase(std::remove(container.begin(), container.end(), value),
+ container.end());
+}
+
+template <class T, class Allocator, class Predicate>
+void EraseIf(std::vector<T, Allocator>& container, Predicate pred) {
+ container.erase(std::remove_if(container.begin(), container.end(), pred),
+ container.end());
+}
+
+template <class T, class Allocator, class Value>
+void Erase(std::forward_list<T, Allocator>& container, const Value& value) {
+ // Unlike std::forward_list::remove, this function template accepts
+ // heterogeneous types and does not force a conversion to the container's
+ // value type before invoking the == operator.
+ container.remove_if([&](const T& cur) { return cur == value; });
+}
+
+template <class T, class Allocator, class Predicate>
+void EraseIf(std::forward_list<T, Allocator>& container, Predicate pred) {
+ container.remove_if(pred);
+}
+
+template <class T, class Allocator, class Value>
+void Erase(std::list<T, Allocator>& container, const Value& value) {
+ // Unlike std::list::remove, this function template accepts heterogeneous
+ // types and does not force a conversion to the container's value type before
+ // invoking the == operator.
+ container.remove_if([&](const T& cur) { return cur == value; });
+}
+
+template <class T, class Allocator, class Predicate>
+void EraseIf(std::list<T, Allocator>& container, Predicate pred) {
+ container.remove_if(pred);
+}
+
+template <class Key, class T, class Compare, class Allocator, class Predicate>
+void EraseIf(std::map<Key, T, Compare, Allocator>& container, Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+template <class Key, class T, class Compare, class Allocator, class Predicate>
+void EraseIf(std::multimap<Key, T, Compare, Allocator>& container,
+ Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+template <class Key, class Compare, class Allocator, class Predicate>
+void EraseIf(std::set<Key, Compare, Allocator>& container, Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+template <class Key, class Compare, class Allocator, class Predicate>
+void EraseIf(std::multiset<Key, Compare, Allocator>& container,
+ Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+template <class Key,
+ class T,
+ class Hash,
+ class KeyEqual,
+ class Allocator,
+ class Predicate>
+void EraseIf(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& container,
+ Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+template <class Key,
+ class T,
+ class Hash,
+ class KeyEqual,
+ class Allocator,
+ class Predicate>
+void EraseIf(
+ std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& container,
+ Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+template <class Key,
+ class Hash,
+ class KeyEqual,
+ class Allocator,
+ class Predicate>
+void EraseIf(std::unordered_set<Key, Hash, KeyEqual, Allocator>& container,
+ Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+template <class Key,
+ class Hash,
+ class KeyEqual,
+ class Allocator,
+ class Predicate>
+void EraseIf(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& container,
+ Predicate pred) {
+ internal::IterateAndEraseIf(container, pred);
+}
+
+// A helper class to be used as the predicate with |EraseIf| to implement
+// in-place set intersection. Helps implement the algorithm of going through
+// each container an element at a time, erasing elements from the first
+// container if they aren't in the second container. Requires each container be
+// sorted. Note that the logic below appears inverted since it is returning
+// whether an element should be erased.
+template <class Collection>
+class IsNotIn {
+ public:
+ explicit IsNotIn(const Collection& collection)
+ : i_(collection.begin()), end_(collection.end()) {}
+
+ bool operator()(const typename Collection::value_type& x) {
+ while (i_ != end_ && *i_ < x)
+ ++i_;
+ if (i_ == end_)
+ return true;
+ if (*i_ == x) {
+ ++i_;
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ typename Collection::const_iterator i_;
+ const typename Collection::const_iterator end_;
+};
+
+// Helper for returning the optional value's address, or nullptr.
+template <class T>
+T* OptionalOrNullptr(base::Optional<T>& optional) {
+ return optional.has_value() ? &optional.value() : nullptr;
+}
+
+template <class T>
+const T* OptionalOrNullptr(const base::Optional<T>& optional) {
+ return optional.has_value() ? &optional.value() : nullptr;
+}
+
+} // namespace base
+
+#endif // BASE_STL_UTIL_H_
diff --git a/security/sandbox/chromium/base/strings/char_traits.h b/security/sandbox/chromium/base/strings/char_traits.h
new file mode 100644
index 0000000000..b193e216cc
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/char_traits.h
@@ -0,0 +1,92 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_CHAR_TRAITS_H_
+#define BASE_STRINGS_CHAR_TRAITS_H_
+
+#include <stddef.h>
+
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// constexpr version of http://en.cppreference.com/w/cpp/string/char_traits.
+// This currently just implements the bits needed to support a (mostly)
+// constexpr StringPiece.
+//
+// TODO(dcheng): Once we switch to C++17, most methods will become constexpr and
+// we can switch over to using the one in the standard library.
+template <typename T>
+struct CharTraits {
+ // Performs a lexographical comparison of the first N characters of |s1| and
+ // |s2|. Returns 0 if equal, -1 if |s1| is less than |s2|, and 1 if |s1| is
+ // greater than |s2|.
+ static constexpr int compare(const T* s1, const T* s2, size_t n) noexcept;
+
+ // Returns the length of |s|, assuming null termination (and not including the
+ // terminating null).
+ static constexpr size_t length(const T* s) noexcept;
+};
+
+template <typename T>
+constexpr int CharTraits<T>::compare(const T* s1,
+ const T* s2,
+ size_t n) noexcept {
+ for (; n; --n, ++s1, ++s2) {
+ if (*s1 < *s2)
+ return -1;
+ if (*s1 > *s2)
+ return 1;
+ }
+ return 0;
+}
+
+template <typename T>
+constexpr size_t CharTraits<T>::length(const T* s) noexcept {
+ size_t i = 0;
+ for (; *s; ++s)
+ ++i;
+ return i;
+}
+
+// char specialization of CharTraits that can use clang's constexpr instrinsics,
+// where available.
+template <>
+struct CharTraits<char> {
+ static constexpr int compare(const char* s1,
+ const char* s2,
+ size_t n) noexcept;
+ static constexpr size_t length(const char* s) noexcept;
+};
+
+constexpr int CharTraits<char>::compare(const char* s1,
+ const char* s2,
+ size_t n) noexcept {
+#if HAS_FEATURE(cxx_constexpr_string_builtins)
+ return __builtin_memcmp(s1, s2, n);
+#else
+ for (; n; --n, ++s1, ++s2) {
+ if (*s1 < *s2)
+ return -1;
+ if (*s1 > *s2)
+ return 1;
+ }
+ return 0;
+#endif
+}
+
+constexpr size_t CharTraits<char>::length(const char* s) noexcept {
+#if defined(__clang__)
+ return __builtin_strlen(s);
+#else
+ size_t i = 0;
+ for (; *s; ++s)
+ ++i;
+ return i;
+#endif
+}
+
+} // namespace base
+
+#endif // BASE_STRINGS_CHAR_TRAITS_H_
diff --git a/security/sandbox/chromium/base/strings/nullable_string16.cc b/security/sandbox/chromium/base/strings/nullable_string16.cc
new file mode 100644
index 0000000000..076b282eb1
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/nullable_string16.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/nullable_string16.h"
+
+#include <ostream>
+#include <utility>
+
+namespace base {
+NullableString16::NullableString16() = default;
+NullableString16::NullableString16(const NullableString16& other) = default;
+NullableString16::NullableString16(NullableString16&& other) = default;
+
+NullableString16::NullableString16(const string16& string, bool is_null) {
+ if (!is_null)
+ string_.emplace(string);
+}
+
+NullableString16::NullableString16(Optional<string16> optional_string16)
+ : string_(std::move(optional_string16)) {}
+
+NullableString16::~NullableString16() = default;
+NullableString16& NullableString16::operator=(const NullableString16& other) =
+ default;
+NullableString16& NullableString16::operator=(NullableString16&& other) =
+ default;
+
+std::ostream& operator<<(std::ostream& out, const NullableString16& value) {
+ return value.is_null() ? out << "(null)" : out << value.string();
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/nullable_string16.h b/security/sandbox/chromium/base/strings/nullable_string16.h
new file mode 100644
index 0000000000..abddee0f74
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/nullable_string16.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_NULLABLE_STRING16_H_
+#define BASE_STRINGS_NULLABLE_STRING16_H_
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+// This class is a simple wrapper for string16 which also contains a null
+// state. This should be used only where the difference between null and
+// empty is meaningful.
+class BASE_EXPORT NullableString16 {
+ public:
+ NullableString16();
+ NullableString16(const NullableString16& other);
+ NullableString16(NullableString16&& other);
+ NullableString16(const string16& string, bool is_null);
+ explicit NullableString16(Optional<string16> optional_string16);
+ ~NullableString16();
+
+ NullableString16& operator=(const NullableString16& other);
+ NullableString16& operator=(NullableString16&& other);
+
+ const string16& string() const {
+ return string_ ? *string_ : EmptyString16();
+ }
+ bool is_null() const { return !string_; }
+ const Optional<string16>& as_optional_string16() const { return string_; }
+
+ private:
+ Optional<string16> string_;
+};
+
+inline bool operator==(const NullableString16& a, const NullableString16& b) {
+ return a.as_optional_string16() == b.as_optional_string16();
+}
+
+inline bool operator!=(const NullableString16& a, const NullableString16& b) {
+ return !(a == b);
+}
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& out,
+ const NullableString16& value);
+
+} // namespace base
+
+#endif // BASE_STRINGS_NULLABLE_STRING16_H_
diff --git a/security/sandbox/chromium/base/strings/safe_sprintf.cc b/security/sandbox/chromium/base/strings/safe_sprintf.cc
new file mode 100644
index 0000000000..89049abd79
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/safe_sprintf.cc
@@ -0,0 +1,682 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/safe_sprintf.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if !defined(NDEBUG)
+// In debug builds, we use RAW_CHECK() to print useful error messages, if
+// SafeSPrintf() is called with broken arguments.
+// As our contract promises that SafeSPrintf() can be called from any
+// restricted run-time context, it is not actually safe to call logging
+// functions from it; and we only ever do so for debug builds and hope for the
+// best. We should _never_ call any logging function other than RAW_CHECK(),
+// and we should _never_ include any logging code that is active in production
+// builds. Most notably, we should not include these logging functions in
+// unofficial release builds, even though those builds would otherwise have
+// DCHECKS() enabled.
+// In other words; please do not remove the #ifdef around this #include.
+// Instead, in production builds we opt for returning a degraded result,
+// whenever an error is encountered.
+// E.g. The broken function call
+// SafeSPrintf("errno = %d (%x)", errno, strerror(errno))
+// will print something like
+// errno = 13, (%x)
+// instead of
+// errno = 13 (Access denied)
+// In most of the anticipated use cases, that's probably the preferred
+// behavior.
+#include "base/logging.h"
+#define DEBUG_CHECK RAW_CHECK
+#else
+#define DEBUG_CHECK(x) do { if (x) { } } while (0)
+#endif
+
+namespace base {
+namespace strings {
+
+// The code in this file is extremely careful to be async-signal-safe.
+//
+// Most obviously, we avoid calling any code that could dynamically allocate
+// memory. Doing so would almost certainly result in bugs and dead-locks.
+// We also avoid calling any other STL functions that could have unintended
+// side-effects involving memory allocation or access to other shared
+// resources.
+//
+// But on top of that, we also avoid calling other library functions, as many
+// of them have the side-effect of calling getenv() (in order to deal with
+// localization) or accessing errno. The latter sounds benign, but there are
+// several execution contexts where it isn't even possible to safely read let
+// alone write errno.
+//
+// The stated design goal of the SafeSPrintf() function is that it can be
+// called from any context that can safely call C or C++ code (i.e. anything
+// that doesn't require assembly code).
+//
+// For a brief overview of some but not all of the issues with async-signal-
+// safety, refer to:
+// http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
+
+namespace {
+const size_t kSSizeMaxConst = ((size_t)(ssize_t)-1) >> 1;
+
+const char kUpCaseHexDigits[] = "0123456789ABCDEF";
+const char kDownCaseHexDigits[] = "0123456789abcdef";
+}
+
+#if defined(NDEBUG)
+// We would like to define kSSizeMax as std::numeric_limits<ssize_t>::max(),
+// but C++ doesn't allow us to do that for constants. Instead, we have to
+// use careful casting and shifting. We later use a static_assert to
+// verify that this worked correctly.
+namespace {
+const size_t kSSizeMax = kSSizeMaxConst;
+}
+#else // defined(NDEBUG)
+// For efficiency, we really need kSSizeMax to be a constant. But for unit
+// tests, it should be adjustable. This allows us to verify edge cases without
+// having to fill the entire available address space. As a compromise, we make
+// kSSizeMax adjustable in debug builds, and then only compile that particular
+// part of the unit test in debug builds.
+namespace {
+static size_t kSSizeMax = kSSizeMaxConst;
+}
+
+namespace internal {
+void SetSafeSPrintfSSizeMaxForTest(size_t max) {
+ kSSizeMax = max;
+}
+
+size_t GetSafeSPrintfSSizeMaxForTest() {
+ return kSSizeMax;
+}
+}
+#endif // defined(NDEBUG)
+
+namespace {
+class Buffer {
+ public:
+ // |buffer| is caller-allocated storage that SafeSPrintf() writes to. It
+ // has |size| bytes of writable storage. It is the caller's responsibility
+ // to ensure that the buffer is at least one byte in size, so that it fits
+ // the trailing NUL that will be added by the destructor. The buffer also
+ // must be smaller or equal to kSSizeMax in size.
+ Buffer(char* buffer, size_t size)
+ : buffer_(buffer),
+ size_(size - 1), // Account for trailing NUL byte
+ count_(0) {
+// MSVS2013's standard library doesn't mark max() as constexpr yet. cl.exe
+// supports static_cast but doesn't really implement constexpr yet so it doesn't
+// complain, but clang does.
+#if __cplusplus >= 201103 && !(defined(__clang__) && defined(OS_WIN))
+ static_assert(kSSizeMaxConst ==
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
+ "kSSizeMaxConst should be the max value of an ssize_t");
+#endif
+ DEBUG_CHECK(size > 0);
+ DEBUG_CHECK(size <= kSSizeMax);
+ }
+
+ ~Buffer() {
+ // The code calling the constructor guaranteed that there was enough space
+ // to store a trailing NUL -- and in debug builds, we are actually
+ // verifying this with DEBUG_CHECK()s in the constructor. So, we can
+ // always unconditionally write the NUL byte in the destructor. We do not
+ // need to adjust the count_, as SafeSPrintf() copies snprintf() in not
+ // including the NUL byte in its return code.
+ *GetInsertionPoint() = '\000';
+ }
+
+ // Returns true, iff the buffer is filled all the way to |kSSizeMax-1|. The
+ // caller can now stop adding more data, as GetCount() has reached its
+ // maximum possible value.
+ inline bool OutOfAddressableSpace() const {
+ return count_ == static_cast<size_t>(kSSizeMax - 1);
+ }
+
+ // Returns the number of bytes that would have been emitted to |buffer_|
+ // if it was sized sufficiently large. This number can be larger than
+ // |size_|, if the caller provided an insufficiently large output buffer.
+ // But it will never be bigger than |kSSizeMax-1|.
+ inline ssize_t GetCount() const {
+ DEBUG_CHECK(count_ < kSSizeMax);
+ return static_cast<ssize_t>(count_);
+ }
+
+ // Emits one |ch| character into the |buffer_| and updates the |count_| of
+ // characters that are currently supposed to be in the buffer.
+ // Returns "false", iff the buffer was already full.
+ // N.B. |count_| increases even if no characters have been written. This is
+ // needed so that GetCount() can return the number of bytes that should
+ // have been allocated for the |buffer_|.
+ inline bool Out(char ch) {
+ if (size_ >= 1 && count_ < size_) {
+ buffer_[count_] = ch;
+ return IncrementCountByOne();
+ }
+ // |count_| still needs to be updated, even if the buffer has been
+ // filled completely. This allows SafeSPrintf() to return the number of
+ // bytes that should have been emitted.
+ IncrementCountByOne();
+ return false;
+ }
+
+ // Inserts |padding|-|len| bytes worth of padding into the |buffer_|.
+ // |count_| will also be incremented by the number of bytes that were meant
+ // to be emitted. The |pad| character is typically either a ' ' space
+ // or a '0' zero, but other non-NUL values are legal.
+ // Returns "false", iff the the |buffer_| filled up (i.e. |count_|
+ // overflowed |size_|) at any time during padding.
+ inline bool Pad(char pad, size_t padding, size_t len) {
+ DEBUG_CHECK(pad);
+ DEBUG_CHECK(padding <= kSSizeMax);
+ for (; padding > len; --padding) {
+ if (!Out(pad)) {
+ if (--padding) {
+ IncrementCount(padding-len);
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // POSIX doesn't define any async-signal-safe function for converting
+ // an integer to ASCII. Define our own version.
+ //
+ // This also gives us the ability to make the function a little more
+ // powerful and have it deal with |padding|, with truncation, and with
+ // predicting the length of the untruncated output.
+ //
+ // IToASCII() converts an integer |i| to ASCII.
+ //
+ // Unlike similar functions in the standard C library, it never appends a
+ // NUL character. This is left for the caller to do.
+ //
+ // While the function signature takes a signed int64_t, the code decides at
+ // run-time whether to treat the argument as signed (int64_t) or as unsigned
+ // (uint64_t) based on the value of |sign|.
+ //
+ // It supports |base|s 2 through 16. Only a |base| of 10 is allowed to have
+ // a |sign|. Otherwise, |i| is treated as unsigned.
+ //
+ // For bases larger than 10, |upcase| decides whether lower-case or upper-
+ // case letters should be used to designate digits greater than 10.
+ //
+ // Padding can be done with either '0' zeros or ' ' spaces. Padding has to
+ // be positive and will always be applied to the left of the output.
+ //
+ // Prepends a |prefix| to the number (e.g. "0x"). This prefix goes to
+ // the left of |padding|, if |pad| is '0'; and to the right of |padding|
+ // if |pad| is ' '.
+ //
+ // Returns "false", if the |buffer_| overflowed at any time.
+ bool IToASCII(bool sign, bool upcase, int64_t i, int base,
+ char pad, size_t padding, const char* prefix);
+
+ private:
+ // Increments |count_| by |inc| unless this would cause |count_| to
+ // overflow |kSSizeMax-1|. Returns "false", iff an overflow was detected;
+ // it then clamps |count_| to |kSSizeMax-1|.
+ inline bool IncrementCount(size_t inc) {
+ // "inc" is either 1 or a "padding" value. Padding is clamped at
+ // run-time to at most kSSizeMax-1. So, we know that "inc" is always in
+ // the range 1..kSSizeMax-1.
+ // This allows us to compute "kSSizeMax - 1 - inc" without incurring any
+ // integer overflows.
+ DEBUG_CHECK(inc <= kSSizeMax - 1);
+ if (count_ > kSSizeMax - 1 - inc) {
+ count_ = kSSizeMax - 1;
+ return false;
+ }
+ count_ += inc;
+ return true;
+ }
+
+ // Convenience method for the common case of incrementing |count_| by one.
+ inline bool IncrementCountByOne() {
+ return IncrementCount(1);
+ }
+
+ // Return the current insertion point into the buffer. This is typically
+ // at |buffer_| + |count_|, but could be before that if truncation
+ // happened. It always points to one byte past the last byte that was
+ // successfully placed into the |buffer_|.
+ inline char* GetInsertionPoint() const {
+ size_t idx = count_;
+ if (idx > size_) {
+ idx = size_;
+ }
+ return buffer_ + idx;
+ }
+
+ // User-provided buffer that will receive the fully formatted output string.
+ char* buffer_;
+
+ // Number of bytes that are available in the buffer excluding the trailing
+ // NUL byte that will be added by the destructor.
+ const size_t size_;
+
+ // Number of bytes that would have been emitted to the buffer, if the buffer
+ // was sufficiently big. This number always excludes the trailing NUL byte
+ // and it is guaranteed to never grow bigger than kSSizeMax-1.
+ size_t count_;
+
+ DISALLOW_COPY_AND_ASSIGN(Buffer);
+};
+
+
+bool Buffer::IToASCII(bool sign, bool upcase, int64_t i, int base,
+ char pad, size_t padding, const char* prefix) {
+ // Sanity check for parameters. None of these should ever fail, but see
+ // above for the rationale why we can't call CHECK().
+ DEBUG_CHECK(base >= 2);
+ DEBUG_CHECK(base <= 16);
+ DEBUG_CHECK(!sign || base == 10);
+ DEBUG_CHECK(pad == '0' || pad == ' ');
+ DEBUG_CHECK(padding <= kSSizeMax);
+ DEBUG_CHECK(!(sign && prefix && *prefix));
+
+ // Handle negative numbers, if the caller indicated that |i| should be
+ // treated as a signed number; otherwise treat |i| as unsigned (even if the
+ // MSB is set!)
+ // Details are tricky, because of limited data-types, but equivalent pseudo-
+ // code would look like:
+ // if (sign && i < 0)
+ // prefix = "-";
+ // num = abs(i);
+ int minint = 0;
+ uint64_t num;
+ if (sign && i < 0) {
+ prefix = "-";
+
+ // Turn our number positive.
+ if (i == std::numeric_limits<int64_t>::min()) {
+ // The most negative integer needs special treatment.
+ minint = 1;
+ num = static_cast<uint64_t>(-(i + 1));
+ } else {
+ // "Normal" negative numbers are easy.
+ num = static_cast<uint64_t>(-i);
+ }
+ } else {
+ num = static_cast<uint64_t>(i);
+ }
+
+ // If padding with '0' zero, emit the prefix or '-' character now. Otherwise,
+ // make the prefix accessible in reverse order, so that we can later output
+ // it right between padding and the number.
+ // We cannot choose the easier approach of just reversing the number, as that
+ // fails in situations where we need to truncate numbers that have padding
+ // and/or prefixes.
+ const char* reverse_prefix = nullptr;
+ if (prefix && *prefix) {
+ if (pad == '0') {
+ while (*prefix) {
+ if (padding) {
+ --padding;
+ }
+ Out(*prefix++);
+ }
+ prefix = nullptr;
+ } else {
+ for (reverse_prefix = prefix; *reverse_prefix; ++reverse_prefix) {
+ }
+ }
+ } else
+ prefix = nullptr;
+ const size_t prefix_length = reverse_prefix - prefix;
+
+ // Loop until we have converted the entire number. Output at least one
+ // character (i.e. '0').
+ size_t start = count_;
+ size_t discarded = 0;
+ bool started = false;
+ do {
+ // Make sure there is still enough space left in our output buffer.
+ if (count_ >= size_) {
+ if (start < size_) {
+ // It is rare that we need to output a partial number. But if asked
+ // to do so, we will still make sure we output the correct number of
+ // leading digits.
+ // Since we are generating the digits in reverse order, we actually
+ // have to discard digits in the order that we have already emitted
+ // them. This is essentially equivalent to:
+ // memmove(buffer_ + start, buffer_ + start + 1, size_ - start - 1)
+ for (char* move = buffer_ + start, *end = buffer_ + size_ - 1;
+ move < end;
+ ++move) {
+ *move = move[1];
+ }
+ ++discarded;
+ --count_;
+ } else if (count_ - size_ > 1) {
+ // Need to increment either |count_| or |discarded| to make progress.
+ // The latter is more efficient, as it eventually triggers fast
+ // handling of padding. But we have to ensure we don't accidentally
+ // change the overall state (i.e. switch the state-machine from
+ // discarding to non-discarding). |count_| needs to always stay
+ // bigger than |size_|.
+ --count_;
+ ++discarded;
+ }
+ }
+
+ // Output the next digit and (if necessary) compensate for the most
+ // negative integer needing special treatment. This works because,
+ // no matter the bit width of the integer, the lowest-most decimal
+ // integer always ends in 2, 4, 6, or 8.
+ if (!num && started) {
+ if (reverse_prefix > prefix) {
+ Out(*--reverse_prefix);
+ } else {
+ Out(pad);
+ }
+ } else {
+ started = true;
+ Out((upcase ? kUpCaseHexDigits : kDownCaseHexDigits)[num%base + minint]);
+ }
+
+ minint = 0;
+ num /= base;
+
+ // Add padding, if requested.
+ if (padding > 0) {
+ --padding;
+
+ // Performance optimization for when we are asked to output excessive
+ // padding, but our output buffer is limited in size. Even if we output
+ // a 64bit number in binary, we would never write more than 64 plus
+ // prefix non-padding characters. So, once this limit has been passed,
+ // any further state change can be computed arithmetically; we know that
+ // by this time, our entire final output consists of padding characters
+ // that have all already been output.
+ if (discarded > 8*sizeof(num) + prefix_length) {
+ IncrementCount(padding);
+ padding = 0;
+ }
+ }
+ } while (num || padding || (reverse_prefix > prefix));
+
+ // Conversion to ASCII actually resulted in the digits being in reverse
+ // order. We can't easily generate them in forward order, as we can't tell
+ // the number of characters needed until we are done converting.
+ // So, now, we reverse the string (except for the possible '-' sign).
+ char* front = buffer_ + start;
+ char* back = GetInsertionPoint();
+ while (--back > front) {
+ char ch = *back;
+ *back = *front;
+ *front++ = ch;
+ }
+
+ IncrementCount(discarded);
+ return !discarded;
+}
+
+} // anonymous namespace
+
+namespace internal {
+
+ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, const Arg* args,
+ const size_t max_args) {
+ // Make sure that at least one NUL byte can be written, and that the buffer
+ // never overflows kSSizeMax. Not only does that use up most or all of the
+ // address space, it also would result in a return code that cannot be
+ // represented.
+ if (static_cast<ssize_t>(sz) < 1)
+ return -1;
+ sz = std::min(sz, kSSizeMax);
+
+ // Iterate over format string and interpret '%' arguments as they are
+ // encountered.
+ Buffer buffer(buf, sz);
+ size_t padding;
+ char pad;
+ for (unsigned int cur_arg = 0; *fmt && !buffer.OutOfAddressableSpace(); ) {
+ if (*fmt++ == '%') {
+ padding = 0;
+ pad = ' ';
+ char ch = *fmt++;
+ format_character_found:
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ // Found a width parameter. Convert to an integer value and store in
+ // "padding". If the leading digit is a zero, change the padding
+ // character from a space ' ' to a zero '0'.
+ pad = ch == '0' ? '0' : ' ';
+ for (;;) {
+ // The maximum allowed padding fills all the available address
+ // space and leaves just enough space to insert the trailing NUL.
+ const size_t max_padding = kSSizeMax - 1;
+ if (padding > max_padding/10 ||
+ 10*padding > max_padding - (ch - '0')) {
+ DEBUG_CHECK(padding <= max_padding/10 &&
+ 10*padding <= max_padding - (ch - '0'));
+ // Integer overflow detected. Skip the rest of the width until
+ // we find the format character, then do the normal error handling.
+ padding_overflow:
+ padding = max_padding;
+ while ((ch = *fmt++) >= '0' && ch <= '9') {
+ }
+ if (cur_arg < max_args) {
+ ++cur_arg;
+ }
+ goto fail_to_expand;
+ }
+ padding = 10*padding + ch - '0';
+ if (padding > max_padding) {
+ // This doesn't happen for "sane" values of kSSizeMax. But once
+ // kSSizeMax gets smaller than about 10, our earlier range checks
+ // are incomplete. Unittests do trigger this artificial corner
+ // case.
+ DEBUG_CHECK(padding <= max_padding);
+ goto padding_overflow;
+ }
+ ch = *fmt++;
+ if (ch < '0' || ch > '9') {
+ // Reached the end of the width parameter. This is where the format
+ // character is found.
+ goto format_character_found;
+ }
+ }
+ break;
+ case 'c': { // Output an ASCII character.
+ // Check that there are arguments left to be inserted.
+ if (cur_arg >= max_args) {
+ DEBUG_CHECK(cur_arg < max_args);
+ goto fail_to_expand;
+ }
+
+ // Check that the argument has the expected type.
+ const Arg& arg = args[cur_arg++];
+ if (arg.type != Arg::INT && arg.type != Arg::UINT) {
+ DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
+ goto fail_to_expand;
+ }
+
+ // Apply padding, if needed.
+ buffer.Pad(' ', padding, 1);
+
+ // Convert the argument to an ASCII character and output it.
+ char as_char = static_cast<char>(arg.integer.i);
+ if (!as_char) {
+ goto end_of_output_buffer;
+ }
+ buffer.Out(as_char);
+ break; }
+ case 'd': // Output a possibly signed decimal value.
+ case 'o': // Output an unsigned octal value.
+ case 'x': // Output an unsigned hexadecimal value.
+ case 'X':
+ case 'p': { // Output a pointer value.
+ // Check that there are arguments left to be inserted.
+ if (cur_arg >= max_args) {
+ DEBUG_CHECK(cur_arg < max_args);
+ goto fail_to_expand;
+ }
+
+ const Arg& arg = args[cur_arg++];
+ int64_t i;
+ const char* prefix = nullptr;
+ if (ch != 'p') {
+ // Check that the argument has the expected type.
+ if (arg.type != Arg::INT && arg.type != Arg::UINT) {
+ DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
+ goto fail_to_expand;
+ }
+ i = arg.integer.i;
+
+ if (ch != 'd') {
+ // The Arg() constructor automatically performed sign expansion on
+ // signed parameters. This is great when outputting a %d decimal
+ // number, but can result in unexpected leading 0xFF bytes when
+ // outputting a %x hexadecimal number. Mask bits, if necessary.
+ // We have to do this here, instead of in the Arg() constructor, as
+ // the Arg() constructor cannot tell whether we will output a %d
+ // or a %x. Only the latter should experience masking.
+ if (arg.integer.width < sizeof(int64_t)) {
+ i &= (1LL << (8*arg.integer.width)) - 1;
+ }
+ }
+ } else {
+ // Pointer values require an actual pointer or a string.
+ if (arg.type == Arg::POINTER) {
+ i = reinterpret_cast<uintptr_t>(arg.ptr);
+ } else if (arg.type == Arg::STRING) {
+ i = reinterpret_cast<uintptr_t>(arg.str);
+ } else if (arg.type == Arg::INT &&
+ arg.integer.width == sizeof(NULL) &&
+ arg.integer.i == 0) { // Allow C++'s version of NULL
+ i = 0;
+ } else {
+ DEBUG_CHECK(arg.type == Arg::POINTER || arg.type == Arg::STRING);
+ goto fail_to_expand;
+ }
+
+ // Pointers always include the "0x" prefix.
+ prefix = "0x";
+ }
+
+ // Use IToASCII() to convert to ASCII representation. For decimal
+ // numbers, optionally print a sign. For hexadecimal numbers,
+ // distinguish between upper and lower case. %p addresses are always
+ // printed as upcase. Supports base 8, 10, and 16. Prints padding
+ // and/or prefixes, if so requested.
+ buffer.IToASCII(ch == 'd' && arg.type == Arg::INT,
+ ch != 'x', i,
+ ch == 'o' ? 8 : ch == 'd' ? 10 : 16,
+ pad, padding, prefix);
+ break; }
+ case 's': {
+ // Check that there are arguments left to be inserted.
+ if (cur_arg >= max_args) {
+ DEBUG_CHECK(cur_arg < max_args);
+ goto fail_to_expand;
+ }
+
+ // Check that the argument has the expected type.
+ const Arg& arg = args[cur_arg++];
+ const char *s;
+ if (arg.type == Arg::STRING) {
+ s = arg.str ? arg.str : "<NULL>";
+ } else if (arg.type == Arg::INT && arg.integer.width == sizeof(NULL) &&
+ arg.integer.i == 0) { // Allow C++'s version of NULL
+ s = "<NULL>";
+ } else {
+ DEBUG_CHECK(arg.type == Arg::STRING);
+ goto fail_to_expand;
+ }
+
+ // Apply padding, if needed. This requires us to first check the
+ // length of the string that we are outputting.
+ if (padding) {
+ size_t len = 0;
+ for (const char* src = s; *src++; ) {
+ ++len;
+ }
+ buffer.Pad(' ', padding, len);
+ }
+
+ // Printing a string involves nothing more than copying it into the
+ // output buffer and making sure we don't output more bytes than
+ // available space; Out() takes care of doing that.
+ for (const char* src = s; *src; ) {
+ buffer.Out(*src++);
+ }
+ break; }
+ case '%':
+ // Quoted percent '%' character.
+ goto copy_verbatim;
+ fail_to_expand:
+ // C++ gives us tools to do type checking -- something that snprintf()
+ // could never really do. So, whenever we see arguments that don't
+ // match up with the format string, we refuse to output them. But
+ // since we have to be extremely conservative about being async-
+ // signal-safe, we are limited in the type of error handling that we
+ // can do in production builds (in debug builds we can use
+ // DEBUG_CHECK() and hope for the best). So, all we do is pass the
+ // format string unchanged. That should eventually get the user's
+ // attention; and in the meantime, it hopefully doesn't lose too much
+ // data.
+ default:
+ // Unknown or unsupported format character. Just copy verbatim to
+ // output.
+ buffer.Out('%');
+ DEBUG_CHECK(ch);
+ if (!ch) {
+ goto end_of_format_string;
+ }
+ buffer.Out(ch);
+ break;
+ }
+ } else {
+ copy_verbatim:
+ buffer.Out(fmt[-1]);
+ }
+ }
+ end_of_format_string:
+ end_of_output_buffer:
+ return buffer.GetCount();
+}
+
+} // namespace internal
+
+ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt) {
+ // Make sure that at least one NUL byte can be written, and that the buffer
+ // never overflows kSSizeMax. Not only does that use up most or all of the
+ // address space, it also would result in a return code that cannot be
+ // represented.
+ if (static_cast<ssize_t>(sz) < 1)
+ return -1;
+ sz = std::min(sz, kSSizeMax);
+
+ Buffer buffer(buf, sz);
+
+ // In the slow-path, we deal with errors by copying the contents of
+ // "fmt" unexpanded. This means, if there are no arguments passed, the
+ // SafeSPrintf() function always degenerates to a version of strncpy() that
+ // de-duplicates '%' characters.
+ const char* src = fmt;
+ for (; *src; ++src) {
+ buffer.Out(*src);
+ DEBUG_CHECK(src[0] != '%' || src[1] == '%');
+ if (src[0] == '%' && src[1] == '%') {
+ ++src;
+ }
+ }
+ return buffer.GetCount();
+}
+
+} // namespace strings
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/safe_sprintf.h b/security/sandbox/chromium/base/strings/safe_sprintf.h
new file mode 100644
index 0000000000..01d649d07a
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/safe_sprintf.h
@@ -0,0 +1,246 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_SAFE_SPRINTF_H_
+#define BASE_STRINGS_SAFE_SPRINTF_H_
+
+#include "build/build_config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+// For ssize_t
+#include <unistd.h>
+#endif
+
+#include "base/base_export.h"
+
+namespace base {
+namespace strings {
+
+#if defined(COMPILER_MSVC)
+// Define ssize_t inside of our namespace.
+#if defined(_WIN64)
+typedef __int64 ssize_t;
+#else
+typedef long ssize_t;
+#endif
+#endif
+
+// SafeSPrintf() is a type-safe and completely self-contained version of
+// snprintf().
+//
+// SafeSNPrintf() is an alternative function signature that can be used when
+// not dealing with fixed-sized buffers. When possible, SafeSPrintf() should
+// always be used instead of SafeSNPrintf()
+//
+// These functions allow for formatting complicated messages from contexts that
+// require strict async-signal-safety. In fact, it is safe to call them from
+// any low-level execution context, as they are guaranteed to make no library
+// or system calls. It deliberately never touches "errno", either.
+//
+// The only exception to this rule is that in debug builds the code calls
+// RAW_CHECK() to help diagnose problems when the format string does not
+// match the rest of the arguments. In release builds, no CHECK()s are used,
+// and SafeSPrintf() instead returns an output string that expands only
+// those arguments that match their format characters. Mismatched arguments
+// are ignored.
+//
+// The code currently only supports a subset of format characters:
+// %c, %o, %d, %x, %X, %p, and %s.
+//
+// SafeSPrintf() aims to be as liberal as reasonably possible. Integer-like
+// values of arbitrary width can be passed to all of the format characters
+// that expect integers. Thus, it is explicitly legal to pass an "int" to
+// "%c", and output will automatically look at the LSB only. It is also
+// explicitly legal to pass either signed or unsigned values, and the format
+// characters will automatically interpret the arguments accordingly.
+//
+// It is still not legal to mix-and-match integer-like values with pointer
+// values. For instance, you cannot pass a pointer to %x, nor can you pass an
+// integer to %p.
+//
+// The one exception is "0" zero being accepted by "%p". This works-around
+// the problem of C++ defining NULL as an integer-like value.
+//
+// All format characters take an optional width parameter. This must be a
+// positive integer. For %d, %o, %x, %X and %p, if the width starts with
+// a leading '0', padding is done with '0' instead of ' ' characters.
+//
+// There are a few features of snprintf()-style format strings, that
+// SafeSPrintf() does not support at this time.
+//
+// If an actual user showed up, there is no particularly strong reason they
+// couldn't be added. But that assumes that the trade-offs between complexity
+// and utility are favorable.
+//
+// For example, adding support for negative padding widths, and for %n are all
+// likely to be viewed positively. They are all clearly useful, low-risk, easy
+// to test, don't jeopardize the async-signal-safety of the code, and overall
+// have little impact on other parts of SafeSPrintf() function.
+//
+// On the other hands, adding support for alternate forms, positional
+// arguments, grouping, wide characters, localization or floating point numbers
+// are all unlikely to ever be added.
+//
+// SafeSPrintf() and SafeSNPrintf() mimic the behavior of snprintf() and they
+// return the number of bytes needed to store the untruncated output. This
+// does *not* include the terminating NUL byte.
+//
+// They return -1, iff a fatal error happened. This typically can only happen,
+// if the buffer size is a) negative, or b) zero (i.e. not even the NUL byte
+// can be written). The return value can never be larger than SSIZE_MAX-1.
+// This ensures that the caller can always add one to the signed return code
+// in order to determine the amount of storage that needs to be allocated.
+//
+// While the code supports type checking and while it is generally very careful
+// to avoid printing incorrect values, it tends to be conservative in printing
+// as much as possible, even when given incorrect parameters. Typically, in
+// case of an error, the format string will not be expanded. (i.e. something
+// like SafeSPrintf(buf, "%p %d", 1, 2) results in "%p 2"). See above for
+// the use of RAW_CHECK() in debug builds, though.
+//
+// Basic example:
+// char buf[20];
+// base::strings::SafeSPrintf(buf, "The answer: %2d", 42);
+//
+// Example with dynamically sized buffer (async-signal-safe). This code won't
+// work on Visual studio, as it requires dynamically allocating arrays on the
+// stack. Consider picking a smaller value for |kMaxSize| if stack size is
+// limited and known. On the other hand, if the parameters to SafeSNPrintf()
+// are trusted and not controllable by the user, you can consider eliminating
+// the check for |kMaxSize| altogether. The current value of SSIZE_MAX is
+// essentially a no-op that just illustrates how to implement an upper bound:
+// const size_t kInitialSize = 128;
+// const size_t kMaxSize = std::numeric_limits<ssize_t>::max();
+// size_t size = kInitialSize;
+// for (;;) {
+// char buf[size];
+// size = SafeSNPrintf(buf, size, "Error message \"%s\"\n", err) + 1;
+// if (sizeof(buf) < kMaxSize && size > kMaxSize) {
+// size = kMaxSize;
+// continue;
+// } else if (size > sizeof(buf))
+// continue;
+// write(2, buf, size-1);
+// break;
+// }
+
+namespace internal {
+// Helpers that use C++ overloading, templates, and specializations to deduce
+// and record type information from function arguments. This allows us to
+// later write a type-safe version of snprintf().
+
+struct Arg {
+ enum Type { INT, UINT, STRING, POINTER };
+
+ // Any integer-like value.
+ Arg(signed char c) : type(INT) {
+ integer.i = c;
+ integer.width = sizeof(char);
+ }
+ Arg(unsigned char c) : type(UINT) {
+ integer.i = c;
+ integer.width = sizeof(char);
+ }
+ Arg(signed short j) : type(INT) {
+ integer.i = j;
+ integer.width = sizeof(short);
+ }
+ Arg(unsigned short j) : type(UINT) {
+ integer.i = j;
+ integer.width = sizeof(short);
+ }
+ Arg(signed int j) : type(INT) {
+ integer.i = j;
+ integer.width = sizeof(int);
+ }
+ Arg(unsigned int j) : type(UINT) {
+ integer.i = j;
+ integer.width = sizeof(int);
+ }
+ Arg(signed long j) : type(INT) {
+ integer.i = j;
+ integer.width = sizeof(long);
+ }
+ Arg(unsigned long j) : type(UINT) {
+ integer.i = j;
+ integer.width = sizeof(long);
+ }
+ Arg(signed long long j) : type(INT) {
+ integer.i = j;
+ integer.width = sizeof(long long);
+ }
+ Arg(unsigned long long j) : type(UINT) {
+ integer.i = j;
+ integer.width = sizeof(long long);
+ }
+
+ // A C-style text string.
+ Arg(const char* s) : str(s), type(STRING) { }
+ Arg(char* s) : str(s), type(STRING) { }
+
+ // Any pointer value that can be cast to a "void*".
+ template<class T> Arg(T* p) : ptr((void*)p), type(POINTER) { }
+
+ union {
+ // An integer-like value.
+ struct {
+ int64_t i;
+ unsigned char width;
+ } integer;
+
+ // A C-style text string.
+ const char* str;
+
+ // A pointer to an arbitrary object.
+ const void* ptr;
+ };
+ const enum Type type;
+};
+
+// This is the internal function that performs the actual formatting of
+// an snprintf()-style format string.
+BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt,
+ const Arg* args, size_t max_args);
+
+#if !defined(NDEBUG)
+// In debug builds, allow unit tests to artificially lower the kSSizeMax
+// constant that is used as a hard upper-bound for all buffers. In normal
+// use, this constant should always be std::numeric_limits<ssize_t>::max().
+BASE_EXPORT void SetSafeSPrintfSSizeMaxForTest(size_t max);
+BASE_EXPORT size_t GetSafeSPrintfSSizeMaxForTest();
+#endif
+
+} // namespace internal
+
+template<typename... Args>
+ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args... args) {
+ // Use Arg() object to record type information and then copy arguments to an
+ // array to make it easier to iterate over them.
+ const internal::Arg arg_array[] = { args... };
+ return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
+}
+
+template<size_t N, typename... Args>
+ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, Args... args) {
+ // Use Arg() object to record type information and then copy arguments to an
+ // array to make it easier to iterate over them.
+ const internal::Arg arg_array[] = { args... };
+ return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
+}
+
+// Fast-path when we don't actually need to substitute any arguments.
+BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt);
+template<size_t N>
+inline ssize_t SafeSPrintf(char (&buf)[N], const char* fmt) {
+ return SafeSNPrintf(buf, N, fmt);
+}
+
+} // namespace strings
+} // namespace base
+
+#endif // BASE_STRINGS_SAFE_SPRINTF_H_
diff --git a/security/sandbox/chromium/base/strings/safe_sprintf_unittest.cc b/security/sandbox/chromium/base/strings/safe_sprintf_unittest.cc
new file mode 100644
index 0000000000..bb9908f928
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/safe_sprintf_unittest.cc
@@ -0,0 +1,765 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/safe_sprintf.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <limits>
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Death tests on Android are currently very flaky. No need to add more flaky
+// tests, as they just make it hard to spot real problems.
+// TODO(markus): See if the restrictions on Android can eventually be lifted.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+#define ALLOW_DEATH_TEST
+#endif
+
+namespace base {
+namespace strings {
+
+TEST(SafeSPrintfTest, Empty) {
+ char buf[2] = { 'X', 'X' };
+
+ // Negative buffer size should always result in an error.
+ EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), ""));
+ EXPECT_EQ('X', buf[0]);
+ EXPECT_EQ('X', buf[1]);
+
+ // Zero buffer size should always result in an error.
+ EXPECT_EQ(-1, SafeSNPrintf(buf, 0, ""));
+ EXPECT_EQ('X', buf[0]);
+ EXPECT_EQ('X', buf[1]);
+
+ // A one-byte buffer should always print a single NUL byte.
+ EXPECT_EQ(0, SafeSNPrintf(buf, 1, ""));
+ EXPECT_EQ(0, buf[0]);
+ EXPECT_EQ('X', buf[1]);
+ buf[0] = 'X';
+
+ // A larger buffer should leave the trailing bytes unchanged.
+ EXPECT_EQ(0, SafeSNPrintf(buf, 2, ""));
+ EXPECT_EQ(0, buf[0]);
+ EXPECT_EQ('X', buf[1]);
+ buf[0] = 'X';
+
+ // The same test using SafeSPrintf() instead of SafeSNPrintf().
+ EXPECT_EQ(0, SafeSPrintf(buf, ""));
+ EXPECT_EQ(0, buf[0]);
+ EXPECT_EQ('X', buf[1]);
+ buf[0] = 'X';
+}
+
+TEST(SafeSPrintfTest, NoArguments) {
+ // Output a text message that doesn't require any substitutions. This
+ // is roughly equivalent to calling strncpy() (but unlike strncpy(), it does
+ // always add a trailing NUL; it always deduplicates '%' characters).
+ static const char text[] = "hello world";
+ char ref[20], buf[20];
+ memset(ref, 'X', sizeof(ref));
+ memcpy(buf, ref, sizeof(buf));
+
+ // A negative buffer size should always result in an error.
+ EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), text));
+ EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+ // Zero buffer size should always result in an error.
+ EXPECT_EQ(-1, SafeSNPrintf(buf, 0, text));
+ EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+ // A one-byte buffer should always print a single NUL byte.
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 1, text));
+ EXPECT_EQ(0, buf[0]);
+ EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
+ memcpy(buf, ref, sizeof(buf));
+
+ // A larger (but limited) buffer should always leave the trailing bytes
+ // unchanged.
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 2, text));
+ EXPECT_EQ(text[0], buf[0]);
+ EXPECT_EQ(0, buf[1]);
+ EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
+ memcpy(buf, ref, sizeof(buf));
+
+ // A unrestricted buffer length should always leave the trailing bytes
+ // unchanged.
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+ SafeSNPrintf(buf, sizeof(buf), text));
+ EXPECT_EQ(std::string(text), std::string(buf));
+ EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+ sizeof(buf) - sizeof(text)));
+ memcpy(buf, ref, sizeof(buf));
+
+ // The same test using SafeSPrintf() instead of SafeSNPrintf().
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, text));
+ EXPECT_EQ(std::string(text), std::string(buf));
+ EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+ sizeof(buf) - sizeof(text)));
+ memcpy(buf, ref, sizeof(buf));
+
+ // Check for deduplication of '%' percent characters.
+ EXPECT_EQ(1, SafeSPrintf(buf, "%%"));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%%%"));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%X"));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%%%%X"));
+#if defined(NDEBUG)
+ EXPECT_EQ(1, SafeSPrintf(buf, "%"));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%X"));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%%%X"));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, "%"), "src.1. == '%'");
+ EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
+ EXPECT_DEATH(SafeSPrintf(buf, "%X"), "src.1. == '%'");
+ EXPECT_DEATH(SafeSPrintf(buf, "%%%X"), "src.1. == '%'");
+#endif
+}
+
+TEST(SafeSPrintfTest, OneArgument) {
+ // Test basic single-argument single-character substitution.
+ const char text[] = "hello world";
+ const char fmt[] = "hello%cworld";
+ char ref[20], buf[20];
+ memset(ref, 'X', sizeof(buf));
+ memcpy(buf, ref, sizeof(buf));
+
+ // A negative buffer size should always result in an error.
+ EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), fmt, ' '));
+ EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+ // Zero buffer size should always result in an error.
+ EXPECT_EQ(-1, SafeSNPrintf(buf, 0, fmt, ' '));
+ EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+ // A one-byte buffer should always print a single NUL byte.
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+ SafeSNPrintf(buf, 1, fmt, ' '));
+ EXPECT_EQ(0, buf[0]);
+ EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
+ memcpy(buf, ref, sizeof(buf));
+
+ // A larger (but limited) buffer should always leave the trailing bytes
+ // unchanged.
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+ SafeSNPrintf(buf, 2, fmt, ' '));
+ EXPECT_EQ(text[0], buf[0]);
+ EXPECT_EQ(0, buf[1]);
+ EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
+ memcpy(buf, ref, sizeof(buf));
+
+ // A unrestricted buffer length should always leave the trailing bytes
+ // unchanged.
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+ SafeSNPrintf(buf, sizeof(buf), fmt, ' '));
+ EXPECT_EQ(std::string(text), std::string(buf));
+ EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+ sizeof(buf) - sizeof(text)));
+ memcpy(buf, ref, sizeof(buf));
+
+ // The same test using SafeSPrintf() instead of SafeSNPrintf().
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, fmt, ' '));
+ EXPECT_EQ(std::string(text), std::string(buf));
+ EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+ sizeof(buf) - sizeof(text)));
+ memcpy(buf, ref, sizeof(buf));
+
+ // Check for deduplication of '%' percent characters.
+ EXPECT_EQ(1, SafeSPrintf(buf, "%%", 0));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%%%", 0));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%Y", 0));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%Y", 0));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%%%Y", 0));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%%%%Y", 0));
+#if defined(NDEBUG)
+ EXPECT_EQ(1, SafeSPrintf(buf, "%", 0));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, "%", 0), "ch");
+ EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
+#endif
+}
+
+TEST(SafeSPrintfTest, MissingArg) {
+#if defined(NDEBUG)
+ char buf[20];
+ EXPECT_EQ(3, SafeSPrintf(buf, "%c%c", 'A'));
+ EXPECT_EQ("A%c", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ char buf[20];
+ EXPECT_DEATH(SafeSPrintf(buf, "%c%c", 'A'), "cur_arg < max_args");
+#endif
+}
+
+TEST(SafeSPrintfTest, ASANFriendlyBufferTest) {
+ // Print into a buffer that is sized exactly to size. ASAN can verify that
+ // nobody attempts to write past the end of the buffer.
+ // There is a more complicated test in PrintLongString() that covers a lot
+ // more edge case, but it is also harder to debug in case of a failure.
+ const char kTestString[] = "This is a test";
+ std::unique_ptr<char[]> buf(new char[sizeof(kTestString)]);
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
+ SafeSNPrintf(buf.get(), sizeof(kTestString), kTestString));
+ EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
+ EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
+ SafeSNPrintf(buf.get(), sizeof(kTestString), "%s", kTestString));
+ EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
+}
+
+TEST(SafeSPrintfTest, NArgs) {
+ // Pre-C++11 compilers have a different code path, that can only print
+ // up to ten distinct arguments.
+ // We test both SafeSPrintf() and SafeSNPrintf(). This makes sure we don't
+ // have typos in the copy-n-pasted code that is needed to deal with various
+ // numbers of arguments.
+ char buf[12];
+ EXPECT_EQ(1, SafeSPrintf(buf, "%c", 1));
+ EXPECT_EQ("\1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%c%c", 1, 2));
+ EXPECT_EQ("\1\2", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%c%c%c", 1, 2, 3));
+ EXPECT_EQ("\1\2\3", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%c%c%c%c", 1, 2, 3, 4));
+ EXPECT_EQ("\1\2\3\4", std::string(buf));
+ EXPECT_EQ(5, SafeSPrintf(buf, "%c%c%c%c%c", 1, 2, 3, 4, 5));
+ EXPECT_EQ("\1\2\3\4\5", std::string(buf));
+ EXPECT_EQ(6, SafeSPrintf(buf, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
+ EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
+ EXPECT_EQ(7, SafeSPrintf(buf, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
+ EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
+ EXPECT_EQ(8, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7, 8));
+ EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
+ EXPECT_EQ(9, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c",
+ 1, 2, 3, 4, 5, 6, 7, 8, 9));
+ EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
+ EXPECT_EQ(10, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c",
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+
+ // Repeat all the tests with SafeSNPrintf() instead of SafeSPrintf().
+ EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
+ EXPECT_EQ(1, SafeSNPrintf(buf, 11, "%c", 1));
+ EXPECT_EQ("\1", std::string(buf));
+ EXPECT_EQ(2, SafeSNPrintf(buf, 11, "%c%c", 1, 2));
+ EXPECT_EQ("\1\2", std::string(buf));
+ EXPECT_EQ(3, SafeSNPrintf(buf, 11, "%c%c%c", 1, 2, 3));
+ EXPECT_EQ("\1\2\3", std::string(buf));
+ EXPECT_EQ(4, SafeSNPrintf(buf, 11, "%c%c%c%c", 1, 2, 3, 4));
+ EXPECT_EQ("\1\2\3\4", std::string(buf));
+ EXPECT_EQ(5, SafeSNPrintf(buf, 11, "%c%c%c%c%c", 1, 2, 3, 4, 5));
+ EXPECT_EQ("\1\2\3\4\5", std::string(buf));
+ EXPECT_EQ(6, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
+ EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
+ EXPECT_EQ(7, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
+ EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
+ EXPECT_EQ(8, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c",
+ 1, 2, 3, 4, 5, 6, 7, 8));
+ EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
+ EXPECT_EQ(9, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c",
+ 1, 2, 3, 4, 5, 6, 7, 8, 9));
+ EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
+ EXPECT_EQ(10, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c%c",
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+ EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
+
+ EXPECT_EQ(11, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c%c",
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+ EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
+ EXPECT_EQ(11, SafeSNPrintf(buf, 12, "%c%c%c%c%c%c%c%c%c%c%c",
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+ EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
+}
+
+TEST(SafeSPrintfTest, DataTypes) {
+ char buf[40];
+
+ // Bytes
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint8_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%d", (uint8_t)-1));
+ EXPECT_EQ("255", std::string(buf));
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int8_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int8_t)-1));
+ EXPECT_EQ("-1", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%d", (int8_t)-128));
+ EXPECT_EQ("-128", std::string(buf));
+
+ // Half-words
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint16_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(5, SafeSPrintf(buf, "%d", (uint16_t)-1));
+ EXPECT_EQ("65535", std::string(buf));
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int16_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int16_t)-1));
+ EXPECT_EQ("-1", std::string(buf));
+ EXPECT_EQ(6, SafeSPrintf(buf, "%d", (int16_t)-32768));
+ EXPECT_EQ("-32768", std::string(buf));
+
+ // Words
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint32_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(10, SafeSPrintf(buf, "%d", (uint32_t)-1));
+ EXPECT_EQ("4294967295", std::string(buf));
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int32_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int32_t)-1));
+ EXPECT_EQ("-1", std::string(buf));
+ // Work-around for an limitation of C90
+ EXPECT_EQ(11, SafeSPrintf(buf, "%d", (int32_t)-2147483647-1));
+ EXPECT_EQ("-2147483648", std::string(buf));
+
+ // Quads
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint64_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(20, SafeSPrintf(buf, "%d", (uint64_t)-1));
+ EXPECT_EQ("18446744073709551615", std::string(buf));
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int64_t)1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int64_t)-1));
+ EXPECT_EQ("-1", std::string(buf));
+ // Work-around for an limitation of C90
+ EXPECT_EQ(20, SafeSPrintf(buf, "%d", (int64_t)-9223372036854775807LL-1));
+ EXPECT_EQ("-9223372036854775808", std::string(buf));
+
+ // Strings (both const and mutable).
+ EXPECT_EQ(4, SafeSPrintf(buf, "test"));
+ EXPECT_EQ("test", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, buf));
+ EXPECT_EQ("test", std::string(buf));
+
+ // Pointer
+ char addr[20];
+ sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
+ SafeSPrintf(buf, "%p", buf);
+ EXPECT_EQ(std::string(addr), std::string(buf));
+ SafeSPrintf(buf, "%p", (const char *)buf);
+ EXPECT_EQ(std::string(addr), std::string(buf));
+ sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)sprintf);
+ SafeSPrintf(buf, "%p", sprintf);
+ EXPECT_EQ(std::string(addr), std::string(buf));
+
+ // Padding for pointers is a little more complicated because of the "0x"
+ // prefix. Padding with '0' zeros is relatively straight-forward, but
+ // padding with ' ' spaces requires more effort.
+ sprintf(addr, "0x%017llX", (unsigned long long)(uintptr_t)buf);
+ SafeSPrintf(buf, "%019p", buf);
+ EXPECT_EQ(std::string(addr), std::string(buf));
+ sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
+ memset(addr, ' ',
+ (char*)memmove(addr + sizeof(addr) - strlen(addr) - 1,
+ addr, strlen(addr)+1) - addr);
+ SafeSPrintf(buf, "%19p", buf);
+ EXPECT_EQ(std::string(addr), std::string(buf));
+}
+
+namespace {
+void PrintLongString(char* buf, size_t sz) {
+ // Output a reasonably complex expression into a limited-size buffer.
+ // At least one byte is available for writing the NUL character.
+ CHECK_GT(sz, static_cast<size_t>(0));
+
+ // Allocate slightly more space, so that we can verify that SafeSPrintf()
+ // never writes past the end of the buffer.
+ std::unique_ptr<char[]> tmp(new char[sz + 2]);
+ memset(tmp.get(), 'X', sz+2);
+
+ // Use SafeSPrintf() to output a complex list of arguments:
+ // - test padding and truncating %c single characters.
+ // - test truncating %s simple strings.
+ // - test mismatching arguments and truncating (for %d != %s).
+ // - test zero-padding and truncating %x hexadecimal numbers.
+ // - test outputting and truncating %d MININT.
+ // - test outputting and truncating %p arbitrary pointer values.
+ // - test outputting, padding and truncating NULL-pointer %s strings.
+ char* out = tmp.get();
+ size_t out_sz = sz;
+ size_t len;
+ for (std::unique_ptr<char[]> perfect_buf;;) {
+ size_t needed =
+ SafeSNPrintf(out, out_sz,
+#if defined(NDEBUG)
+ "A%2cong %s: %d %010X %d %p%7s", 'l', "string", "",
+#else
+ "A%2cong %s: %%d %010X %d %p%7s", 'l', "string",
+#endif
+ 0xDEADBEEF, std::numeric_limits<intptr_t>::min(),
+ PrintLongString, static_cast<char*>(nullptr)) +
+ 1;
+
+ // Various sanity checks:
+ // The numbered of characters needed to print the full string should always
+ // be bigger or equal to the bytes that have actually been output.
+ len = strlen(tmp.get());
+ CHECK_GE(needed, len+1);
+
+ // The number of characters output should always fit into the buffer that
+ // was passed into SafeSPrintf().
+ CHECK_LT(len, out_sz);
+
+ // The output is always terminated with a NUL byte (actually, this test is
+ // always going to pass, as strlen() already verified this)
+ EXPECT_FALSE(tmp[len]);
+
+ // ASAN can check that we are not overwriting buffers, iff we make sure the
+ // buffer is exactly the size that we are expecting to be written. After
+ // running SafeSNPrintf() the first time, it is possible to compute the
+ // correct buffer size for this test. So, allocate a second buffer and run
+ // the exact same SafeSNPrintf() command again.
+ if (!perfect_buf.get()) {
+ out_sz = std::min(needed, sz);
+ out = new char[out_sz];
+ perfect_buf.reset(out);
+ } else {
+ break;
+ }
+ }
+
+ // All trailing bytes are unchanged.
+ for (size_t i = len+1; i < sz+2; ++i)
+ EXPECT_EQ('X', tmp[i]);
+
+ // The text that was generated by SafeSPrintf() should always match the
+ // equivalent text generated by sprintf(). Please note that the format
+ // string for sprintf() is not complicated, as it does not have the
+ // benefit of getting type information from the C++ compiler.
+ //
+ // N.B.: It would be so much cleaner to use snprintf(). But unfortunately,
+ // Visual Studio doesn't support this function, and the work-arounds
+ // are all really awkward.
+ char ref[256];
+ CHECK_LE(sz, sizeof(ref));
+ sprintf(ref, "A long string: %%d 00DEADBEEF %lld 0x%llX <NULL>",
+ static_cast<long long>(std::numeric_limits<intptr_t>::min()),
+ static_cast<unsigned long long>(
+ reinterpret_cast<uintptr_t>(PrintLongString)));
+ ref[sz-1] = '\000';
+
+#if defined(NDEBUG)
+ const size_t kSSizeMax = std::numeric_limits<ssize_t>::max();
+#else
+ const size_t kSSizeMax = internal::GetSafeSPrintfSSizeMaxForTest();
+#endif
+
+ // Compare the output from SafeSPrintf() to the one from sprintf().
+ EXPECT_EQ(std::string(ref).substr(0, kSSizeMax-1), std::string(tmp.get()));
+
+ // We allocated a slightly larger buffer, so that we could perform some
+ // extra sanity checks. Now that the tests have all passed, we copy the
+ // data to the output buffer that the caller provided.
+ memcpy(buf, tmp.get(), len+1);
+}
+
+#if !defined(NDEBUG)
+class ScopedSafeSPrintfSSizeMaxSetter {
+ public:
+ ScopedSafeSPrintfSSizeMaxSetter(size_t sz) {
+ old_ssize_max_ = internal::GetSafeSPrintfSSizeMaxForTest();
+ internal::SetSafeSPrintfSSizeMaxForTest(sz);
+ }
+
+ ~ScopedSafeSPrintfSSizeMaxSetter() {
+ internal::SetSafeSPrintfSSizeMaxForTest(old_ssize_max_);
+ }
+
+ private:
+ size_t old_ssize_max_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSafeSPrintfSSizeMaxSetter);
+};
+#endif
+
+} // anonymous namespace
+
+TEST(SafeSPrintfTest, Truncation) {
+ // We use PrintLongString() to print a complex long string and then
+ // truncate to all possible lengths. This ends up exercising a lot of
+ // different code paths in SafeSPrintf() and IToASCII(), as truncation can
+ // happen in a lot of different states.
+ char ref[256];
+ PrintLongString(ref, sizeof(ref));
+ for (size_t i = strlen(ref)+1; i; --i) {
+ char buf[sizeof(ref)];
+ PrintLongString(buf, i);
+ EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
+ }
+
+ // When compiling in debug mode, we have the ability to fake a small
+ // upper limit for the maximum value that can be stored in an ssize_t.
+ // SafeSPrintf() uses this upper limit to determine how many bytes it will
+ // write to the buffer, even if the caller claimed a bigger buffer size.
+ // Repeat the truncation test and verify that this other code path in
+ // SafeSPrintf() works correctly, too.
+#if !defined(NDEBUG)
+ for (size_t i = strlen(ref)+1; i > 1; --i) {
+ ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(i);
+ char buf[sizeof(ref)];
+ PrintLongString(buf, sizeof(buf));
+ EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
+ }
+
+ // kSSizeMax is also used to constrain the maximum amount of padding, before
+ // SafeSPrintf() detects an error in the format string.
+ ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(100);
+ char buf[256];
+ EXPECT_EQ(99, SafeSPrintf(buf, "%99c", ' '));
+ EXPECT_EQ(std::string(99, ' '), std::string(buf));
+ *buf = '\000';
+#if defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, "%100c", ' '), "padding <= max_padding");
+#endif
+ EXPECT_EQ(0, *buf);
+#endif
+}
+
+TEST(SafeSPrintfTest, Padding) {
+ char buf[40], fmt[40];
+
+ // Chars %c
+ EXPECT_EQ(1, SafeSPrintf(buf, "%c", 'A'));
+ EXPECT_EQ("A", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%2c", 'A'));
+ EXPECT_EQ(" A", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%02c", 'A'));
+ EXPECT_EQ(" A", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%-2c", 'A'));
+ EXPECT_EQ("%-2c", std::string(buf));
+ SafeSPrintf(fmt, "%%%dc", std::numeric_limits<ssize_t>::max() - 1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, SafeSPrintf(buf, fmt, 'A'));
+ SafeSPrintf(fmt, "%%%dc",
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+ EXPECT_EQ(2, SafeSPrintf(buf, fmt, 'A'));
+ EXPECT_EQ("%c", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, fmt, 'A'), "padding <= max_padding");
+#endif
+
+ // Octal %o
+ EXPECT_EQ(1, SafeSPrintf(buf, "%o", 1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%2o", 1));
+ EXPECT_EQ(" 1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%02o", 1));
+ EXPECT_EQ("01", std::string(buf));
+ EXPECT_EQ(12, SafeSPrintf(buf, "%12o", -1));
+ EXPECT_EQ(" 37777777777", std::string(buf));
+ EXPECT_EQ(12, SafeSPrintf(buf, "%012o", -1));
+ EXPECT_EQ("037777777777", std::string(buf));
+ EXPECT_EQ(23, SafeSPrintf(buf, "%23o", -1LL));
+ EXPECT_EQ(" 1777777777777777777777", std::string(buf));
+ EXPECT_EQ(23, SafeSPrintf(buf, "%023o", -1LL));
+ EXPECT_EQ("01777777777777777777777", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%2o", 0111));
+ EXPECT_EQ("111", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%-2o", 1));
+ EXPECT_EQ("%-2o", std::string(buf));
+ SafeSPrintf(fmt, "%%%do", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, 1));
+ EXPECT_EQ(" ", std::string(buf));
+ SafeSPrintf(fmt, "%%0%do", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, 1));
+ EXPECT_EQ("000", std::string(buf));
+ SafeSPrintf(fmt, "%%%do",
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+ EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+ EXPECT_EQ("%o", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+ // Decimals %d
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", 1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%2d", 1));
+ EXPECT_EQ(" 1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%02d", 1));
+ EXPECT_EQ("01", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%3d", -1));
+ EXPECT_EQ(" -1", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%03d", -1));
+ EXPECT_EQ("-01", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%2d", 111));
+ EXPECT_EQ("111", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%2d", -111));
+ EXPECT_EQ("-111", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%-2d", 1));
+ EXPECT_EQ("%-2d", std::string(buf));
+ SafeSPrintf(fmt, "%%%dd", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, 1));
+ EXPECT_EQ(" ", std::string(buf));
+ SafeSPrintf(fmt, "%%0%dd", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, 1));
+ EXPECT_EQ("000", std::string(buf));
+ SafeSPrintf(fmt, "%%%dd",
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+ EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+ EXPECT_EQ("%d", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+ // Hex %X
+ EXPECT_EQ(1, SafeSPrintf(buf, "%X", 1));
+ EXPECT_EQ("1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%2X", 1));
+ EXPECT_EQ(" 1", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%02X", 1));
+ EXPECT_EQ("01", std::string(buf));
+ EXPECT_EQ(9, SafeSPrintf(buf, "%9X", -1));
+ EXPECT_EQ(" FFFFFFFF", std::string(buf));
+ EXPECT_EQ(9, SafeSPrintf(buf, "%09X", -1));
+ EXPECT_EQ("0FFFFFFFF", std::string(buf));
+ EXPECT_EQ(17, SafeSPrintf(buf, "%17X", -1LL));
+ EXPECT_EQ(" FFFFFFFFFFFFFFFF", std::string(buf));
+ EXPECT_EQ(17, SafeSPrintf(buf, "%017X", -1LL));
+ EXPECT_EQ("0FFFFFFFFFFFFFFFF", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%2X", 0x111));
+ EXPECT_EQ("111", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%-2X", 1));
+ EXPECT_EQ("%-2X", std::string(buf));
+ SafeSPrintf(fmt, "%%%dX", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, 1));
+ EXPECT_EQ(" ", std::string(buf));
+ SafeSPrintf(fmt, "%%0%dX", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, 1));
+ EXPECT_EQ("000", std::string(buf));
+ SafeSPrintf(fmt, "%%%dX",
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+ EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+ EXPECT_EQ("%X", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+ // Pointer %p
+ EXPECT_EQ(3, SafeSPrintf(buf, "%p", (void*)1));
+ EXPECT_EQ("0x1", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%4p", (void*)1));
+ EXPECT_EQ(" 0x1", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%04p", (void*)1));
+ EXPECT_EQ("0x01", std::string(buf));
+ EXPECT_EQ(5, SafeSPrintf(buf, "%4p", (void*)0x111));
+ EXPECT_EQ("0x111", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%-2p", (void*)1));
+ EXPECT_EQ("%-2p", std::string(buf));
+ SafeSPrintf(fmt, "%%%dp", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, (void*)1));
+ EXPECT_EQ(" ", std::string(buf));
+ SafeSPrintf(fmt, "%%0%dp", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, (void*)1));
+ EXPECT_EQ("0x0", std::string(buf));
+ SafeSPrintf(fmt, "%%%dp",
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+ EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+ EXPECT_EQ("%p", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+ // String
+ EXPECT_EQ(1, SafeSPrintf(buf, "%s", "A"));
+ EXPECT_EQ("A", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%2s", "A"));
+ EXPECT_EQ(" A", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%02s", "A"));
+ EXPECT_EQ(" A", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%2s", "AAA"));
+ EXPECT_EQ("AAA", std::string(buf));
+ EXPECT_EQ(4, SafeSPrintf(buf, "%-2s", "A"));
+ EXPECT_EQ("%-2s", std::string(buf));
+ SafeSPrintf(fmt, "%%%ds", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, "A"));
+ EXPECT_EQ(" ", std::string(buf));
+ SafeSPrintf(fmt, "%%0%ds", std::numeric_limits<ssize_t>::max()-1);
+ EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+ SafeSNPrintf(buf, 4, fmt, "A"));
+ EXPECT_EQ(" ", std::string(buf));
+ SafeSPrintf(fmt, "%%%ds",
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+ EXPECT_EQ(2, SafeSPrintf(buf, fmt, "A"));
+ EXPECT_EQ("%s", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, fmt, "A"), "padding <= max_padding");
+#endif
+}
+
+TEST(SafeSPrintfTest, EmbeddedNul) {
+ char buf[] = { 'X', 'X', 'X', 'X' };
+ EXPECT_EQ(2, SafeSPrintf(buf, "%3c", 0));
+ EXPECT_EQ(' ', buf[0]);
+ EXPECT_EQ(' ', buf[1]);
+ EXPECT_EQ(0, buf[2]);
+ EXPECT_EQ('X', buf[3]);
+
+ // Check handling of a NUL format character. N.B. this takes two different
+ // code paths depending on whether we are actually passing arguments. If
+ // we don't have any arguments, we are running in the fast-path code, that
+ // looks (almost) like a strncpy().
+#if defined(NDEBUG)
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
+ EXPECT_EQ("%%", std::string(buf));
+ EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
+ EXPECT_EQ("%%", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+ EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
+ EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
+#endif
+}
+
+TEST(SafeSPrintfTest, EmitNULL) {
+ char buf[40];
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion-null"
+#endif
+ EXPECT_EQ(1, SafeSPrintf(buf, "%d", NULL));
+ EXPECT_EQ("0", std::string(buf));
+ EXPECT_EQ(3, SafeSPrintf(buf, "%p", NULL));
+ EXPECT_EQ("0x0", std::string(buf));
+ EXPECT_EQ(6, SafeSPrintf(buf, "%s", NULL));
+ EXPECT_EQ("<NULL>", std::string(buf));
+#if defined(__GCC__)
+#pragma GCC diagnostic pop
+#endif
+}
+
+TEST(SafeSPrintfTest, PointerSize) {
+ // The internal data representation is a 64bit value, independent of the
+ // native word size. We want to perform sign-extension for signed integers,
+ // but we want to avoid doing so for pointer types. This could be a
+ // problem on systems, where pointers are only 32bit. This tests verifies
+ // that there is no such problem.
+ char *str = reinterpret_cast<char *>(0x80000000u);
+ void *ptr = str;
+ char buf[40];
+ EXPECT_EQ(10, SafeSPrintf(buf, "%p", str));
+ EXPECT_EQ("0x80000000", std::string(buf));
+ EXPECT_EQ(10, SafeSPrintf(buf, "%p", ptr));
+ EXPECT_EQ("0x80000000", std::string(buf));
+}
+
+} // namespace strings
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/string16.cc b/security/sandbox/chromium/base/strings/string16.cc
new file mode 100644
index 0000000000..84962e6710
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string16.cc
@@ -0,0 +1,87 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string16.h"
+
+#if defined(WCHAR_T_IS_UTF16) && !defined(_AIX)
+
+#error This file should not be used on 2-byte wchar_t systems
+// If this winds up being needed on 2-byte wchar_t systems, either the
+// definitions below can be used, or the host system's wide character
+// functions like wmemcmp can be wrapped.
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+#include <ostream>
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+int c16memcmp(const char16* s1, const char16* s2, size_t n) {
+ // We cannot call memcmp because that changes the semantics.
+ while (n-- > 0) {
+ if (*s1 != *s2) {
+ // We cannot use (*s1 - *s2) because char16 is unsigned.
+ return ((*s1 < *s2) ? -1 : 1);
+ }
+ ++s1;
+ ++s2;
+ }
+ return 0;
+}
+
+size_t c16len(const char16* s) {
+ const char16 *s_orig = s;
+ while (*s) {
+ ++s;
+ }
+ return s - s_orig;
+}
+
+const char16* c16memchr(const char16* s, char16 c, size_t n) {
+ while (n-- > 0) {
+ if (*s == c) {
+ return s;
+ }
+ ++s;
+ }
+ return nullptr;
+}
+
+char16* c16memmove(char16* s1, const char16* s2, size_t n) {
+ return static_cast<char16*>(memmove(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memcpy(char16* s1, const char16* s2, size_t n) {
+ return static_cast<char16*>(memcpy(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memset(char16* s, char16 c, size_t n) {
+ char16 *s_orig = s;
+ while (n-- > 0) {
+ *s = c;
+ ++s;
+ }
+ return s_orig;
+}
+
+namespace string16_internals {
+
+std::ostream& operator<<(std::ostream& out, const string16& str) {
+ return out << base::StringPiece16(str);
+}
+
+void PrintTo(const string16& str, std::ostream* out) {
+ *out << str;
+}
+
+} // namespace string16_internals
+
+} // namespace base
+
+template class std::
+ basic_string<base::char16, base::string16_internals::string16_char_traits>;
+
+#endif // WCHAR_T_IS_UTF32
diff --git a/security/sandbox/chromium/base/strings/string16.h b/security/sandbox/chromium/base/strings/string16.h
new file mode 100644
index 0000000000..3cb6c7c495
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string16.h
@@ -0,0 +1,229 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING16_H_
+#define BASE_STRINGS_STRING16_H_
+
+// WHAT:
+// A version of std::basic_string that provides 2-byte characters even when
+// wchar_t is not implemented as a 2-byte type. You can access this class as
+// string16. We also define char16, which string16 is based upon.
+//
+// WHY:
+// On Windows, wchar_t is 2 bytes, and it can conveniently handle UTF-16/UCS-2
+// data. Plenty of existing code operates on strings encoded as UTF-16.
+//
+// On many other platforms, sizeof(wchar_t) is 4 bytes by default. We can make
+// it 2 bytes by using the GCC flag -fshort-wchar. But then std::wstring fails
+// at run time, because it calls some functions (like wcslen) that come from
+// the system's native C library -- which was built with a 4-byte wchar_t!
+// It's wasteful to use 4-byte wchar_t strings to carry UTF-16 data, and it's
+// entirely improper on those systems where the encoding of wchar_t is defined
+// as UTF-32.
+//
+// Here, we define string16, which is similar to std::wstring but replaces all
+// libc functions with custom, 2-byte-char compatible routines. It is capable
+// of carrying UTF-16-encoded data.
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <functional>
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+// Define a macro for wrapping construction of char16 arrays and string16s from
+// a literal string. This indirection allows for an easier migration of
+// base::char16 to char16_t on platforms where WCHAR_T_IS_UTF16, as only a one
+// character change to the macro will be necessary.
+// This macro does not exist when WCHAR_T_IS_UTF32, as it is currently not
+// possible to create a char array form a literal in this case.
+// TODO(https://crbug.com/911896): Remove this macro once base::char16 is
+// char16_t on all platforms.
+#define STRING16_LITERAL(x) L##x
+
+namespace base {
+
+typedef wchar_t char16;
+typedef std::wstring string16;
+
+} // namespace base
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+#include <wchar.h> // for mbstate_t
+
+namespace base {
+
+typedef uint16_t char16;
+
+// char16 versions of the functions required by string16_char_traits; these
+// are based on the wide character functions of similar names ("w" or "wcs"
+// instead of "c16").
+BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n);
+BASE_EXPORT size_t c16len(const char16* s);
+BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n);
+BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n);
+
+// This namespace contains the implementation of base::string16 along with
+// things that need to be found via argument-dependent lookup from a
+// base::string16.
+namespace string16_internals {
+
+struct string16_char_traits {
+ typedef char16 char_type;
+ typedef int int_type;
+
+ // int_type needs to be able to hold each possible value of char_type, and in
+ // addition, the distinct value of eof().
+ static_assert(sizeof(int_type) > sizeof(char_type),
+ "int must be larger than 16 bits wide");
+
+ typedef std::streamoff off_type;
+ typedef mbstate_t state_type;
+ typedef std::fpos<state_type> pos_type;
+
+ static void assign(char_type& c1, const char_type& c2) {
+ c1 = c2;
+ }
+
+ static bool eq(const char_type& c1, const char_type& c2) {
+ return c1 == c2;
+ }
+ static bool lt(const char_type& c1, const char_type& c2) {
+ return c1 < c2;
+ }
+
+ static int compare(const char_type* s1, const char_type* s2, size_t n) {
+ return c16memcmp(s1, s2, n);
+ }
+
+ static size_t length(const char_type* s) {
+ return c16len(s);
+ }
+
+ static const char_type* find(const char_type* s, size_t n,
+ const char_type& a) {
+ return c16memchr(s, a, n);
+ }
+
+ static char_type* move(char_type* s1, const char_type* s2, size_t n) {
+ return c16memmove(s1, s2, n);
+ }
+
+ static char_type* copy(char_type* s1, const char_type* s2, size_t n) {
+ return c16memcpy(s1, s2, n);
+ }
+
+ static char_type* assign(char_type* s, size_t n, char_type a) {
+ return c16memset(s, a, n);
+ }
+
+ static int_type not_eof(const int_type& c) {
+ return eq_int_type(c, eof()) ? 0 : c;
+ }
+
+ static char_type to_char_type(const int_type& c) {
+ return char_type(c);
+ }
+
+ static int_type to_int_type(const char_type& c) {
+ return int_type(c);
+ }
+
+ static bool eq_int_type(const int_type& c1, const int_type& c2) {
+ return c1 == c2;
+ }
+
+ static int_type eof() {
+ return static_cast<int_type>(EOF);
+ }
+};
+
+} // namespace string16_internals
+
+typedef std::basic_string<char16,
+ base::string16_internals::string16_char_traits>
+ string16;
+
+namespace string16_internals {
+
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& out,
+ const string16& str);
+
+// This is required by googletest to print a readable output on test failures.
+BASE_EXPORT extern void PrintTo(const string16& str, std::ostream* out);
+
+} // namespace string16_internals
+
+} // namespace base
+
+// The string class will be explicitly instantiated only once, in string16.cc.
+//
+// std::basic_string<> in GNU libstdc++ contains a static data member,
+// _S_empty_rep_storage, to represent empty strings. When an operation such
+// as assignment or destruction is performed on a string, causing its existing
+// data member to be invalidated, it must not be freed if this static data
+// member is being used. Otherwise, it counts as an attempt to free static
+// (and not allocated) data, which is a memory error.
+//
+// Generally, due to C++ template magic, _S_empty_rep_storage will be marked
+// as a coalesced symbol, meaning that the linker will combine multiple
+// instances into a single one when generating output.
+//
+// If a string class is used by multiple shared libraries, a problem occurs.
+// Each library will get its own copy of _S_empty_rep_storage. When strings
+// are passed across a library boundary for alteration or destruction, memory
+// errors will result. GNU libstdc++ contains a configuration option,
+// --enable-fully-dynamic-string (_GLIBCXX_FULLY_DYNAMIC_STRING), which
+// disables the static data member optimization, but it's a good optimization
+// and non-STL code is generally at the mercy of the system's STL
+// configuration. Fully-dynamic strings are not the default for GNU libstdc++
+// libstdc++ itself or for the libstdc++ installations on the systems we care
+// about, such as Mac OS X and relevant flavors of Linux.
+//
+// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24196 .
+//
+// To avoid problems, string classes need to be explicitly instantiated only
+// once, in exactly one library. All other string users see it via an "extern"
+// declaration. This is precisely how GNU libstdc++ handles
+// std::basic_string<char> (string) and std::basic_string<wchar_t> (wstring).
+//
+// This also works around a Mac OS X linker bug in ld64-85.2.1 (Xcode 3.1.2),
+// in which the linker does not fully coalesce symbols when dead code
+// stripping is enabled. This bug causes the memory errors described above
+// to occur even when a std::basic_string<> does not cross shared library
+// boundaries, such as in statically-linked executables.
+//
+// TODO(mark): File this bug with Apple and update this note with a bug number.
+
+extern template class BASE_EXPORT
+ std::basic_string<base::char16,
+ base::string16_internals::string16_char_traits>;
+
+// Specialize std::hash for base::string16. Although the style guide forbids
+// this in general, it is necessary for consistency with WCHAR_T_IS_UTF16
+// platforms, where base::string16 is a type alias for std::wstring.
+namespace std {
+template <>
+struct hash<base::string16> {
+ std::size_t operator()(const base::string16& s) const {
+ std::size_t result = 0;
+ for (base::char16 c : s)
+ result = (result * 131) + c;
+ return result;
+ }
+};
+} // namespace std
+
+#endif // WCHAR_T_IS_UTF32
+
+#endif // BASE_STRINGS_STRING16_H_
diff --git a/security/sandbox/chromium/base/strings/string_number_conversions.cc b/security/sandbox/chromium/base/strings/string_number_conversions.cc
new file mode 100644
index 0000000000..3b5eda1fe3
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_number_conversions.cc
@@ -0,0 +1,545 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_number_conversions.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <wctype.h>
+
+#include <limits>
+#include <type_traits>
+
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "double-conversion/double-conversion.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT>
+struct IntToStringT {
+ static STR IntToString(INT value) {
+ // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
+ // So round up to allocate 3 output characters per byte, plus 1 for '-'.
+ const size_t kOutputBufSize =
+ 3 * sizeof(INT) + std::numeric_limits<INT>::is_signed;
+
+ // Create the string in a temporary buffer, write it back to front, and
+ // then return the substr of what we ended up using.
+ using CHR = typename STR::value_type;
+ CHR outbuf[kOutputBufSize];
+
+ // The ValueOrDie call below can never fail, because UnsignedAbs is valid
+ // for all valid inputs.
+ typename std::make_unsigned<INT>::type res =
+ CheckedNumeric<INT>(value).UnsignedAbs().ValueOrDie();
+
+ CHR* end = outbuf + kOutputBufSize;
+ CHR* i = end;
+ do {
+ --i;
+ DCHECK(i != outbuf);
+ *i = static_cast<CHR>((res % 10) + '0');
+ res /= 10;
+ } while (res != 0);
+ if (IsValueNegative(value)) {
+ --i;
+ DCHECK(i != outbuf);
+ *i = static_cast<CHR>('-');
+ }
+ return STR(i, end);
+ }
+};
+
+// Utility to convert a character to a digit in a given base
+template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
+};
+
+// Faster specialization for bases <= 10
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
+ public:
+ static bool Convert(CHAR c, uint8_t* digit) {
+ if (c >= '0' && c < '0' + BASE) {
+ *digit = static_cast<uint8_t>(c - '0');
+ return true;
+ }
+ return false;
+ }
+};
+
+// Specialization for bases where 10 < base <= 36
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
+ public:
+ static bool Convert(CHAR c, uint8_t* digit) {
+ if (c >= '0' && c <= '9') {
+ *digit = c - '0';
+ } else if (c >= 'a' && c < 'a' + BASE - 10) {
+ *digit = c - 'a' + 10;
+ } else if (c >= 'A' && c < 'A' + BASE - 10) {
+ *digit = c - 'A' + 10;
+ } else {
+ return false;
+ }
+ return true;
+ }
+};
+
+template <int BASE, typename CHAR>
+bool CharToDigit(CHAR c, uint8_t* digit) {
+ return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
+}
+
+// There is an IsUnicodeWhitespace for wchars defined in string_util.h, but it
+// is locale independent, whereas the functions we are replacing were
+// locale-dependent. TBD what is desired, but for the moment let's not
+// introduce a change in behaviour.
+template<typename CHAR> class WhitespaceHelper {
+};
+
+template<> class WhitespaceHelper<char> {
+ public:
+ static bool Invoke(char c) {
+ return 0 != isspace(static_cast<unsigned char>(c));
+ }
+};
+
+template<> class WhitespaceHelper<char16> {
+ public:
+ static bool Invoke(char16 c) {
+ return 0 != iswspace(c);
+ }
+};
+
+template<typename CHAR> bool LocalIsWhitespace(CHAR c) {
+ return WhitespaceHelper<CHAR>::Invoke(c);
+}
+
+// IteratorRangeToNumberTraits should provide:
+// - a typedef for iterator_type, the iterator type used as input.
+// - a typedef for value_type, the target numeric type.
+// - static functions min, max (returning the minimum and maximum permitted
+// values)
+// - constant kBase, the base in which to interpret the input
+template<typename IteratorRangeToNumberTraits>
+class IteratorRangeToNumber {
+ public:
+ typedef IteratorRangeToNumberTraits traits;
+ typedef typename traits::iterator_type const_iterator;
+ typedef typename traits::value_type value_type;
+
+ // Generalized iterator-range-to-number conversion.
+ //
+ static bool Invoke(const_iterator begin,
+ const_iterator end,
+ value_type* output) {
+ bool valid = true;
+
+ while (begin != end && LocalIsWhitespace(*begin)) {
+ valid = false;
+ ++begin;
+ }
+
+ if (begin != end && *begin == '-') {
+ if (!std::numeric_limits<value_type>::is_signed) {
+ *output = 0;
+ valid = false;
+ } else if (!Negative::Invoke(begin + 1, end, output)) {
+ valid = false;
+ }
+ } else {
+ if (begin != end && *begin == '+') {
+ ++begin;
+ }
+ if (!Positive::Invoke(begin, end, output)) {
+ valid = false;
+ }
+ }
+
+ return valid;
+ }
+
+ private:
+ // Sign provides:
+ // - a static function, CheckBounds, that determines whether the next digit
+ // causes an overflow/underflow
+ // - a static function, Increment, that appends the next digit appropriately
+ // according to the sign of the number being parsed.
+ template<typename Sign>
+ class Base {
+ public:
+ static bool Invoke(const_iterator begin, const_iterator end,
+ typename traits::value_type* output) {
+ *output = 0;
+
+ if (begin == end) {
+ return false;
+ }
+
+ // Note: no performance difference was found when using template
+ // specialization to remove this check in bases other than 16
+ if (traits::kBase == 16 && end - begin > 2 && *begin == '0' &&
+ (*(begin + 1) == 'x' || *(begin + 1) == 'X')) {
+ begin += 2;
+ }
+
+ for (const_iterator current = begin; current != end; ++current) {
+ uint8_t new_digit = 0;
+
+ if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
+ return false;
+ }
+
+ if (current != begin) {
+ if (!Sign::CheckBounds(output, new_digit)) {
+ return false;
+ }
+ *output *= traits::kBase;
+ }
+
+ Sign::Increment(new_digit, output);
+ }
+ return true;
+ }
+ };
+
+ class Positive : public Base<Positive> {
+ public:
+ static bool CheckBounds(value_type* output, uint8_t new_digit) {
+ if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
+ (*output == static_cast<value_type>(traits::max() / traits::kBase) &&
+ new_digit > traits::max() % traits::kBase)) {
+ *output = traits::max();
+ return false;
+ }
+ return true;
+ }
+ static void Increment(uint8_t increment, value_type* output) {
+ *output += increment;
+ }
+ };
+
+ class Negative : public Base<Negative> {
+ public:
+ static bool CheckBounds(value_type* output, uint8_t new_digit) {
+ if (*output < traits::min() / traits::kBase ||
+ (*output == traits::min() / traits::kBase &&
+ new_digit > 0 - traits::min() % traits::kBase)) {
+ *output = traits::min();
+ return false;
+ }
+ return true;
+ }
+ static void Increment(uint8_t increment, value_type* output) {
+ *output -= increment;
+ }
+ };
+};
+
+template<typename ITERATOR, typename VALUE, int BASE>
+class BaseIteratorRangeToNumberTraits {
+ public:
+ typedef ITERATOR iterator_type;
+ typedef VALUE value_type;
+ static value_type min() {
+ return std::numeric_limits<value_type>::min();
+ }
+ static value_type max() {
+ return std::numeric_limits<value_type>::max();
+ }
+ static const int kBase = BASE;
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToIntTraits
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
+};
+
+template <typename ITERATOR>
+class BaseHexIteratorRangeToUIntTraits
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32_t, 16> {};
+
+template <typename ITERATOR>
+class BaseHexIteratorRangeToInt64Traits
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, int64_t, 16> {};
+
+template <typename ITERATOR>
+class BaseHexIteratorRangeToUInt64Traits
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64_t, 16> {};
+
+typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
+ HexIteratorRangeToIntTraits;
+
+typedef BaseHexIteratorRangeToUIntTraits<StringPiece::const_iterator>
+ HexIteratorRangeToUIntTraits;
+
+typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
+ HexIteratorRangeToInt64Traits;
+
+typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
+ HexIteratorRangeToUInt64Traits;
+
+template <typename VALUE, int BASE>
+class StringPieceToNumberTraits
+ : public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator,
+ VALUE,
+ BASE> {
+};
+
+template <typename VALUE>
+bool StringToIntImpl(StringPiece input, VALUE* output) {
+ return IteratorRangeToNumber<StringPieceToNumberTraits<VALUE, 10> >::Invoke(
+ input.begin(), input.end(), output);
+}
+
+template <typename VALUE, int BASE>
+class StringPiece16ToNumberTraits
+ : public BaseIteratorRangeToNumberTraits<StringPiece16::const_iterator,
+ VALUE,
+ BASE> {
+};
+
+template <typename VALUE>
+bool String16ToIntImpl(StringPiece16 input, VALUE* output) {
+ return IteratorRangeToNumber<StringPiece16ToNumberTraits<VALUE, 10> >::Invoke(
+ input.begin(), input.end(), output);
+}
+
+} // namespace
+
+std::string NumberToString(int value) {
+ return IntToStringT<std::string, int>::IntToString(value);
+}
+
+string16 NumberToString16(int value) {
+ return IntToStringT<string16, int>::IntToString(value);
+}
+
+std::string NumberToString(unsigned value) {
+ return IntToStringT<std::string, unsigned>::IntToString(value);
+}
+
+string16 NumberToString16(unsigned value) {
+ return IntToStringT<string16, unsigned>::IntToString(value);
+}
+
+std::string NumberToString(long value) {
+ return IntToStringT<std::string, long>::IntToString(value);
+}
+
+string16 NumberToString16(long value) {
+ return IntToStringT<string16, long>::IntToString(value);
+}
+
+std::string NumberToString(unsigned long value) {
+ return IntToStringT<std::string, unsigned long>::IntToString(value);
+}
+
+string16 NumberToString16(unsigned long value) {
+ return IntToStringT<string16, unsigned long>::IntToString(value);
+}
+
+std::string NumberToString(long long value) {
+ return IntToStringT<std::string, long long>::IntToString(value);
+}
+
+string16 NumberToString16(long long value) {
+ return IntToStringT<string16, long long>::IntToString(value);
+}
+
+std::string NumberToString(unsigned long long value) {
+ return IntToStringT<std::string, unsigned long long>::IntToString(value);
+}
+
+string16 NumberToString16(unsigned long long value) {
+ return IntToStringT<string16, unsigned long long>::IntToString(value);
+}
+
+static const double_conversion::DoubleToStringConverter*
+GetDoubleToStringConverter() {
+ static NoDestructor<double_conversion::DoubleToStringConverter> converter(
+ double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
+ nullptr, nullptr, 'e', -6, 12, 0, 0);
+ return converter.get();
+}
+
+std::string NumberToString(double value) {
+ char buffer[32];
+ double_conversion::StringBuilder builder(buffer, sizeof(buffer));
+ GetDoubleToStringConverter()->ToShortest(value, &builder);
+ return std::string(buffer, builder.position());
+}
+
+base::string16 NumberToString16(double value) {
+ char buffer[32];
+ double_conversion::StringBuilder builder(buffer, sizeof(buffer));
+ GetDoubleToStringConverter()->ToShortest(value, &builder);
+
+ // The number will be ASCII. This creates the string using the "input
+ // iterator" variant which promotes from 8-bit to 16-bit via "=".
+ return base::string16(&buffer[0], &buffer[builder.position()]);
+}
+
+bool StringToInt(StringPiece input, int* output) {
+ return StringToIntImpl(input, output);
+}
+
+bool StringToInt(StringPiece16 input, int* output) {
+ return String16ToIntImpl(input, output);
+}
+
+bool StringToUint(StringPiece input, unsigned* output) {
+ return StringToIntImpl(input, output);
+}
+
+bool StringToUint(StringPiece16 input, unsigned* output) {
+ return String16ToIntImpl(input, output);
+}
+
+bool StringToInt64(StringPiece input, int64_t* output) {
+ return StringToIntImpl(input, output);
+}
+
+bool StringToInt64(StringPiece16 input, int64_t* output) {
+ return String16ToIntImpl(input, output);
+}
+
+bool StringToUint64(StringPiece input, uint64_t* output) {
+ return StringToIntImpl(input, output);
+}
+
+bool StringToUint64(StringPiece16 input, uint64_t* output) {
+ return String16ToIntImpl(input, output);
+}
+
+bool StringToSizeT(StringPiece input, size_t* output) {
+ return StringToIntImpl(input, output);
+}
+
+bool StringToSizeT(StringPiece16 input, size_t* output) {
+ return String16ToIntImpl(input, output);
+}
+
+template <typename STRING, typename CHAR>
+bool StringToDoubleImpl(STRING input, const CHAR* data, double* output) {
+ static NoDestructor<double_conversion::StringToDoubleConverter> converter(
+ double_conversion::StringToDoubleConverter::ALLOW_LEADING_SPACES |
+ double_conversion::StringToDoubleConverter::ALLOW_TRAILING_JUNK,
+ 0.0, 0, nullptr, nullptr);
+
+ int processed_characters_count;
+ *output = converter->StringToDouble(data, input.size(),
+ &processed_characters_count);
+
+ // Cases to return false:
+ // - If the input string is empty, there was nothing to parse.
+ // - If the value saturated to HUGE_VAL.
+ // - If the entire string was not processed, there are either characters
+ // remaining in the string after a parsed number, or the string does not
+ // begin with a parseable number.
+ // - If the first character is a space, there was leading whitespace
+ return !input.empty() && *output != HUGE_VAL && *output != -HUGE_VAL &&
+ static_cast<size_t>(processed_characters_count) == input.size() &&
+ !IsUnicodeWhitespace(input[0]);
+}
+
+bool StringToDouble(StringPiece input, double* output) {
+ return StringToDoubleImpl(input, input.data(), output);
+}
+
+bool StringToDouble(StringPiece16 input, double* output) {
+ return StringToDoubleImpl(
+ input, reinterpret_cast<const uint16_t*>(input.data()), output);
+}
+
+std::string HexEncode(const void* bytes, size_t size) {
+ static const char kHexChars[] = "0123456789ABCDEF";
+
+ // Each input byte creates two output hex characters.
+ std::string ret(size * 2, '\0');
+
+ for (size_t i = 0; i < size; ++i) {
+ char b = reinterpret_cast<const char*>(bytes)[i];
+ ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+ ret[(i * 2) + 1] = kHexChars[b & 0xf];
+ }
+ return ret;
+}
+
+std::string HexEncode(base::span<const uint8_t> bytes) {
+ return HexEncode(bytes.data(), bytes.size());
+}
+
+bool HexStringToInt(StringPiece input, int* output) {
+ return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+bool HexStringToUInt(StringPiece input, uint32_t* output) {
+ return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+bool HexStringToInt64(StringPiece input, int64_t* output) {
+ return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+bool HexStringToUInt64(StringPiece input, uint64_t* output) {
+ return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+template <typename Container>
+static bool HexStringToByteContainer(StringPiece input, Container* output) {
+ DCHECK_EQ(output->size(), 0u);
+ size_t count = input.size();
+ if (count == 0 || (count % 2) != 0)
+ return false;
+ for (uintptr_t i = 0; i < count / 2; ++i) {
+ uint8_t msb = 0; // most significant 4 bits
+ uint8_t lsb = 0; // least significant 4 bits
+ if (!CharToDigit<16>(input[i * 2], &msb) ||
+ !CharToDigit<16>(input[i * 2 + 1], &lsb)) {
+ return false;
+ }
+ output->push_back((msb << 4) | lsb);
+ }
+ return true;
+}
+
+bool HexStringToBytes(StringPiece input, std::vector<uint8_t>* output) {
+ return HexStringToByteContainer(input, output);
+}
+
+bool HexStringToString(StringPiece input, std::string* output) {
+ return HexStringToByteContainer(input, output);
+}
+
+bool HexStringToSpan(StringPiece input, base::span<uint8_t> output) {
+ size_t count = input.size();
+ if (count == 0 || (count % 2) != 0)
+ return false;
+
+ if (count / 2 != output.size())
+ return false;
+
+ for (uintptr_t i = 0; i < count / 2; ++i) {
+ uint8_t msb = 0; // most significant 4 bits
+ uint8_t lsb = 0; // least significant 4 bits
+ if (!CharToDigit<16>(input[i * 2], &msb) ||
+ !CharToDigit<16>(input[i * 2 + 1], &lsb)) {
+ return false;
+ }
+ output[i] = (msb << 4) | lsb;
+ }
+ return true;
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/string_number_conversions.h b/security/sandbox/chromium/base/strings/string_number_conversions.h
new file mode 100644
index 0000000000..87df24e21c
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_number_conversions.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/containers/span.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+// ----------------------------------------------------------------------------
+// IMPORTANT MESSAGE FROM YOUR SPONSOR
+//
+// This file contains no "wstring" variants. New code should use string16. If
+// you need to make old code work, use the UTF8 version and convert. Please do
+// not add wstring variants.
+//
+// Please do not add "convenience" functions for converting strings to integers
+// that return the value and ignore success/failure. That encourages people to
+// write code that doesn't properly handle the error conditions.
+//
+// DO NOT use these functions in any UI unless it's NOT localized on purpose.
+// Instead, use base::MessageFormatter for a complex message with numbers
+// (integer, float, double) embedded or base::Format{Number,Double,Percent} to
+// just format a single number/percent. Note that some languages use native
+// digits instead of ASCII digits while others use a group separator or decimal
+// point different from ',' and '.'. Using these functions in the UI would lead
+// numbers to be formatted in a non-native way.
+// ----------------------------------------------------------------------------
+
+namespace base {
+
+// Number -> string conversions ------------------------------------------------
+
+// Ignores locale! see warning above.
+BASE_EXPORT std::string NumberToString(int value);
+BASE_EXPORT string16 NumberToString16(int value);
+BASE_EXPORT std::string NumberToString(unsigned int value);
+BASE_EXPORT string16 NumberToString16(unsigned int value);
+BASE_EXPORT std::string NumberToString(long value);
+BASE_EXPORT string16 NumberToString16(long value);
+BASE_EXPORT std::string NumberToString(unsigned long value);
+BASE_EXPORT string16 NumberToString16(unsigned long value);
+BASE_EXPORT std::string NumberToString(long long value);
+BASE_EXPORT string16 NumberToString16(long long value);
+BASE_EXPORT std::string NumberToString(unsigned long long value);
+BASE_EXPORT string16 NumberToString16(unsigned long long value);
+BASE_EXPORT std::string NumberToString(double value);
+BASE_EXPORT string16 NumberToString16(double value);
+
+// String -> number conversions ------------------------------------------------
+
+// Perform a best-effort conversion of the input string to a numeric type,
+// setting |*output| to the result of the conversion. Returns true for
+// "perfect" conversions; returns false in the following cases:
+// - Overflow. |*output| will be set to the maximum value supported
+// by the data type.
+// - Underflow. |*output| will be set to the minimum value supported
+// by the data type.
+// - Trailing characters in the string after parsing the number. |*output|
+// will be set to the value of the number that was parsed.
+// - Leading whitespace in the string before parsing the number. |*output| will
+// be set to the value of the number that was parsed.
+// - No characters parseable as a number at the beginning of the string.
+// |*output| will be set to 0.
+// - Empty string. |*output| will be set to 0.
+// WARNING: Will write to |output| even when returning false.
+// Read the comments above carefully.
+BASE_EXPORT bool StringToInt(StringPiece input, int* output);
+BASE_EXPORT bool StringToInt(StringPiece16 input, int* output);
+
+BASE_EXPORT bool StringToUint(StringPiece input, unsigned* output);
+BASE_EXPORT bool StringToUint(StringPiece16 input, unsigned* output);
+
+BASE_EXPORT bool StringToInt64(StringPiece input, int64_t* output);
+BASE_EXPORT bool StringToInt64(StringPiece16 input, int64_t* output);
+
+BASE_EXPORT bool StringToUint64(StringPiece input, uint64_t* output);
+BASE_EXPORT bool StringToUint64(StringPiece16 input, uint64_t* output);
+
+BASE_EXPORT bool StringToSizeT(StringPiece input, size_t* output);
+BASE_EXPORT bool StringToSizeT(StringPiece16 input, size_t* output);
+
+// For floating-point conversions, only conversions of input strings in decimal
+// form are defined to work. Behavior with strings representing floating-point
+// numbers in hexadecimal, and strings representing non-finite values (such as
+// NaN and inf) is undefined. Otherwise, these behave the same as the integral
+// variants. This expects the input string to NOT be specific to the locale.
+// If your input is locale specific, use ICU to read the number.
+// WARNING: Will write to |output| even when returning false.
+// Read the comments here and above StringToInt() carefully.
+BASE_EXPORT bool StringToDouble(StringPiece input, double* output);
+BASE_EXPORT bool StringToDouble(StringPiece16 input, double* output);
+
+// Hex encoding ----------------------------------------------------------------
+
+// Returns a hex string representation of a binary buffer. The returned hex
+// string will be in upper case. This function does not check if |size| is
+// within reasonable limits since it's written with trusted data in mind. If
+// you suspect that the data you want to format might be large, the absolute
+// max size for |size| should be is
+// std::numeric_limits<size_t>::max() / 2
+BASE_EXPORT std::string HexEncode(const void* bytes, size_t size);
+BASE_EXPORT std::string HexEncode(base::span<const uint8_t> bytes);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// -0x80000000 < |input| < 0x7FFFFFFF.
+BASE_EXPORT bool HexStringToInt(StringPiece input, int* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// 0x00000000 < |input| < 0xFFFFFFFF.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt(StringPiece input, uint32_t* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.
+BASE_EXPORT bool HexStringToInt64(StringPiece input, int64_t* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt64(StringPiece input, uint64_t* output);
+
+// Similar to the previous functions, except that output is a vector of bytes.
+// |*output| will contain as many bytes as were successfully parsed prior to the
+// error. There is no overflow, but input.size() must be evenly divisible by 2.
+// Leading 0x or +/- are not allowed.
+BASE_EXPORT bool HexStringToBytes(StringPiece input,
+ std::vector<uint8_t>* output);
+
+// Same as HexStringToBytes, but for an std::string.
+BASE_EXPORT bool HexStringToString(StringPiece input, std::string* output);
+
+// Decodes the hex string |input| into a presized |output|. The output buffer
+// must be sized exactly to |input.size() / 2| or decoding will fail and no
+// bytes will be written to |output|. Decoding an empty input is also
+// considered a failure. When decoding fails due to encountering invalid input
+// characters, |output| will have been filled with the decoded bytes up until
+// the failure.
+BASE_EXPORT bool HexStringToSpan(StringPiece input, base::span<uint8_t> output);
+
+} // namespace base
+
+#endif // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
diff --git a/security/sandbox/chromium/base/strings/string_piece.cc b/security/sandbox/chromium/base/strings/string_piece.cc
new file mode 100644
index 0000000000..d743144a4e
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_piece.cc
@@ -0,0 +1,426 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Copied from strings/stringpiece.cc with modifications
+
+#include "base/strings/string_piece.h"
+
+#include <limits.h>
+
+#include <algorithm>
+#include <ostream>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+namespace {
+
+// For each character in characters_wanted, sets the index corresponding
+// to the ASCII code of that character to 1 in table. This is used by
+// the find_.*_of methods below to tell whether or not a character is in
+// the lookup table in constant time.
+// The argument `table' must be an array that is large enough to hold all
+// the possible values of an unsigned char. Thus it should be be declared
+// as follows:
+// bool table[UCHAR_MAX + 1]
+inline void BuildLookupTable(const StringPiece& characters_wanted,
+ bool* table) {
+ const size_t length = characters_wanted.length();
+ const char* const data = characters_wanted.data();
+ for (size_t i = 0; i < length; ++i) {
+ table[static_cast<unsigned char>(data[i])] = true;
+ }
+}
+
+} // namespace
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+template class BasicStringPiece<std::string>;
+template class BasicStringPiece<string16>;
+#endif
+
+std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
+ o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
+ return o;
+}
+
+std::ostream& operator<<(std::ostream& o, const StringPiece16& piece) {
+ return o << UTF16ToUTF8(piece);
+}
+
+namespace internal {
+
+template<typename STR>
+void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
+ if (!self.empty())
+ target->append(self.data(), self.size());
+}
+
+void AppendToString(const StringPiece& self, std::string* target) {
+ AppendToStringT(self, target);
+}
+
+void AppendToString(const StringPiece16& self, string16* target) {
+ AppendToStringT(self, target);
+}
+
+template<typename STR>
+size_t copyT(const BasicStringPiece<STR>& self,
+ typename STR::value_type* buf,
+ size_t n,
+ size_t pos) {
+ size_t ret = std::min(self.size() - pos, n);
+ memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type));
+ return ret;
+}
+
+size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
+ return copyT(self, buf, n, pos);
+}
+
+size_t copy(const StringPiece16& self, char16* buf, size_t n, size_t pos) {
+ return copyT(self, buf, n, pos);
+}
+
+template<typename STR>
+size_t findT(const BasicStringPiece<STR>& self,
+ const BasicStringPiece<STR>& s,
+ size_t pos) {
+ if (pos > self.size())
+ return BasicStringPiece<STR>::npos;
+
+ typename BasicStringPiece<STR>::const_iterator result =
+ std::search(self.begin() + pos, self.end(), s.begin(), s.end());
+ const size_t xpos =
+ static_cast<size_t>(result - self.begin());
+ return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos;
+}
+
+size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
+ return findT(self, s, pos);
+}
+
+size_t find(const StringPiece16& self, const StringPiece16& s, size_t pos) {
+ return findT(self, s, pos);
+}
+
+template<typename STR>
+size_t findT(const BasicStringPiece<STR>& self,
+ typename STR::value_type c,
+ size_t pos) {
+ if (pos >= self.size())
+ return BasicStringPiece<STR>::npos;
+
+ typename BasicStringPiece<STR>::const_iterator result =
+ std::find(self.begin() + pos, self.end(), c);
+ return result != self.end() ?
+ static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
+}
+
+size_t find(const StringPiece& self, char c, size_t pos) {
+ return findT(self, c, pos);
+}
+
+size_t find(const StringPiece16& self, char16 c, size_t pos) {
+ return findT(self, c, pos);
+}
+
+template<typename STR>
+size_t rfindT(const BasicStringPiece<STR>& self,
+ const BasicStringPiece<STR>& s,
+ size_t pos) {
+ if (self.size() < s.size())
+ return BasicStringPiece<STR>::npos;
+
+ if (s.empty())
+ return std::min(self.size(), pos);
+
+ typename BasicStringPiece<STR>::const_iterator last =
+ self.begin() + std::min(self.size() - s.size(), pos) + s.size();
+ typename BasicStringPiece<STR>::const_iterator result =
+ std::find_end(self.begin(), last, s.begin(), s.end());
+ return result != last ?
+ static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
+}
+
+size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
+ return rfindT(self, s, pos);
+}
+
+size_t rfind(const StringPiece16& self, const StringPiece16& s, size_t pos) {
+ return rfindT(self, s, pos);
+}
+
+template<typename STR>
+size_t rfindT(const BasicStringPiece<STR>& self,
+ typename STR::value_type c,
+ size_t pos) {
+ if (self.size() == 0)
+ return BasicStringPiece<STR>::npos;
+
+ for (size_t i = std::min(pos, self.size() - 1); ;
+ --i) {
+ if (self.data()[i] == c)
+ return i;
+ if (i == 0)
+ break;
+ }
+ return BasicStringPiece<STR>::npos;
+}
+
+size_t rfind(const StringPiece& self, char c, size_t pos) {
+ return rfindT(self, c, pos);
+}
+
+size_t rfind(const StringPiece16& self, char16 c, size_t pos) {
+ return rfindT(self, c, pos);
+}
+
+// 8-bit version using lookup table.
+size_t find_first_of(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos) {
+ if (self.size() == 0 || s.size() == 0)
+ return StringPiece::npos;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.size() == 1)
+ return find(self, s.data()[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (size_t i = pos; i < self.size(); ++i) {
+ if (lookup[static_cast<unsigned char>(self.data()[i])]) {
+ return i;
+ }
+ }
+ return StringPiece::npos;
+}
+
+// 16-bit brute force version.
+size_t find_first_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos) {
+ // Use the faster std::find() if searching for a single character.
+ StringPiece16::const_iterator found =
+ s.size() == 1 ? std::find(self.begin() + pos, self.end(), s[0])
+ : std::find_first_of(self.begin() + pos, self.end(),
+ s.begin(), s.end());
+ if (found == self.end())
+ return StringPiece16::npos;
+ return found - self.begin();
+}
+
+// 8-bit version using lookup table.
+size_t find_first_not_of(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos) {
+ if (self.size() == 0)
+ return StringPiece::npos;
+
+ if (s.size() == 0)
+ return 0;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.size() == 1)
+ return find_first_not_of(self, s.data()[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (size_t i = pos; i < self.size(); ++i) {
+ if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
+ return i;
+ }
+ }
+ return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos) {
+ if (self.size() == 0)
+ return StringPiece16::npos;
+
+ for (size_t self_i = pos; self_i < self.size(); ++self_i) {
+ bool found = false;
+ for (auto c : s) {
+ if (self[self_i] == c) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return self_i;
+ }
+ return StringPiece16::npos;
+}
+
+template<typename STR>
+size_t find_first_not_ofT(const BasicStringPiece<STR>& self,
+ typename STR::value_type c,
+ size_t pos) {
+ if (self.size() == 0)
+ return BasicStringPiece<STR>::npos;
+
+ for (; pos < self.size(); ++pos) {
+ if (self.data()[pos] != c) {
+ return pos;
+ }
+ }
+ return BasicStringPiece<STR>::npos;
+}
+
+size_t find_first_not_of(const StringPiece& self,
+ char c,
+ size_t pos) {
+ return find_first_not_ofT(self, c, pos);
+}
+
+size_t find_first_not_of(const StringPiece16& self,
+ char16 c,
+ size_t pos) {
+ return find_first_not_ofT(self, c, pos);
+}
+
+// 8-bit version using lookup table.
+size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) {
+ if (self.size() == 0 || s.size() == 0)
+ return StringPiece::npos;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.size() == 1)
+ return rfind(self, s.data()[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (size_t i = std::min(pos, self.size() - 1); ; --i) {
+ if (lookup[static_cast<unsigned char>(self.data()[i])])
+ return i;
+ if (i == 0)
+ break;
+ }
+ return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+size_t find_last_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos) {
+ if (self.size() == 0)
+ return StringPiece16::npos;
+
+ for (size_t self_i = std::min(pos, self.size() - 1); ;
+ --self_i) {
+ for (auto c : s) {
+ if (self.data()[self_i] == c)
+ return self_i;
+ }
+ if (self_i == 0)
+ break;
+ }
+ return StringPiece16::npos;
+}
+
+// 8-bit version using lookup table.
+size_t find_last_not_of(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos) {
+ if (self.size() == 0)
+ return StringPiece::npos;
+
+ size_t i = std::min(pos, self.size() - 1);
+ if (s.size() == 0)
+ return i;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.size() == 1)
+ return find_last_not_of(self, s.data()[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (; ; --i) {
+ if (!lookup[static_cast<unsigned char>(self.data()[i])])
+ return i;
+ if (i == 0)
+ break;
+ }
+ return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+size_t find_last_not_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos) {
+ if (self.size() == 0)
+ return StringPiece::npos;
+
+ for (size_t self_i = std::min(pos, self.size() - 1); ; --self_i) {
+ bool found = false;
+ for (auto c : s) {
+ if (self.data()[self_i] == c) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return self_i;
+ if (self_i == 0)
+ break;
+ }
+ return StringPiece16::npos;
+}
+
+template<typename STR>
+size_t find_last_not_ofT(const BasicStringPiece<STR>& self,
+ typename STR::value_type c,
+ size_t pos) {
+ if (self.size() == 0)
+ return BasicStringPiece<STR>::npos;
+
+ for (size_t i = std::min(pos, self.size() - 1); ; --i) {
+ if (self.data()[i] != c)
+ return i;
+ if (i == 0)
+ break;
+ }
+ return BasicStringPiece<STR>::npos;
+}
+
+size_t find_last_not_of(const StringPiece& self,
+ char c,
+ size_t pos) {
+ return find_last_not_ofT(self, c, pos);
+}
+
+size_t find_last_not_of(const StringPiece16& self,
+ char16 c,
+ size_t pos) {
+ return find_last_not_ofT(self, c, pos);
+}
+
+template<typename STR>
+BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self,
+ size_t pos,
+ size_t n) {
+ if (pos > self.size()) pos = self.size();
+ if (n > self.size() - pos) n = self.size() - pos;
+ return BasicStringPiece<STR>(self.data() + pos, n);
+}
+
+StringPiece substr(const StringPiece& self,
+ size_t pos,
+ size_t n) {
+ return substrT(self, pos, n);
+}
+
+StringPiece16 substr(const StringPiece16& self,
+ size_t pos,
+ size_t n) {
+ return substrT(self, pos, n);
+}
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/string_piece.h b/security/sandbox/chromium/base/strings/string_piece.h
new file mode 100644
index 0000000000..536bf3f023
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_piece.h
@@ -0,0 +1,513 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Copied from strings/stringpiece.h with modifications
+//
+// A string-like object that points to a sized piece of memory.
+//
+// You can use StringPiece as a function or method parameter. A StringPiece
+// parameter can receive a double-quoted string literal argument, a "const
+// char*" argument, a string argument, or a StringPiece argument with no data
+// copying. Systematic use of StringPiece for arguments reduces data
+// copies and strlen() calls.
+//
+// Prefer passing StringPieces by value:
+// void MyFunction(StringPiece arg);
+// If circumstances require, you may also pass by const reference:
+// void MyFunction(const StringPiece& arg); // not preferred
+// Both of these have the same lifetime semantics. Passing by value
+// generates slightly smaller code. For more discussion, Googlers can see
+// the thread go/stringpiecebyvalue on c-users.
+
+#ifndef BASE_STRINGS_STRING_PIECE_H_
+#define BASE_STRINGS_STRING_PIECE_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <string>
+#include <type_traits>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/strings/char_traits.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece_forward.h"
+
+namespace base {
+
+// internal --------------------------------------------------------------------
+
+// Many of the StringPiece functions use different implementations for the
+// 8-bit and 16-bit versions, and we don't want lots of template expansions in
+// this (very common) header that will slow down compilation.
+//
+// So here we define overloaded functions called by the StringPiece template.
+// For those that share an implementation, the two versions will expand to a
+// template internal to the .cc file.
+namespace internal {
+
+BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
+BASE_EXPORT void AppendToString(const StringPiece16& self, string16* target);
+
+BASE_EXPORT size_t copy(const StringPiece& self,
+ char* buf,
+ size_t n,
+ size_t pos);
+BASE_EXPORT size_t copy(const StringPiece16& self,
+ char16* buf,
+ size_t n,
+ size_t pos);
+
+BASE_EXPORT size_t find(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos);
+BASE_EXPORT size_t find(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos);
+BASE_EXPORT size_t find(const StringPiece& self,
+ char c,
+ size_t pos);
+BASE_EXPORT size_t find(const StringPiece16& self,
+ char16 c,
+ size_t pos);
+
+BASE_EXPORT size_t rfind(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece& self,
+ char c,
+ size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece16& self,
+ char16 c,
+ size_t pos);
+
+BASE_EXPORT size_t find_first_of(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos);
+BASE_EXPORT size_t find_first_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos);
+
+BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
+ char c,
+ size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+ char16 c,
+ size_t pos);
+
+BASE_EXPORT size_t find_last_of(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece& self,
+ char c,
+ size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece16& self,
+ char16 c,
+ size_t pos);
+
+BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
+ const StringPiece& s,
+ size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
+ const StringPiece16& s,
+ size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
+ char16 c,
+ size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
+ char c,
+ size_t pos);
+
+BASE_EXPORT StringPiece substr(const StringPiece& self,
+ size_t pos,
+ size_t n);
+BASE_EXPORT StringPiece16 substr(const StringPiece16& self,
+ size_t pos,
+ size_t n);
+
+} // namespace internal
+
+// BasicStringPiece ------------------------------------------------------------
+
+// Defines the types, methods, operators, and data members common to both
+// StringPiece and StringPiece16.
+//
+// This is templatized by string class type rather than character type, so
+// BasicStringPiece<std::string> or BasicStringPiece<base::string16>.
+template <typename STRING_TYPE> class BasicStringPiece {
+ public:
+ // Standard STL container boilerplate.
+ typedef size_t size_type;
+ typedef typename STRING_TYPE::value_type value_type;
+ typedef const value_type* pointer;
+ typedef const value_type& reference;
+ typedef const value_type& const_reference;
+ typedef ptrdiff_t difference_type;
+ typedef const value_type* const_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+ static const size_type npos;
+
+ public:
+ // We provide non-explicit singleton constructors so users can pass
+ // in a "const char*" or a "string" wherever a "StringPiece" is
+ // expected (likewise for char16, string16, StringPiece16).
+ constexpr BasicStringPiece() : ptr_(NULL), length_(0) {}
+ // TODO(dcheng): Construction from nullptr is not allowed for
+ // std::basic_string_view, so remove the special handling for it.
+ // Note: This doesn't just use STRING_TYPE::traits_type::length(), since that
+ // isn't constexpr until C++17.
+ constexpr BasicStringPiece(const value_type* str)
+ : ptr_(str), length_(!str ? 0 : CharTraits<value_type>::length(str)) {}
+ BasicStringPiece(const STRING_TYPE& str)
+ : ptr_(str.data()), length_(str.size()) {}
+ constexpr BasicStringPiece(const value_type* offset, size_type len)
+ : ptr_(offset), length_(len) {}
+ BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
+ const typename STRING_TYPE::const_iterator& end) {
+ DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
+ length_ = static_cast<size_t>(std::distance(begin, end));
+
+ // The length test before assignment is to avoid dereferencing an iterator
+ // that may point to the end() of a string.
+ ptr_ = length_ > 0 ? &*begin : nullptr;
+ }
+
+ // data() may return a pointer to a buffer with embedded NULs, and the
+ // returned buffer may or may not be null terminated. Therefore it is
+ // typically a mistake to pass data() to a routine that expects a NUL
+ // terminated string.
+ constexpr const value_type* data() const { return ptr_; }
+ constexpr size_type size() const noexcept { return length_; }
+ constexpr size_type length() const noexcept { return length_; }
+ bool empty() const { return length_ == 0; }
+
+ constexpr value_type operator[](size_type i) const {
+ CHECK(i < length_);
+ return ptr_[i];
+ }
+
+ value_type front() const {
+ CHECK_NE(0UL, length_);
+ return ptr_[0];
+ }
+
+ value_type back() const {
+ CHECK_NE(0UL, length_);
+ return ptr_[length_ - 1];
+ }
+
+ constexpr void remove_prefix(size_type n) {
+ CHECK(n <= length_);
+ ptr_ += n;
+ length_ -= n;
+ }
+
+ constexpr void remove_suffix(size_type n) {
+ CHECK(n <= length_);
+ length_ -= n;
+ }
+
+ constexpr int compare(BasicStringPiece x) const noexcept {
+ int r = CharTraits<value_type>::compare(
+ ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
+ if (r == 0) {
+ if (length_ < x.length_) r = -1;
+ else if (length_ > x.length_) r = +1;
+ }
+ return r;
+ }
+
+ // This is the style of conversion preferred by std::string_view in C++17.
+ explicit operator STRING_TYPE() const { return as_string(); }
+
+ STRING_TYPE as_string() const {
+ // std::string doesn't like to take a NULL pointer even with a 0 size.
+ return empty() ? STRING_TYPE() : STRING_TYPE(data(), size());
+ }
+
+ const_iterator begin() const { return ptr_; }
+ const_iterator end() const { return ptr_ + length_; }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(ptr_ + length_);
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(ptr_);
+ }
+
+ size_type max_size() const { return length_; }
+ size_type capacity() const { return length_; }
+
+ void AppendToString(STRING_TYPE* target) const {
+ internal::AppendToString(*this, target);
+ }
+
+ size_type copy(value_type* buf, size_type n, size_type pos = 0) const {
+ return internal::copy(*this, buf, n, pos);
+ }
+
+ // Does "this" start with "x"
+ constexpr bool starts_with(BasicStringPiece x) const noexcept {
+ return (
+ (this->length_ >= x.length_) &&
+ (CharTraits<value_type>::compare(this->ptr_, x.ptr_, x.length_) == 0));
+ }
+
+ // Does "this" end with "x"
+ constexpr bool ends_with(BasicStringPiece x) const noexcept {
+ return ((this->length_ >= x.length_) &&
+ (CharTraits<value_type>::compare(
+ this->ptr_ + (this->length_ - x.length_), x.ptr_, x.length_) ==
+ 0));
+ }
+
+ // find: Search for a character or substring at a given offset.
+ size_type find(const BasicStringPiece<STRING_TYPE>& s,
+ size_type pos = 0) const {
+ return internal::find(*this, s, pos);
+ }
+ size_type find(value_type c, size_type pos = 0) const {
+ return internal::find(*this, c, pos);
+ }
+
+ // rfind: Reverse find.
+ size_type rfind(const BasicStringPiece& s,
+ size_type pos = BasicStringPiece::npos) const {
+ return internal::rfind(*this, s, pos);
+ }
+ size_type rfind(value_type c, size_type pos = BasicStringPiece::npos) const {
+ return internal::rfind(*this, c, pos);
+ }
+
+ // find_first_of: Find the first occurence of one of a set of characters.
+ size_type find_first_of(const BasicStringPiece& s,
+ size_type pos = 0) const {
+ return internal::find_first_of(*this, s, pos);
+ }
+ size_type find_first_of(value_type c, size_type pos = 0) const {
+ return find(c, pos);
+ }
+
+ // find_first_not_of: Find the first occurence not of a set of characters.
+ size_type find_first_not_of(const BasicStringPiece& s,
+ size_type pos = 0) const {
+ return internal::find_first_not_of(*this, s, pos);
+ }
+ size_type find_first_not_of(value_type c, size_type pos = 0) const {
+ return internal::find_first_not_of(*this, c, pos);
+ }
+
+ // find_last_of: Find the last occurence of one of a set of characters.
+ size_type find_last_of(const BasicStringPiece& s,
+ size_type pos = BasicStringPiece::npos) const {
+ return internal::find_last_of(*this, s, pos);
+ }
+ size_type find_last_of(value_type c,
+ size_type pos = BasicStringPiece::npos) const {
+ return rfind(c, pos);
+ }
+
+ // find_last_not_of: Find the last occurence not of a set of characters.
+ size_type find_last_not_of(const BasicStringPiece& s,
+ size_type pos = BasicStringPiece::npos) const {
+ return internal::find_last_not_of(*this, s, pos);
+ }
+ size_type find_last_not_of(value_type c,
+ size_type pos = BasicStringPiece::npos) const {
+ return internal::find_last_not_of(*this, c, pos);
+ }
+
+ // substr.
+ BasicStringPiece substr(size_type pos,
+ size_type n = BasicStringPiece::npos) const {
+ return internal::substr(*this, pos, n);
+ }
+
+ protected:
+ const value_type* ptr_;
+ size_type length_;
+};
+
+template <typename STRING_TYPE>
+const typename BasicStringPiece<STRING_TYPE>::size_type
+BasicStringPiece<STRING_TYPE>::npos =
+ typename BasicStringPiece<STRING_TYPE>::size_type(-1);
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+extern template class BASE_EXPORT BasicStringPiece<std::string>;
+extern template class BASE_EXPORT BasicStringPiece<string16>;
+#endif
+
+// Comparison operators --------------------------------------------------------
+// operator ==
+template <typename StringT>
+constexpr bool operator==(BasicStringPiece<StringT> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;
+}
+
+// Here and below we make use of std::common_type_t to emulate an identity type
+// transformation. This creates a non-deduced context, so that we can compare
+// StringPieces with types that implicitly convert to StringPieces. See
+// https://wg21.link/n3766 for details.
+// Furthermore, we require dummy template parameters for these overloads to work
+// around a name mangling issue on Windows.
+template <typename StringT, int = 1>
+constexpr bool operator==(
+ BasicStringPiece<StringT> lhs,
+ std::common_type_t<BasicStringPiece<StringT>> rhs) noexcept {
+ return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;
+}
+
+template <typename StringT, int = 2>
+constexpr bool operator==(std::common_type_t<BasicStringPiece<StringT>> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;
+}
+
+// operator !=
+template <typename StringT>
+constexpr bool operator!=(BasicStringPiece<StringT> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+template <typename StringT, int = 1>
+constexpr bool operator!=(
+ BasicStringPiece<StringT> lhs,
+ std::common_type_t<BasicStringPiece<StringT>> rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+template <typename StringT, int = 2>
+constexpr bool operator!=(std::common_type_t<BasicStringPiece<StringT>> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+// operator <
+template <typename StringT>
+constexpr bool operator<(BasicStringPiece<StringT> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return lhs.compare(rhs) < 0;
+}
+
+template <typename StringT, int = 1>
+constexpr bool operator<(
+ BasicStringPiece<StringT> lhs,
+ std::common_type_t<BasicStringPiece<StringT>> rhs) noexcept {
+ return lhs.compare(rhs) < 0;
+}
+
+template <typename StringT, int = 2>
+constexpr bool operator<(std::common_type_t<BasicStringPiece<StringT>> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return lhs.compare(rhs) < 0;
+}
+
+// operator >
+template <typename StringT>
+constexpr bool operator>(BasicStringPiece<StringT> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return rhs < lhs;
+}
+
+template <typename StringT, int = 1>
+constexpr bool operator>(
+ BasicStringPiece<StringT> lhs,
+ std::common_type_t<BasicStringPiece<StringT>> rhs) noexcept {
+ return rhs < lhs;
+}
+
+template <typename StringT, int = 2>
+constexpr bool operator>(std::common_type_t<BasicStringPiece<StringT>> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return rhs < lhs;
+}
+
+// operator <=
+template <typename StringT>
+constexpr bool operator<=(BasicStringPiece<StringT> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return !(rhs < lhs);
+}
+
+template <typename StringT, int = 1>
+constexpr bool operator<=(
+ BasicStringPiece<StringT> lhs,
+ std::common_type_t<BasicStringPiece<StringT>> rhs) noexcept {
+ return !(rhs < lhs);
+}
+
+template <typename StringT, int = 2>
+constexpr bool operator<=(std::common_type_t<BasicStringPiece<StringT>> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return !(rhs < lhs);
+}
+
+// operator >=
+template <typename StringT>
+constexpr bool operator>=(BasicStringPiece<StringT> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+template <typename StringT, int = 1>
+constexpr bool operator>=(
+ BasicStringPiece<StringT> lhs,
+ std::common_type_t<BasicStringPiece<StringT>> rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+template <typename StringT, int = 2>
+constexpr bool operator>=(std::common_type_t<BasicStringPiece<StringT>> lhs,
+ BasicStringPiece<StringT> rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& o,
+ const StringPiece& piece);
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& o,
+ const StringPiece16& piece);
+
+// Hashing ---------------------------------------------------------------------
+
+// We provide appropriate hash functions so StringPiece and StringPiece16 can
+// be used as keys in hash sets and maps.
+
+// This hash function is copied from base/strings/string16.h. We don't use the
+// ones already defined for string and string16 directly because it would
+// require the string constructors to be called, which we don't want.
+
+template <typename StringPieceType>
+struct StringPieceHashImpl {
+ std::size_t operator()(StringPieceType sp) const {
+ std::size_t result = 0;
+ for (auto c : sp)
+ result = (result * 131) + c;
+ return result;
+ }
+};
+
+using StringPieceHash = StringPieceHashImpl<StringPiece>;
+using StringPiece16Hash = StringPieceHashImpl<StringPiece16>;
+using WStringPieceHash = StringPieceHashImpl<WStringPiece>;
+
+} // namespace base
+
+#endif // BASE_STRINGS_STRING_PIECE_H_
diff --git a/security/sandbox/chromium/base/strings/string_piece_forward.h b/security/sandbox/chromium/base/strings/string_piece_forward.h
new file mode 100644
index 0000000000..b50b9806c9
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_piece_forward.h
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Forward declaration of StringPiece types from base/strings/string_piece.h
+
+#ifndef BASE_STRINGS_STRING_PIECE_FORWARD_H_
+#define BASE_STRINGS_STRING_PIECE_FORWARD_H_
+
+#include <string>
+
+#include "base/strings/string16.h"
+
+namespace base {
+
+template <typename STRING_TYPE>
+class BasicStringPiece;
+typedef BasicStringPiece<std::string> StringPiece;
+typedef BasicStringPiece<string16> StringPiece16;
+typedef BasicStringPiece<std::wstring> WStringPiece;
+
+} // namespace base
+
+#endif // BASE_STRINGS_STRING_PIECE_FORWARD_H_
diff --git a/security/sandbox/chromium/base/strings/string_split.cc b/security/sandbox/chromium/base/strings/string_split.cc
new file mode 100644
index 0000000000..42bc5e5b60
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_split.cc
@@ -0,0 +1,254 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_split.h"
+
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+// Returns either the ASCII or UTF-16 whitespace.
+template<typename Str> BasicStringPiece<Str> WhitespaceForType();
+#if defined(OS_WIN) && defined(BASE_STRING16_IS_STD_U16STRING)
+template <>
+WStringPiece WhitespaceForType<std::wstring>() {
+ return kWhitespaceWide;
+}
+#endif
+
+template<> StringPiece16 WhitespaceForType<string16>() {
+ return kWhitespaceUTF16;
+}
+template<> StringPiece WhitespaceForType<std::string>() {
+ return kWhitespaceASCII;
+}
+
+// General string splitter template. Can take 8- or 16-bit input, can produce
+// the corresponding string or StringPiece output.
+template <typename OutputStringType, typename Str>
+static std::vector<OutputStringType> SplitStringT(
+ BasicStringPiece<Str> str,
+ BasicStringPiece<Str> delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ std::vector<OutputStringType> result;
+ if (str.empty())
+ return result;
+
+ size_t start = 0;
+ while (start != Str::npos) {
+ size_t end = str.find_first_of(delimiter, start);
+
+ BasicStringPiece<Str> piece;
+ if (end == Str::npos) {
+ piece = str.substr(start);
+ start = Str::npos;
+ } else {
+ piece = str.substr(start, end - start);
+ start = end + 1;
+ }
+
+ if (whitespace == TRIM_WHITESPACE)
+ piece = TrimString(piece, WhitespaceForType<Str>(), TRIM_ALL);
+
+ if (result_type == SPLIT_WANT_ALL || !piece.empty())
+ result.emplace_back(piece);
+ }
+ return result;
+}
+
+bool AppendStringKeyValue(StringPiece input,
+ char delimiter,
+ StringPairs* result) {
+ // Always append a new item regardless of success (it might be empty). The
+ // below code will copy the strings directly into the result pair.
+ result->resize(result->size() + 1);
+ auto& result_pair = result->back();
+
+ // Find the delimiter.
+ size_t end_key_pos = input.find_first_of(delimiter);
+ if (end_key_pos == std::string::npos) {
+ DVLOG(1) << "cannot find delimiter in: " << input;
+ return false; // No delimiter.
+ }
+ result_pair.first = std::string(input.substr(0, end_key_pos));
+
+ // Find the value string.
+ StringPiece remains = input.substr(end_key_pos, input.size() - end_key_pos);
+ size_t begin_value_pos = remains.find_first_not_of(delimiter);
+ if (begin_value_pos == StringPiece::npos) {
+ DVLOG(1) << "cannot parse value from input: " << input;
+ return false; // No value.
+ }
+
+ result_pair.second = std::string(
+ remains.substr(begin_value_pos, remains.size() - begin_value_pos));
+
+ return true;
+}
+
+template <typename OutputStringType, typename Str>
+std::vector<OutputStringType> SplitStringUsingSubstrT(
+ BasicStringPiece<Str> input,
+ BasicStringPiece<Str> delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ using Piece = BasicStringPiece<Str>;
+ using size_type = typename Piece::size_type;
+
+ std::vector<OutputStringType> result;
+ for (size_type begin_index = 0, end_index = 0; end_index != Piece::npos;
+ begin_index = end_index + delimiter.size()) {
+ end_index = input.find(delimiter, begin_index);
+ Piece term = end_index == Piece::npos
+ ? input.substr(begin_index)
+ : input.substr(begin_index, end_index - begin_index);
+
+ if (whitespace == TRIM_WHITESPACE)
+ term = TrimString(term, WhitespaceForType<Str>(), TRIM_ALL);
+
+ if (result_type == SPLIT_WANT_ALL || !term.empty())
+ result.emplace_back(term);
+ }
+
+ return result;
+}
+
+} // namespace
+
+std::vector<std::string> SplitString(StringPiece input,
+ StringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringT<std::string>(input, separators, whitespace, result_type);
+}
+
+std::vector<string16> SplitString(StringPiece16 input,
+ StringPiece16 separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringT<string16>(input, separators, whitespace, result_type);
+}
+
+std::vector<StringPiece> SplitStringPiece(StringPiece input,
+ StringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringT<StringPiece>(input, separators, whitespace, result_type);
+}
+
+std::vector<StringPiece16> SplitStringPiece(StringPiece16 input,
+ StringPiece16 separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringT<StringPiece16>(input, separators, whitespace,
+ result_type);
+}
+
+bool SplitStringIntoKeyValuePairs(StringPiece input,
+ char key_value_delimiter,
+ char key_value_pair_delimiter,
+ StringPairs* key_value_pairs) {
+ return SplitStringIntoKeyValuePairsUsingSubstr(
+ input, key_value_delimiter, StringPiece(&key_value_pair_delimiter, 1),
+ key_value_pairs);
+}
+
+bool SplitStringIntoKeyValuePairsUsingSubstr(
+ StringPiece input,
+ char key_value_delimiter,
+ StringPiece key_value_pair_delimiter,
+ StringPairs* key_value_pairs) {
+ key_value_pairs->clear();
+
+ std::vector<StringPiece> pairs = SplitStringPieceUsingSubstr(
+ input, key_value_pair_delimiter, TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+ key_value_pairs->reserve(pairs.size());
+
+ bool success = true;
+ for (const StringPiece& pair : pairs) {
+ if (!AppendStringKeyValue(pair, key_value_delimiter, key_value_pairs)) {
+ // Don't return here, to allow for pairs without associated
+ // value or key; just record that the split failed.
+ success = false;
+ }
+ }
+ return success;
+}
+
+std::vector<string16> SplitStringUsingSubstr(StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringUsingSubstrT<string16>(input, delimiter, whitespace,
+ result_type);
+}
+
+std::vector<std::string> SplitStringUsingSubstr(StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringUsingSubstrT<std::string>(input, delimiter, whitespace,
+ result_type);
+}
+
+std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+ StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ std::vector<StringPiece16> result;
+ return SplitStringUsingSubstrT<StringPiece16>(input, delimiter, whitespace,
+ result_type);
+}
+
+std::vector<StringPiece> SplitStringPieceUsingSubstr(
+ StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringUsingSubstrT<StringPiece>(input, delimiter, whitespace,
+ result_type);
+}
+
+#if defined(OS_WIN) && defined(BASE_STRING16_IS_STD_U16STRING)
+std::vector<std::wstring> SplitString(WStringPiece input,
+ WStringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringT<std::wstring>(input, separators, whitespace, result_type);
+}
+
+std::vector<WStringPiece> SplitStringPiece(WStringPiece input,
+ WStringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringT<WStringPiece>(input, separators, whitespace, result_type);
+}
+
+std::vector<std::wstring> SplitStringUsingSubstr(WStringPiece input,
+ WStringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringUsingSubstrT<std::wstring>(input, delimiter, whitespace,
+ result_type);
+}
+
+std::vector<WStringPiece> SplitStringPieceUsingSubstr(
+ WStringPiece input,
+ WStringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ return SplitStringUsingSubstrT<WStringPiece>(input, delimiter, whitespace,
+ result_type);
+}
+#endif
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/string_split.h b/security/sandbox/chromium/base/strings/string_split.h
new file mode 100644
index 0000000000..efa8b199fe
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_split.h
@@ -0,0 +1,169 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_SPLIT_H_
+#define BASE_STRINGS_STRING_SPLIT_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+namespace base {
+
+enum WhitespaceHandling {
+ KEEP_WHITESPACE,
+ TRIM_WHITESPACE,
+};
+
+enum SplitResult {
+ // Strictly return all results.
+ //
+ // If the input is ",," and the separator is ',' this will return a
+ // vector of three empty strings.
+ SPLIT_WANT_ALL,
+
+ // Only nonempty results will be added to the results. Multiple separators
+ // will be coalesced. Separators at the beginning and end of the input will
+ // be ignored. With TRIM_WHITESPACE, whitespace-only results will be dropped.
+ //
+ // If the input is ",," and the separator is ',', this will return an empty
+ // vector.
+ SPLIT_WANT_NONEMPTY,
+};
+
+// Split the given string on ANY of the given separators, returning copies of
+// the result.
+//
+// Note this is inverse of JoinString() defined in string_util.h.
+//
+// To split on either commas or semicolons, keeping all whitespace:
+//
+// std::vector<std::string> tokens = base::SplitString(
+// input, ", WARN_UNUSED_RESULT;", base::KEEP_WHITESPACE,
+// base::SPLIT_WANT_ALL) WARN_UNUSED_RESULT;
+BASE_EXPORT std::vector<std::string> SplitString(StringPiece input,
+ StringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type)
+ WARN_UNUSED_RESULT;
+BASE_EXPORT std::vector<string16> SplitString(StringPiece16 input,
+ StringPiece16 separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type)
+ WARN_UNUSED_RESULT;
+
+// Like SplitString above except it returns a vector of StringPieces which
+// reference the original buffer without copying. Although you have to be
+// careful to keep the original string unmodified, this provides an efficient
+// way to iterate through tokens in a string.
+//
+// Note this is inverse of JoinString() defined in string_util.h.
+//
+// To iterate through all whitespace-separated tokens in an input string:
+//
+// for (const auto& cur :
+// base::SplitStringPiece(input, base::kWhitespaceASCII,
+// base::KEEP_WHITESPACE,
+// base::SPLIT_WANT_NONEMPTY)) {
+// ...
+BASE_EXPORT std::vector<StringPiece> SplitStringPiece(
+ StringPiece input,
+ StringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+BASE_EXPORT std::vector<StringPiece16> SplitStringPiece(
+ StringPiece16 input,
+ StringPiece16 separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+
+using StringPairs = std::vector<std::pair<std::string, std::string>>;
+
+// Splits |line| into key value pairs according to the given delimiters and
+// removes whitespace leading each key and trailing each value. Returns true
+// only if each pair has a non-empty key and value. |key_value_pairs| will
+// include ("","") pairs for entries without |key_value_delimiter|.
+BASE_EXPORT bool SplitStringIntoKeyValuePairs(StringPiece input,
+ char key_value_delimiter,
+ char key_value_pair_delimiter,
+ StringPairs* key_value_pairs);
+
+// Similar to SplitStringIntoKeyValuePairs, but use a substring
+// |key_value_pair_delimiter| instead of a single char.
+BASE_EXPORT bool SplitStringIntoKeyValuePairsUsingSubstr(
+ StringPiece input,
+ char key_value_delimiter,
+ StringPiece key_value_pair_delimiter,
+ StringPairs* key_value_pairs);
+
+// Similar to SplitString, but use a substring delimiter instead of a list of
+// characters that are all possible delimiters.
+BASE_EXPORT std::vector<string16> SplitStringUsingSubstr(
+ StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+BASE_EXPORT std::vector<std::string> SplitStringUsingSubstr(
+ StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+
+// Like SplitStringUsingSubstr above except it returns a vector of StringPieces
+// which reference the original buffer without copying. Although you have to be
+// careful to keep the original string unmodified, this provides an efficient
+// way to iterate through tokens in a string.
+//
+// To iterate through all newline-separated tokens in an input string:
+//
+// for (const auto& cur :
+// base::SplitStringUsingSubstr(input, "\r\n",
+// base::KEEP_WHITESPACE,
+// base::SPLIT_WANT_NONEMPTY)) {
+// ...
+BASE_EXPORT std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+ StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr(
+ StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+
+#if defined(OS_WIN) && defined(BASE_STRING16_IS_STD_U16STRING)
+BASE_EXPORT std::vector<std::wstring> SplitString(WStringPiece input,
+ WStringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type)
+ WARN_UNUSED_RESULT;
+
+BASE_EXPORT std::vector<WStringPiece> SplitStringPiece(
+ WStringPiece input,
+ WStringPiece separators,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+
+BASE_EXPORT std::vector<std::wstring> SplitStringUsingSubstr(
+ WStringPiece input,
+ WStringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+
+BASE_EXPORT std::vector<WStringPiece> SplitStringPieceUsingSubstr(
+ WStringPiece input,
+ WStringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) WARN_UNUSED_RESULT;
+#endif
+
+} // namespace base
+
+#endif // BASE_STRINGS_STRING_SPLIT_H_
diff --git a/security/sandbox/chromium/base/strings/string_util.cc b/security/sandbox/chromium/base/strings/string_util.cc
new file mode 100644
index 0000000000..4e4be06e88
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_util.cc
@@ -0,0 +1,1057 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+
+// Overloaded function to append one string onto the end of another. Having a
+// separate overload for |source| as both string and StringPiece allows for more
+// efficient usage from functions templated to work with either type (avoiding a
+// redundant call to the BasicStringPiece constructor in both cases).
+template <typename string_type>
+inline void AppendToString(string_type* target, const string_type& source) {
+ target->append(source);
+}
+
+template <typename string_type>
+inline void AppendToString(string_type* target,
+ const BasicStringPiece<string_type>& source) {
+ source.AppendToString(target);
+}
+
+// Assuming that a pointer is the size of a "machine word", then
+// uintptr_t is an integer type that is also a machine word.
+using MachineWord = uintptr_t;
+
+inline bool IsMachineWordAligned(const void* pointer) {
+ return !(reinterpret_cast<MachineWord>(pointer) & (sizeof(MachineWord) - 1));
+}
+
+template <typename CharacterType>
+struct NonASCIIMask;
+template <>
+struct NonASCIIMask<char> {
+ static constexpr MachineWord value() {
+ return static_cast<MachineWord>(0x8080808080808080ULL);
+ }
+};
+template <>
+struct NonASCIIMask<char16> {
+ static constexpr MachineWord value() {
+ return static_cast<MachineWord>(0xFF80FF80FF80FF80ULL);
+ }
+};
+#if defined(WCHAR_T_IS_UTF32)
+template <>
+struct NonASCIIMask<wchar_t> {
+ static constexpr MachineWord value() {
+ return static_cast<MachineWord>(0xFFFFFF80FFFFFF80ULL);
+ }
+};
+#endif // WCHAR_T_IS_UTF32
+
+} // namespace
+
+bool IsWprintfFormatPortable(const wchar_t* format) {
+ for (const wchar_t* position = format; *position != '\0'; ++position) {
+ if (*position == '%') {
+ bool in_specification = true;
+ bool modifier_l = false;
+ while (in_specification) {
+ // Eat up characters until reaching a known specifier.
+ if (*++position == '\0') {
+ // The format string ended in the middle of a specification. Call
+ // it portable because no unportable specifications were found. The
+ // string is equally broken on all platforms.
+ return true;
+ }
+
+ if (*position == 'l') {
+ // 'l' is the only thing that can save the 's' and 'c' specifiers.
+ modifier_l = true;
+ } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
+ *position == 'S' || *position == 'C' || *position == 'F' ||
+ *position == 'D' || *position == 'O' || *position == 'U') {
+ // Not portable.
+ return false;
+ }
+
+ if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
+ // Portable, keep scanning the rest of the format string.
+ in_specification = false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+namespace {
+
+template<typename StringType>
+StringType ToLowerASCIIImpl(BasicStringPiece<StringType> str) {
+ StringType ret;
+ ret.reserve(str.size());
+ for (size_t i = 0; i < str.size(); i++)
+ ret.push_back(ToLowerASCII(str[i]));
+ return ret;
+}
+
+template<typename StringType>
+StringType ToUpperASCIIImpl(BasicStringPiece<StringType> str) {
+ StringType ret;
+ ret.reserve(str.size());
+ for (size_t i = 0; i < str.size(); i++)
+ ret.push_back(ToUpperASCII(str[i]));
+ return ret;
+}
+
+} // namespace
+
+std::string ToLowerASCII(StringPiece str) {
+ return ToLowerASCIIImpl<std::string>(str);
+}
+
+string16 ToLowerASCII(StringPiece16 str) {
+ return ToLowerASCIIImpl<string16>(str);
+}
+
+std::string ToUpperASCII(StringPiece str) {
+ return ToUpperASCIIImpl<std::string>(str);
+}
+
+string16 ToUpperASCII(StringPiece16 str) {
+ return ToUpperASCIIImpl<string16>(str);
+}
+
+template<class StringType>
+int CompareCaseInsensitiveASCIIT(BasicStringPiece<StringType> a,
+ BasicStringPiece<StringType> b) {
+ // Find the first characters that aren't equal and compare them. If the end
+ // of one of the strings is found before a nonequal character, the lengths
+ // of the strings are compared.
+ size_t i = 0;
+ while (i < a.length() && i < b.length()) {
+ typename StringType::value_type lower_a = ToLowerASCII(a[i]);
+ typename StringType::value_type lower_b = ToLowerASCII(b[i]);
+ if (lower_a < lower_b)
+ return -1;
+ if (lower_a > lower_b)
+ return 1;
+ i++;
+ }
+
+ // End of one string hit before finding a different character. Expect the
+ // common case to be "strings equal" at this point so check that first.
+ if (a.length() == b.length())
+ return 0;
+
+ if (a.length() < b.length())
+ return -1;
+ return 1;
+}
+
+int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+ return CompareCaseInsensitiveASCIIT<std::string>(a, b);
+}
+
+int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+ return CompareCaseInsensitiveASCIIT<string16>(a, b);
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b) {
+ if (a.length() != b.length())
+ return false;
+ return CompareCaseInsensitiveASCIIT<std::string>(a, b) == 0;
+}
+
+bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b) {
+ if (a.length() != b.length())
+ return false;
+ return CompareCaseInsensitiveASCIIT<string16>(a, b) == 0;
+}
+
+const std::string& EmptyString() {
+ static const base::NoDestructor<std::string> s;
+ return *s;
+}
+
+const string16& EmptyString16() {
+ static const base::NoDestructor<string16> s16;
+ return *s16;
+}
+
+template <class StringType>
+bool ReplaceCharsT(const StringType& input,
+ BasicStringPiece<StringType> find_any_of_these,
+ BasicStringPiece<StringType> replace_with,
+ StringType* output);
+
+bool ReplaceChars(const string16& input,
+ StringPiece16 replace_chars,
+ StringPiece16 replace_with,
+ string16* output) {
+ return ReplaceCharsT(input, replace_chars, replace_with, output);
+}
+
+bool ReplaceChars(const std::string& input,
+ StringPiece replace_chars,
+ StringPiece replace_with,
+ std::string* output) {
+ return ReplaceCharsT(input, replace_chars, replace_with, output);
+}
+
+bool RemoveChars(const string16& input,
+ StringPiece16 remove_chars,
+ string16* output) {
+ return ReplaceCharsT(input, remove_chars, StringPiece16(), output);
+}
+
+bool RemoveChars(const std::string& input,
+ StringPiece remove_chars,
+ std::string* output) {
+ return ReplaceCharsT(input, remove_chars, StringPiece(), output);
+}
+
+template <typename Str>
+TrimPositions TrimStringT(BasicStringPiece<Str> input,
+ BasicStringPiece<Str> trim_chars,
+ TrimPositions positions,
+ Str* output) {
+ // Find the edges of leading/trailing whitespace as desired. Need to use
+ // a StringPiece version of input to be able to call find* on it with the
+ // StringPiece version of trim_chars (normally the trim_chars will be a
+ // constant so avoid making a copy).
+ const size_t last_char = input.length() - 1;
+ const size_t first_good_char =
+ (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
+ const size_t last_good_char = (positions & TRIM_TRAILING)
+ ? input.find_last_not_of(trim_chars)
+ : last_char;
+
+ // When the string was all trimmed, report that we stripped off characters
+ // from whichever position the caller was interested in. For empty input, we
+ // stripped no characters, but we still need to clear |output|.
+ if (input.empty() || first_good_char == Str::npos ||
+ last_good_char == Str::npos) {
+ bool input_was_empty = input.empty(); // in case output == &input
+ output->clear();
+ return input_was_empty ? TRIM_NONE : positions;
+ }
+
+ // Trim.
+ output->assign(input.data() + first_good_char,
+ last_good_char - first_good_char + 1);
+
+ // Return where we trimmed from.
+ return static_cast<TrimPositions>(
+ (first_good_char == 0 ? TRIM_NONE : TRIM_LEADING) |
+ (last_good_char == last_char ? TRIM_NONE : TRIM_TRAILING));
+}
+
+bool TrimString(StringPiece16 input,
+ StringPiece16 trim_chars,
+ string16* output) {
+ return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+bool TrimString(StringPiece input,
+ StringPiece trim_chars,
+ std::string* output) {
+ return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+template<typename Str>
+BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
+ BasicStringPiece<Str> trim_chars,
+ TrimPositions positions) {
+ size_t begin = (positions & TRIM_LEADING) ?
+ input.find_first_not_of(trim_chars) : 0;
+ size_t end = (positions & TRIM_TRAILING) ?
+ input.find_last_not_of(trim_chars) + 1 : input.size();
+ return input.substr(begin, end - begin);
+}
+
+StringPiece16 TrimString(StringPiece16 input,
+ StringPiece16 trim_chars,
+ TrimPositions positions) {
+ return TrimStringPieceT(input, trim_chars, positions);
+}
+
+StringPiece TrimString(StringPiece input,
+ StringPiece trim_chars,
+ TrimPositions positions) {
+ return TrimStringPieceT(input, trim_chars, positions);
+}
+
+void TruncateUTF8ToByteSize(const std::string& input,
+ const size_t byte_size,
+ std::string* output) {
+ DCHECK(output);
+ if (byte_size > input.length()) {
+ *output = input;
+ return;
+ }
+ DCHECK_LE(byte_size,
+ static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
+ // Note: This cast is necessary because CBU8_NEXT uses int32_ts.
+ int32_t truncation_length = static_cast<int32_t>(byte_size);
+ int32_t char_index = truncation_length - 1;
+ const char* data = input.data();
+
+ // Using CBU8, we will move backwards from the truncation point
+ // to the beginning of the string looking for a valid UTF8
+ // character. Once a full UTF8 character is found, we will
+ // truncate the string to the end of that character.
+ while (char_index >= 0) {
+ int32_t prev = char_index;
+ base_icu::UChar32 code_point = 0;
+ CBU8_NEXT(data, char_index, truncation_length, code_point);
+ if (!IsValidCharacter(code_point) ||
+ !IsValidCodepoint(code_point)) {
+ char_index = prev - 1;
+ } else {
+ break;
+ }
+ }
+
+ if (char_index >= 0 )
+ *output = input.substr(0, char_index);
+ else
+ output->clear();
+}
+
+TrimPositions TrimWhitespace(StringPiece16 input,
+ TrimPositions positions,
+ string16* output) {
+ return TrimStringT(input, StringPiece16(kWhitespaceUTF16), positions, output);
+}
+
+StringPiece16 TrimWhitespace(StringPiece16 input,
+ TrimPositions positions) {
+ return TrimStringPieceT(input, StringPiece16(kWhitespaceUTF16), positions);
+}
+
+TrimPositions TrimWhitespaceASCII(StringPiece input,
+ TrimPositions positions,
+ std::string* output) {
+ return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output);
+}
+
+StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
+ return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
+}
+
+template<typename STR>
+STR CollapseWhitespaceT(const STR& text,
+ bool trim_sequences_with_line_breaks) {
+ STR result;
+ result.resize(text.size());
+
+ // Set flags to pretend we're already in a trimmed whitespace sequence, so we
+ // will trim any leading whitespace.
+ bool in_whitespace = true;
+ bool already_trimmed = true;
+
+ int chars_written = 0;
+ for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
+ if (IsUnicodeWhitespace(*i)) {
+ if (!in_whitespace) {
+ // Reduce all whitespace sequences to a single space.
+ in_whitespace = true;
+ result[chars_written++] = L' ';
+ }
+ if (trim_sequences_with_line_breaks && !already_trimmed &&
+ ((*i == '\n') || (*i == '\r'))) {
+ // Whitespace sequences containing CR or LF are eliminated entirely.
+ already_trimmed = true;
+ --chars_written;
+ }
+ } else {
+ // Non-whitespace chracters are copied straight across.
+ in_whitespace = false;
+ already_trimmed = false;
+ result[chars_written++] = *i;
+ }
+ }
+
+ if (in_whitespace && !already_trimmed) {
+ // Any trailing whitespace is eliminated.
+ --chars_written;
+ }
+
+ result.resize(chars_written);
+ return result;
+}
+
+string16 CollapseWhitespace(const string16& text,
+ bool trim_sequences_with_line_breaks) {
+ return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+std::string CollapseWhitespaceASCII(const std::string& text,
+ bool trim_sequences_with_line_breaks) {
+ return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+bool ContainsOnlyChars(StringPiece input, StringPiece characters) {
+ return input.find_first_not_of(characters) == StringPiece::npos;
+}
+
+bool ContainsOnlyChars(StringPiece16 input, StringPiece16 characters) {
+ return input.find_first_not_of(characters) == StringPiece16::npos;
+}
+
+template <class Char>
+inline bool DoIsStringASCII(const Char* characters, size_t length) {
+ if (!length)
+ return true;
+ constexpr MachineWord non_ascii_bit_mask = NonASCIIMask<Char>::value();
+ MachineWord all_char_bits = 0;
+ const Char* end = characters + length;
+
+ // Prologue: align the input.
+ while (!IsMachineWordAligned(characters) && characters < end)
+ all_char_bits |= *characters++;
+ if (all_char_bits & non_ascii_bit_mask)
+ return false;
+
+ // Compare the values of CPU word size.
+ constexpr size_t chars_per_word = sizeof(MachineWord) / sizeof(Char);
+ constexpr int batch_count = 16;
+ while (characters <= end - batch_count * chars_per_word) {
+ all_char_bits = 0;
+ for (int i = 0; i < batch_count; ++i) {
+ all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
+ characters += chars_per_word;
+ }
+ if (all_char_bits & non_ascii_bit_mask)
+ return false;
+ }
+
+ // Process the remaining words.
+ all_char_bits = 0;
+ while (characters <= end - chars_per_word) {
+ all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
+ characters += chars_per_word;
+ }
+
+ // Process the remaining bytes.
+ while (characters < end)
+ all_char_bits |= *characters++;
+
+ return !(all_char_bits & non_ascii_bit_mask);
+}
+
+bool IsStringASCII(StringPiece str) {
+ return DoIsStringASCII(str.data(), str.length());
+}
+
+bool IsStringASCII(StringPiece16 str) {
+ return DoIsStringASCII(str.data(), str.length());
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+bool IsStringASCII(WStringPiece str) {
+ return DoIsStringASCII(str.data(), str.length());
+}
+#endif
+
+template <bool (*Validator)(uint32_t)>
+inline static bool DoIsStringUTF8(StringPiece str) {
+ const char* src = str.data();
+ int32_t src_len = static_cast<int32_t>(str.length());
+ int32_t char_index = 0;
+
+ while (char_index < src_len) {
+ int32_t code_point;
+ CBU8_NEXT(src, char_index, src_len, code_point);
+ if (!Validator(code_point))
+ return false;
+ }
+ return true;
+}
+
+bool IsStringUTF8(StringPiece str) {
+ return DoIsStringUTF8<IsValidCharacter>(str);
+}
+
+bool IsStringUTF8AllowingNoncharacters(StringPiece str) {
+ return DoIsStringUTF8<IsValidCodepoint>(str);
+}
+
+// Implementation note: Normally this function will be called with a hardcoded
+// constant for the lowercase_ascii parameter. Constructing a StringPiece from
+// a C constant requires running strlen, so the result will be two passes
+// through the buffers, one to file the length of lowercase_ascii, and one to
+// compare each letter.
+//
+// This function could have taken a const char* to avoid this and only do one
+// pass through the string. But the strlen is faster than the case-insensitive
+// compares and lets us early-exit in the case that the strings are different
+// lengths (will often be the case for non-matches). So whether one approach or
+// the other will be faster depends on the case.
+//
+// The hardcoded strings are typically very short so it doesn't matter, and the
+// string piece gives additional flexibility for the caller (doesn't have to be
+// null terminated) so we choose the StringPiece route.
+template<typename Str>
+static inline bool DoLowerCaseEqualsASCII(BasicStringPiece<Str> str,
+ StringPiece lowercase_ascii) {
+ if (str.size() != lowercase_ascii.size())
+ return false;
+ for (size_t i = 0; i < str.size(); i++) {
+ if (ToLowerASCII(str[i]) != lowercase_ascii[i])
+ return false;
+ }
+ return true;
+}
+
+bool LowerCaseEqualsASCII(StringPiece str, StringPiece lowercase_ascii) {
+ return DoLowerCaseEqualsASCII<std::string>(str, lowercase_ascii);
+}
+
+bool LowerCaseEqualsASCII(StringPiece16 str, StringPiece lowercase_ascii) {
+ return DoLowerCaseEqualsASCII<string16>(str, lowercase_ascii);
+}
+
+bool EqualsASCII(StringPiece16 str, StringPiece ascii) {
+ if (str.length() != ascii.length())
+ return false;
+ return std::equal(ascii.begin(), ascii.end(), str.begin());
+}
+
+template<typename Str>
+bool StartsWithT(BasicStringPiece<Str> str,
+ BasicStringPiece<Str> search_for,
+ CompareCase case_sensitivity) {
+ if (search_for.size() > str.size())
+ return false;
+
+ BasicStringPiece<Str> source = str.substr(0, search_for.size());
+
+ switch (case_sensitivity) {
+ case CompareCase::SENSITIVE:
+ return source == search_for;
+
+ case CompareCase::INSENSITIVE_ASCII:
+ return std::equal(
+ search_for.begin(), search_for.end(),
+ source.begin(),
+ CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool StartsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity) {
+ return StartsWithT<std::string>(str, search_for, case_sensitivity);
+}
+
+bool StartsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity) {
+ return StartsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+template <typename Str>
+bool EndsWithT(BasicStringPiece<Str> str,
+ BasicStringPiece<Str> search_for,
+ CompareCase case_sensitivity) {
+ if (search_for.size() > str.size())
+ return false;
+
+ BasicStringPiece<Str> source = str.substr(str.size() - search_for.size(),
+ search_for.size());
+
+ switch (case_sensitivity) {
+ case CompareCase::SENSITIVE:
+ return source == search_for;
+
+ case CompareCase::INSENSITIVE_ASCII:
+ return std::equal(
+ source.begin(), source.end(),
+ search_for.begin(),
+ CaseInsensitiveCompareASCII<typename Str::value_type>());
+
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+bool EndsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity) {
+ return EndsWithT<std::string>(str, search_for, case_sensitivity);
+}
+
+bool EndsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity) {
+ return EndsWithT<string16>(str, search_for, case_sensitivity);
+}
+
+char HexDigitToInt(wchar_t c) {
+ DCHECK(IsHexDigit(c));
+ if (c >= '0' && c <= '9')
+ return static_cast<char>(c - '0');
+ if (c >= 'A' && c <= 'F')
+ return static_cast<char>(c - 'A' + 10);
+ if (c >= 'a' && c <= 'f')
+ return static_cast<char>(c - 'a' + 10);
+ return 0;
+}
+
+bool IsUnicodeWhitespace(wchar_t c) {
+ // kWhitespaceWide is a NULL-terminated string
+ for (const wchar_t* cur = kWhitespaceWide; *cur; ++cur) {
+ if (*cur == c)
+ return true;
+ }
+ return false;
+}
+
+static const char* const kByteStringsUnlocalized[] = {
+ " B",
+ " kB",
+ " MB",
+ " GB",
+ " TB",
+ " PB"
+};
+
+string16 FormatBytesUnlocalized(int64_t bytes) {
+ double unit_amount = static_cast<double>(bytes);
+ size_t dimension = 0;
+ const int kKilo = 1024;
+ while (unit_amount >= kKilo &&
+ dimension < base::size(kByteStringsUnlocalized) - 1) {
+ unit_amount /= kKilo;
+ dimension++;
+ }
+
+ char buf[64];
+ if (bytes != 0 && dimension > 0 && unit_amount < 100) {
+ base::snprintf(buf, base::size(buf), "%.1lf%s", unit_amount,
+ kByteStringsUnlocalized[dimension]);
+ } else {
+ base::snprintf(buf, base::size(buf), "%.0lf%s", unit_amount,
+ kByteStringsUnlocalized[dimension]);
+ }
+
+ return ASCIIToUTF16(buf);
+}
+
+// A Matcher for DoReplaceMatchesAfterOffset() that matches substrings.
+template <class StringType>
+struct SubstringMatcher {
+ BasicStringPiece<StringType> find_this;
+
+ size_t Find(const StringType& input, size_t pos) {
+ return input.find(find_this.data(), pos, find_this.length());
+ }
+ size_t MatchSize() { return find_this.length(); }
+};
+
+// A Matcher for DoReplaceMatchesAfterOffset() that matches single characters.
+template <class StringType>
+struct CharacterMatcher {
+ BasicStringPiece<StringType> find_any_of_these;
+
+ size_t Find(const StringType& input, size_t pos) {
+ return input.find_first_of(find_any_of_these.data(), pos,
+ find_any_of_these.length());
+ }
+ constexpr size_t MatchSize() { return 1; }
+};
+
+enum class ReplaceType { REPLACE_ALL, REPLACE_FIRST };
+
+// Runs in O(n) time in the length of |str|, and transforms the string without
+// reallocating when possible. Returns |true| if any matches were found.
+//
+// This is parameterized on a |Matcher| traits type, so that it can be the
+// implementation for both ReplaceChars() and ReplaceSubstringsAfterOffset().
+template <class StringType, class Matcher>
+bool DoReplaceMatchesAfterOffset(StringType* str,
+ size_t initial_offset,
+ Matcher matcher,
+ BasicStringPiece<StringType> replace_with,
+ ReplaceType replace_type) {
+ using CharTraits = typename StringType::traits_type;
+
+ const size_t find_length = matcher.MatchSize();
+ if (!find_length)
+ return false;
+
+ // If the find string doesn't appear, there's nothing to do.
+ size_t first_match = matcher.Find(*str, initial_offset);
+ if (first_match == StringType::npos)
+ return false;
+
+ // If we're only replacing one instance, there's no need to do anything
+ // complicated.
+ const size_t replace_length = replace_with.length();
+ if (replace_type == ReplaceType::REPLACE_FIRST) {
+ str->replace(first_match, find_length, replace_with.data(), replace_length);
+ return true;
+ }
+
+ // If the find and replace strings are the same length, we can simply use
+ // replace() on each instance, and finish the entire operation in O(n) time.
+ if (find_length == replace_length) {
+ auto* buffer = &((*str)[0]);
+ for (size_t offset = first_match; offset != StringType::npos;
+ offset = matcher.Find(*str, offset + replace_length)) {
+ CharTraits::copy(buffer + offset, replace_with.data(), replace_length);
+ }
+ return true;
+ }
+
+ // Since the find and replace strings aren't the same length, a loop like the
+ // one above would be O(n^2) in the worst case, as replace() will shift the
+ // entire remaining string each time. We need to be more clever to keep things
+ // O(n).
+ //
+ // When the string is being shortened, it's possible to just shift the matches
+ // down in one pass while finding, and truncate the length at the end of the
+ // search.
+ //
+ // If the string is being lengthened, more work is required. The strategy used
+ // here is to make two find() passes through the string. The first pass counts
+ // the number of matches to determine the new size. The second pass will
+ // either construct the new string into a new buffer (if the existing buffer
+ // lacked capacity), or else -- if there is room -- create a region of scratch
+ // space after |first_match| by shifting the tail of the string to a higher
+ // index, and doing in-place moves from the tail to lower indices thereafter.
+ size_t str_length = str->length();
+ size_t expansion = 0;
+ if (replace_length > find_length) {
+ // This operation lengthens the string; determine the new length by counting
+ // matches.
+ const size_t expansion_per_match = (replace_length - find_length);
+ size_t num_matches = 0;
+ for (size_t match = first_match; match != StringType::npos;
+ match = matcher.Find(*str, match + find_length)) {
+ expansion += expansion_per_match;
+ ++num_matches;
+ }
+ const size_t final_length = str_length + expansion;
+
+ if (str->capacity() < final_length) {
+ // If we'd have to allocate a new buffer to grow the string, build the
+ // result directly into the new allocation via append().
+ StringType src(str->get_allocator());
+ str->swap(src);
+ str->reserve(final_length);
+
+ size_t pos = 0;
+ for (size_t match = first_match;; match = matcher.Find(src, pos)) {
+ str->append(src, pos, match - pos);
+ str->append(replace_with.data(), replace_length);
+ pos = match + find_length;
+
+ // A mid-loop test/break enables skipping the final Find() call; the
+ // number of matches is known, so don't search past the last one.
+ if (!--num_matches)
+ break;
+ }
+
+ // Handle substring after the final match.
+ str->append(src, pos, str_length - pos);
+ return true;
+ }
+
+ // Prepare for the copy/move loop below -- expand the string to its final
+ // size by shifting the data after the first match to the end of the resized
+ // string.
+ size_t shift_src = first_match + find_length;
+ size_t shift_dst = shift_src + expansion;
+
+ // Big |expansion| factors (relative to |str_length|) require padding up to
+ // |shift_dst|.
+ if (shift_dst > str_length)
+ str->resize(shift_dst);
+
+ str->replace(shift_dst, str_length - shift_src, *str, shift_src,
+ str_length - shift_src);
+ str_length = final_length;
+ }
+
+ // We can alternate replacement and move operations. This won't overwrite the
+ // unsearched region of the string so long as |write_offset| <= |read_offset|;
+ // that condition is always satisfied because:
+ //
+ // (a) If the string is being shortened, |expansion| is zero and
+ // |write_offset| grows slower than |read_offset|.
+ //
+ // (b) If the string is being lengthened, |write_offset| grows faster than
+ // |read_offset|, but |expansion| is big enough so that |write_offset|
+ // will only catch up to |read_offset| at the point of the last match.
+ auto* buffer = &((*str)[0]);
+ size_t write_offset = first_match;
+ size_t read_offset = first_match + expansion;
+ do {
+ if (replace_length) {
+ CharTraits::copy(buffer + write_offset, replace_with.data(),
+ replace_length);
+ write_offset += replace_length;
+ }
+ read_offset += find_length;
+
+ // min() clamps StringType::npos (the largest unsigned value) to str_length.
+ size_t match = std::min(matcher.Find(*str, read_offset), str_length);
+
+ size_t length = match - read_offset;
+ if (length) {
+ CharTraits::move(buffer + write_offset, buffer + read_offset, length);
+ write_offset += length;
+ read_offset += length;
+ }
+ } while (read_offset < str_length);
+
+ // If we're shortening the string, truncate it now.
+ str->resize(write_offset);
+ return true;
+}
+
+template <class StringType>
+bool ReplaceCharsT(const StringType& input,
+ BasicStringPiece<StringType> find_any_of_these,
+ BasicStringPiece<StringType> replace_with,
+ StringType* output) {
+ // Commonly, this is called with output and input being the same string; in
+ // that case, this assignment is inexpensive.
+ *output = input;
+
+ return DoReplaceMatchesAfterOffset(
+ output, 0, CharacterMatcher<StringType>{find_any_of_these}, replace_with,
+ ReplaceType::REPLACE_ALL);
+}
+
+void ReplaceFirstSubstringAfterOffset(string16* str,
+ size_t start_offset,
+ StringPiece16 find_this,
+ StringPiece16 replace_with) {
+ DoReplaceMatchesAfterOffset(str, start_offset,
+ SubstringMatcher<string16>{find_this},
+ replace_with, ReplaceType::REPLACE_FIRST);
+}
+
+void ReplaceFirstSubstringAfterOffset(std::string* str,
+ size_t start_offset,
+ StringPiece find_this,
+ StringPiece replace_with) {
+ DoReplaceMatchesAfterOffset(str, start_offset,
+ SubstringMatcher<std::string>{find_this},
+ replace_with, ReplaceType::REPLACE_FIRST);
+}
+
+void ReplaceSubstringsAfterOffset(string16* str,
+ size_t start_offset,
+ StringPiece16 find_this,
+ StringPiece16 replace_with) {
+ DoReplaceMatchesAfterOffset(str, start_offset,
+ SubstringMatcher<string16>{find_this},
+ replace_with, ReplaceType::REPLACE_ALL);
+}
+
+void ReplaceSubstringsAfterOffset(std::string* str,
+ size_t start_offset,
+ StringPiece find_this,
+ StringPiece replace_with) {
+ DoReplaceMatchesAfterOffset(str, start_offset,
+ SubstringMatcher<std::string>{find_this},
+ replace_with, ReplaceType::REPLACE_ALL);
+}
+
+template <class string_type>
+inline typename string_type::value_type* WriteIntoT(string_type* str,
+ size_t length_with_null) {
+ DCHECK_GE(length_with_null, 1u);
+ str->reserve(length_with_null);
+ str->resize(length_with_null - 1);
+ return &((*str)[0]);
+}
+
+char* WriteInto(std::string* str, size_t length_with_null) {
+ return WriteIntoT(str, length_with_null);
+}
+
+char16* WriteInto(string16* str, size_t length_with_null) {
+ return WriteIntoT(str, length_with_null);
+}
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// Work around VC++ code-gen bug. https://crbug.com/804884
+#pragma optimize("", off)
+#endif
+
+// Generic version for all JoinString overloads. |list_type| must be a sequence
+// (std::vector or std::initializer_list) of strings/StringPieces (std::string,
+// string16, StringPiece or StringPiece16). |string_type| is either std::string
+// or string16.
+template <typename list_type, typename string_type>
+static string_type JoinStringT(const list_type& parts,
+ BasicStringPiece<string_type> sep) {
+ if (parts.size() == 0)
+ return string_type();
+
+ // Pre-allocate the eventual size of the string. Start with the size of all of
+ // the separators (note that this *assumes* parts.size() > 0).
+ size_t total_size = (parts.size() - 1) * sep.size();
+ for (const auto& part : parts)
+ total_size += part.size();
+ string_type result;
+ result.reserve(total_size);
+
+ auto iter = parts.begin();
+ DCHECK(iter != parts.end());
+ AppendToString(&result, *iter);
+ ++iter;
+
+ for (; iter != parts.end(); ++iter) {
+ sep.AppendToString(&result);
+ // Using the overloaded AppendToString allows this template function to work
+ // on both strings and StringPieces without creating an intermediate
+ // StringPiece object.
+ AppendToString(&result, *iter);
+ }
+
+ // Sanity-check that we pre-allocated correctly.
+ DCHECK_EQ(total_size, result.size());
+
+ return result;
+}
+
+std::string JoinString(const std::vector<std::string>& parts,
+ StringPiece separator) {
+ return JoinStringT(parts, separator);
+}
+
+string16 JoinString(const std::vector<string16>& parts,
+ StringPiece16 separator) {
+ return JoinStringT(parts, separator);
+}
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// Work around VC++ code-gen bug. https://crbug.com/804884
+#pragma optimize("", on)
+#endif
+
+std::string JoinString(const std::vector<StringPiece>& parts,
+ StringPiece separator) {
+ return JoinStringT(parts, separator);
+}
+
+string16 JoinString(const std::vector<StringPiece16>& parts,
+ StringPiece16 separator) {
+ return JoinStringT(parts, separator);
+}
+
+std::string JoinString(std::initializer_list<StringPiece> parts,
+ StringPiece separator) {
+ return JoinStringT(parts, separator);
+}
+
+string16 JoinString(std::initializer_list<StringPiece16> parts,
+ StringPiece16 separator) {
+ return JoinStringT(parts, separator);
+}
+
+#if defined(OS_WIN) && defined(BASE_STRING16_IS_STD_U16STRING)
+
+TrimPositions TrimWhitespace(WStringPiece input,
+ TrimPositions positions,
+ std::wstring* output) {
+ return TrimStringT(input, WStringPiece(kWhitespaceWide), positions, output);
+}
+
+WStringPiece TrimWhitespace(WStringPiece input, TrimPositions positions) {
+ return TrimStringPieceT(input, WStringPiece(kWhitespaceWide), positions);
+}
+
+bool TrimString(WStringPiece input,
+ WStringPiece trim_chars,
+ std::wstring* output) {
+ return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+WStringPiece TrimString(WStringPiece input,
+ WStringPiece trim_chars,
+ TrimPositions positions) {
+ return TrimStringPieceT(input, trim_chars, positions);
+}
+
+wchar_t* WriteInto(std::wstring* str, size_t length_with_null) {
+ return WriteIntoT(str, length_with_null);
+}
+
+#endif
+
+// The following code is compatible with the OpenBSD lcpy interface. See:
+// http://www.gratisoft.us/todd/papers/strlcpy.html
+// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
+
+namespace {
+
+template <typename CHAR>
+size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
+ for (size_t i = 0; i < dst_size; ++i) {
+ if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
+ return i;
+ }
+
+ // We were left off at dst_size. We over copied 1 byte. Null terminate.
+ if (dst_size != 0)
+ dst[dst_size - 1] = 0;
+
+ // Count the rest of the |src|, and return it's length in characters.
+ while (src[dst_size]) ++dst_size;
+ return dst_size;
+}
+
+} // namespace
+
+size_t strlcpy(char* dst, const char* src, size_t dst_size) {
+ return lcpyT<char>(dst, src, dst_size);
+}
+size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+ return lcpyT<wchar_t>(dst, src, dst_size);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/string_util.h b/security/sandbox/chromium/base/strings/string_util.h
new file mode 100644
index 0000000000..f6e96c13f5
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_util.h
@@ -0,0 +1,549 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file defines utility functions for working with strings.
+
+#ifndef BASE_STRINGS_STRING_UTIL_H_
+#define BASE_STRINGS_STRING_UTIL_H_
+
+#include <ctype.h>
+#include <stdarg.h> // va_list
+#include <stddef.h>
+#include <stdint.h>
+
+#include <initializer_list>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h" // For implicit conversions.
+#include "build/build_config.h"
+
+namespace base {
+
+// C standard-library functions that aren't cross-platform are provided as
+// "base::...", and their prototypes are listed below. These functions are
+// then implemented as inline calls to the platform-specific equivalents in the
+// platform-specific headers.
+
+// Wrapper for vsnprintf that always null-terminates and always returns the
+// number of characters that would be in an untruncated formatted
+// string, even when truncation occurs.
+int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
+ PRINTF_FORMAT(3, 0);
+
+// Some of these implementations need to be inlined.
+
+// We separate the declaration from the implementation of this inline
+// function just so the PRINTF_FORMAT works.
+inline int snprintf(char* buffer, size_t size, const char* format, ...)
+ PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer, size_t size, const char* format, ...) {
+ va_list arguments;
+ va_start(arguments, format);
+ int result = vsnprintf(buffer, size, format, arguments);
+ va_end(arguments);
+ return result;
+}
+
+// BSD-style safe and consistent string copy functions.
+// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
+// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
+// long as |dst_size| is not 0. Returns the length of |src| in characters.
+// If the return value is >= dst_size, then the output was truncated.
+// NOTE: All sizes are in number of characters, NOT in bytes.
+BASE_EXPORT size_t strlcpy(char* dst, const char* src, size_t dst_size);
+BASE_EXPORT size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size);
+
+// Scan a wprintf format string to determine whether it's portable across a
+// variety of systems. This function only checks that the conversion
+// specifiers used by the format string are supported and have the same meaning
+// on a variety of systems. It doesn't check for other errors that might occur
+// within a format string.
+//
+// Nonportable conversion specifiers for wprintf are:
+// - 's' and 'c' without an 'l' length modifier. %s and %c operate on char
+// data on all systems except Windows, which treat them as wchar_t data.
+// Use %ls and %lc for wchar_t data instead.
+// - 'S' and 'C', which operate on wchar_t data on all systems except Windows,
+// which treat them as char data. Use %ls and %lc for wchar_t data
+// instead.
+// - 'F', which is not identified by Windows wprintf documentation.
+// - 'D', 'O', and 'U', which are deprecated and not available on all systems.
+// Use %ld, %lo, and %lu instead.
+//
+// Note that there is no portable conversion specifier for char data when
+// working with wprintf.
+//
+// This function is intended to be called from base::vswprintf.
+BASE_EXPORT bool IsWprintfFormatPortable(const wchar_t* format);
+
+// ASCII-specific tolower. The standard library's tolower is locale sensitive,
+// so we don't want to use it here.
+inline char ToLowerASCII(char c) {
+ return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+inline char16 ToLowerASCII(char16 c) {
+ return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+
+// ASCII-specific toupper. The standard library's toupper is locale sensitive,
+// so we don't want to use it here.
+inline char ToUpperASCII(char c) {
+ return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+inline char16 ToUpperASCII(char16 c) {
+ return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+
+// Converts the given string to it's ASCII-lowercase equivalent.
+BASE_EXPORT std::string ToLowerASCII(StringPiece str);
+BASE_EXPORT string16 ToLowerASCII(StringPiece16 str);
+
+// Converts the given string to it's ASCII-uppercase equivalent.
+BASE_EXPORT std::string ToUpperASCII(StringPiece str);
+BASE_EXPORT string16 ToUpperASCII(StringPiece16 str);
+
+// Functor for case-insensitive ASCII comparisons for STL algorithms like
+// std::search.
+//
+// Note that a full Unicode version of this functor is not possible to write
+// because case mappings might change the number of characters, depend on
+// context (combining accents), and require handling UTF-16. If you need
+// proper Unicode support, use base::i18n::ToLower/FoldCase and then just
+// use a normal operator== on the result.
+template<typename Char> struct CaseInsensitiveCompareASCII {
+ public:
+ bool operator()(Char x, Char y) const {
+ return ToLowerASCII(x) == ToLowerASCII(y);
+ }
+};
+
+// Like strcasecmp for case-insensitive ASCII characters only. Returns:
+// -1 (a < b)
+// 0 (a == b)
+// 1 (a > b)
+// (unlike strcasecmp which can return values greater or less than 1/-1). For
+// full Unicode support, use base::i18n::ToLower or base::i18h::FoldCase
+// and then just call the normal string operators on the result.
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT int CompareCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
+// Equality for ASCII case-insensitive comparisons. For full Unicode support,
+// use base::i18n::ToLower or base::i18h::FoldCase and then compare with either
+// == or !=.
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece a, StringPiece b);
+BASE_EXPORT bool EqualsCaseInsensitiveASCII(StringPiece16 a, StringPiece16 b);
+
+// These threadsafe functions return references to globally unique empty
+// strings.
+//
+// It is likely faster to construct a new empty string object (just a few
+// instructions to set the length to 0) than to get the empty string instance
+// returned by these functions (which requires threadsafe static access).
+//
+// Therefore, DO NOT USE THESE AS A GENERAL-PURPOSE SUBSTITUTE FOR DEFAULT
+// CONSTRUCTORS. There is only one case where you should use these: functions
+// which need to return a string by reference (e.g. as a class member
+// accessor), and don't have an empty string to use (e.g. in an error case).
+// These should not be used as initializers, function arguments, or return
+// values for functions which return by value or outparam.
+BASE_EXPORT const std::string& EmptyString();
+BASE_EXPORT const string16& EmptyString16();
+
+// Contains the set of characters representing whitespace in the corresponding
+// encoding. Null-terminated. The ASCII versions are the whitespaces as defined
+// by HTML5, and don't include control characters.
+BASE_EXPORT extern const wchar_t kWhitespaceWide[]; // Includes Unicode.
+BASE_EXPORT extern const char16 kWhitespaceUTF16[]; // Includes Unicode.
+BASE_EXPORT extern const char16 kWhitespaceNoCrLfUTF16[]; // Unicode w/o CR/LF.
+BASE_EXPORT extern const char kWhitespaceASCII[];
+BASE_EXPORT extern const char16 kWhitespaceASCIIAs16[]; // No unicode.
+
+// Null-terminated string representing the UTF-8 byte order mark.
+BASE_EXPORT extern const char kUtf8ByteOrderMark[];
+
+// Removes characters in |remove_chars| from anywhere in |input|. Returns true
+// if any characters were removed. |remove_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool RemoveChars(const string16& input,
+ StringPiece16 remove_chars,
+ string16* output);
+BASE_EXPORT bool RemoveChars(const std::string& input,
+ StringPiece remove_chars,
+ std::string* output);
+
+// Replaces characters in |replace_chars| from anywhere in |input| with
+// |replace_with|. Each character in |replace_chars| will be replaced with
+// the |replace_with| string. Returns true if any characters were replaced.
+// |replace_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool ReplaceChars(const string16& input,
+ StringPiece16 replace_chars,
+ StringPiece16 replace_with,
+ string16* output);
+BASE_EXPORT bool ReplaceChars(const std::string& input,
+ StringPiece replace_chars,
+ StringPiece replace_with,
+ std::string* output);
+
+enum TrimPositions {
+ TRIM_NONE = 0,
+ TRIM_LEADING = 1 << 0,
+ TRIM_TRAILING = 1 << 1,
+ TRIM_ALL = TRIM_LEADING | TRIM_TRAILING,
+};
+
+// Removes characters in |trim_chars| from the beginning and end of |input|.
+// The 8-bit version only works on 8-bit characters, not UTF-8. Returns true if
+// any characters were removed.
+//
+// It is safe to use the same variable for both |input| and |output| (this is
+// the normal usage to trim in-place).
+BASE_EXPORT bool TrimString(StringPiece16 input,
+ StringPiece16 trim_chars,
+ string16* output);
+BASE_EXPORT bool TrimString(StringPiece input,
+ StringPiece trim_chars,
+ std::string* output);
+
+// StringPiece versions of the above. The returned pieces refer to the original
+// buffer.
+BASE_EXPORT StringPiece16 TrimString(StringPiece16 input,
+ StringPiece16 trim_chars,
+ TrimPositions positions);
+BASE_EXPORT StringPiece TrimString(StringPiece input,
+ StringPiece trim_chars,
+ TrimPositions positions);
+
+// Truncates a string to the nearest UTF-8 character that will leave
+// the string less than or equal to the specified byte size.
+BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
+ const size_t byte_size,
+ std::string* output);
+
+#if defined(WCHAR_T_IS_UTF16)
+// Utility functions to access the underlying string buffer as a wide char
+// pointer.
+//
+// Note: These functions violate strict aliasing when char16 and wchar_t are
+// unrelated types. We thus pass -fno-strict-aliasing to the compiler on
+// non-Windows platforms [1], and rely on it being off in Clang's CL mode [2].
+//
+// [1] https://crrev.com/b9a0976622/build/config/compiler/BUILD.gn#244
+// [2]
+// https://github.com/llvm/llvm-project/blob/1e28a66/clang/lib/Driver/ToolChains/Clang.cpp#L3949
+inline wchar_t* as_writable_wcstr(char16* str) {
+ return reinterpret_cast<wchar_t*>(str);
+}
+
+inline wchar_t* as_writable_wcstr(string16& str) {
+ return reinterpret_cast<wchar_t*>(data(str));
+}
+
+inline const wchar_t* as_wcstr(const char16* str) {
+ return reinterpret_cast<const wchar_t*>(str);
+}
+
+inline const wchar_t* as_wcstr(StringPiece16 str) {
+ return reinterpret_cast<const wchar_t*>(str.data());
+}
+
+// Utility functions to access the underlying string buffer as a char16 pointer.
+inline char16* as_writable_u16cstr(wchar_t* str) {
+ return reinterpret_cast<char16*>(str);
+}
+
+inline char16* as_writable_u16cstr(std::wstring& str) {
+ return reinterpret_cast<char16*>(data(str));
+}
+
+inline const char16* as_u16cstr(const wchar_t* str) {
+ return reinterpret_cast<const char16*>(str);
+}
+
+inline const char16* as_u16cstr(WStringPiece str) {
+ return reinterpret_cast<const char16*>(str.data());
+}
+
+// Utility functions to convert between base::WStringPiece and
+// base::StringPiece16.
+inline WStringPiece AsWStringPiece(StringPiece16 str) {
+ return WStringPiece(as_wcstr(str.data()), str.size());
+}
+
+inline StringPiece16 AsStringPiece16(WStringPiece str) {
+ return StringPiece16(as_u16cstr(str.data()), str.size());
+}
+
+inline std::wstring AsWString(StringPiece16 str) {
+ return std::wstring(as_wcstr(str.data()), str.size());
+}
+
+inline string16 AsString16(WStringPiece str) {
+ return string16(as_u16cstr(str.data()), str.size());
+}
+#endif // defined(WCHAR_T_IS_UTF16)
+
+// Trims any whitespace from either end of the input string.
+//
+// The StringPiece versions return a substring referencing the input buffer.
+// The ASCII versions look only for ASCII whitespace.
+//
+// The std::string versions return where whitespace was found.
+// NOTE: Safe to use the same variable for both input and output.
+BASE_EXPORT TrimPositions TrimWhitespace(StringPiece16 input,
+ TrimPositions positions,
+ string16* output);
+BASE_EXPORT StringPiece16 TrimWhitespace(StringPiece16 input,
+ TrimPositions positions);
+BASE_EXPORT TrimPositions TrimWhitespaceASCII(StringPiece input,
+ TrimPositions positions,
+ std::string* output);
+BASE_EXPORT StringPiece TrimWhitespaceASCII(StringPiece input,
+ TrimPositions positions);
+
+// Searches for CR or LF characters. Removes all contiguous whitespace
+// strings that contain them. This is useful when trying to deal with text
+// copied from terminals.
+// Returns |text|, with the following three transformations:
+// (1) Leading and trailing whitespace is trimmed.
+// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace
+// sequences containing a CR or LF are trimmed.
+// (3) All other whitespace sequences are converted to single spaces.
+BASE_EXPORT string16 CollapseWhitespace(
+ const string16& text,
+ bool trim_sequences_with_line_breaks);
+BASE_EXPORT std::string CollapseWhitespaceASCII(
+ const std::string& text,
+ bool trim_sequences_with_line_breaks);
+
+// Returns true if |input| is empty or contains only characters found in
+// |characters|.
+BASE_EXPORT bool ContainsOnlyChars(StringPiece input, StringPiece characters);
+BASE_EXPORT bool ContainsOnlyChars(StringPiece16 input,
+ StringPiece16 characters);
+
+// Returns true if |str| is structurally valid UTF-8 and also doesn't
+// contain any non-character code point (e.g. U+10FFFE). Prohibiting
+// non-characters increases the likelihood of detecting non-UTF-8 in
+// real-world text, for callers which do not need to accept
+// non-characters in strings.
+BASE_EXPORT bool IsStringUTF8(StringPiece str);
+
+// Returns true if |str| contains valid UTF-8, allowing non-character
+// code points.
+BASE_EXPORT bool IsStringUTF8AllowingNoncharacters(StringPiece str);
+
+// Returns true if |str| contains only valid ASCII character values.
+// Note 1: IsStringASCII executes in time determined solely by the
+// length of the string, not by its contents, so it is robust against
+// timing attacks for all strings of equal length.
+// Note 2: IsStringASCII assumes the input is likely all ASCII, and
+// does not leave early if it is not the case.
+BASE_EXPORT bool IsStringASCII(StringPiece str);
+BASE_EXPORT bool IsStringASCII(StringPiece16 str);
+#if defined(WCHAR_T_IS_UTF32)
+BASE_EXPORT bool IsStringASCII(WStringPiece str);
+#endif
+
+// Compare the lower-case form of the given string against the given
+// previously-lower-cased ASCII string (typically a constant).
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece str,
+ StringPiece lowecase_ascii);
+BASE_EXPORT bool LowerCaseEqualsASCII(StringPiece16 str,
+ StringPiece lowecase_ascii);
+
+// Performs a case-sensitive string compare of the given 16-bit string against
+// the given 8-bit ASCII string (typically a constant). The behavior is
+// undefined if the |ascii| string is not ASCII.
+BASE_EXPORT bool EqualsASCII(StringPiece16 str, StringPiece ascii);
+
+// Indicates case sensitivity of comparisons. Only ASCII case insensitivity
+// is supported. Full Unicode case-insensitive conversions would need to go in
+// base/i18n so it can use ICU.
+//
+// If you need to do Unicode-aware case-insensitive StartsWith/EndsWith, it's
+// best to call base::i18n::ToLower() or base::i18n::FoldCase() (see
+// base/i18n/case_conversion.h for usage advice) on the arguments, and then use
+// the results to a case-sensitive comparison.
+enum class CompareCase {
+ SENSITIVE,
+ INSENSITIVE_ASCII,
+};
+
+BASE_EXPORT bool StartsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity);
+BASE_EXPORT bool StartsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece str,
+ StringPiece search_for,
+ CompareCase case_sensitivity);
+BASE_EXPORT bool EndsWith(StringPiece16 str,
+ StringPiece16 search_for,
+ CompareCase case_sensitivity);
+
+// Determines the type of ASCII character, independent of locale (the C
+// library versions will change based on locale).
+template <typename Char>
+inline bool IsAsciiWhitespace(Char c) {
+ return c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '\f';
+}
+template <typename Char>
+inline bool IsAsciiAlpha(Char c) {
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+template <typename Char>
+inline bool IsAsciiUpper(Char c) {
+ return c >= 'A' && c <= 'Z';
+}
+template <typename Char>
+inline bool IsAsciiLower(Char c) {
+ return c >= 'a' && c <= 'z';
+}
+template <typename Char>
+inline bool IsAsciiDigit(Char c) {
+ return c >= '0' && c <= '9';
+}
+template <typename Char>
+inline bool IsAsciiPrintable(Char c) {
+ return c >= ' ' && c <= '~';
+}
+
+template <typename Char>
+inline bool IsHexDigit(Char c) {
+ return (c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f');
+}
+
+// Returns the integer corresponding to the given hex character. For example:
+// '4' -> 4
+// 'a' -> 10
+// 'B' -> 11
+// Assumes the input is a valid hex character. DCHECKs in debug builds if not.
+BASE_EXPORT char HexDigitToInt(wchar_t c);
+
+// Returns true if it's a Unicode whitespace character.
+BASE_EXPORT bool IsUnicodeWhitespace(wchar_t c);
+
+// Return a byte string in human-readable format with a unit suffix. Not
+// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
+// highly recommended instead. TODO(avi): Figure out how to get callers to use
+// FormatBytes instead; remove this.
+BASE_EXPORT string16 FormatBytesUnlocalized(int64_t bytes);
+
+// Starting at |start_offset| (usually 0), replace the first instance of
+// |find_this| with |replace_with|.
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+ base::string16* str,
+ size_t start_offset,
+ StringPiece16 find_this,
+ StringPiece16 replace_with);
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+ std::string* str,
+ size_t start_offset,
+ StringPiece find_this,
+ StringPiece replace_with);
+
+// Starting at |start_offset| (usually 0), look through |str| and replace all
+// instances of |find_this| with |replace_with|.
+//
+// This does entire substrings; use std::replace in <algorithm> for single
+// characters, for example:
+// std::replace(str.begin(), str.end(), 'a', 'b');
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+ string16* str,
+ size_t start_offset,
+ StringPiece16 find_this,
+ StringPiece16 replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+ std::string* str,
+ size_t start_offset,
+ StringPiece find_this,
+ StringPiece replace_with);
+
+// Reserves enough memory in |str| to accommodate |length_with_null| characters,
+// sets the size of |str| to |length_with_null - 1| characters, and returns a
+// pointer to the underlying contiguous array of characters. This is typically
+// used when calling a function that writes results into a character array, but
+// the caller wants the data to be managed by a string-like object. It is
+// convenient in that is can be used inline in the call, and fast in that it
+// avoids copying the results of the call from a char* into a string.
+//
+// Internally, this takes linear time because the resize() call 0-fills the
+// underlying array for potentially all
+// (|length_with_null - 1| * sizeof(string_type::value_type)) bytes. Ideally we
+// could avoid this aspect of the resize() call, as we expect the caller to
+// immediately write over this memory, but there is no other way to set the size
+// of the string, and not doing that will mean people who access |str| rather
+// than str.c_str() will get back a string of whatever size |str| had on entry
+// to this function (probably 0).
+BASE_EXPORT char* WriteInto(std::string* str, size_t length_with_null);
+BASE_EXPORT char16* WriteInto(string16* str, size_t length_with_null);
+
+// Joins a vector or list of strings into a single string, inserting |separator|
+// (which may be empty) in between all elements.
+//
+// Note this is inverse of SplitString()/SplitStringPiece() defined in
+// string_split.h.
+//
+// If possible, callers should build a vector of StringPieces and use the
+// StringPiece variant, so that they do not create unnecessary copies of
+// strings. For example, instead of using SplitString, modifying the vector,
+// then using JoinString, use SplitStringPiece followed by JoinString so that no
+// copies of those strings are created until the final join operation.
+//
+// Use StrCat (in base/strings/strcat.h) if you don't need a separator.
+BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
+ StringPiece separator);
+BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
+ StringPiece16 separator);
+BASE_EXPORT std::string JoinString(const std::vector<StringPiece>& parts,
+ StringPiece separator);
+BASE_EXPORT string16 JoinString(const std::vector<StringPiece16>& parts,
+ StringPiece16 separator);
+// Explicit initializer_list overloads are required to break ambiguity when used
+// with a literal initializer list (otherwise the compiler would not be able to
+// decide between the string and StringPiece overloads).
+BASE_EXPORT std::string JoinString(std::initializer_list<StringPiece> parts,
+ StringPiece separator);
+BASE_EXPORT string16 JoinString(std::initializer_list<StringPiece16> parts,
+ StringPiece16 separator);
+
+#if defined(OS_WIN) && defined(BASE_STRING16_IS_STD_U16STRING)
+BASE_EXPORT TrimPositions TrimWhitespace(WStringPiece input,
+ TrimPositions positions,
+ std::wstring* output);
+
+BASE_EXPORT WStringPiece TrimWhitespace(WStringPiece input,
+ TrimPositions positions);
+
+BASE_EXPORT bool TrimString(WStringPiece input,
+ WStringPiece trim_chars,
+ std::wstring* output);
+
+BASE_EXPORT WStringPiece TrimString(WStringPiece input,
+ WStringPiece trim_chars,
+ TrimPositions positions);
+
+BASE_EXPORT wchar_t* WriteInto(std::wstring* str, size_t length_with_null);
+#endif
+
+} // namespace base
+
+#if defined(OS_WIN)
+#include "base/strings/string_util_win.h"
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include "base/strings/string_util_posix.h"
+#else
+#error Define string operations appropriately for your platform
+#endif
+
+#endif // BASE_STRINGS_STRING_UTIL_H_
diff --git a/security/sandbox/chromium/base/strings/string_util_constants.cc b/security/sandbox/chromium/base/strings/string_util_constants.cc
new file mode 100644
index 0000000000..212c5ab082
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_util_constants.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+namespace base {
+
+#define WHITESPACE_ASCII_NO_CR_LF \
+ 0x09, /* CHARACTER TABULATION */ \
+ 0x0B, /* LINE TABULATION */ \
+ 0x0C, /* FORM FEED (FF) */ \
+ 0x20 /* SPACE */
+
+#define WHITESPACE_ASCII \
+ WHITESPACE_ASCII_NO_CR_LF, /* Comment to make clang-format linebreak */ \
+ 0x0A, /* LINE FEED (LF) */ \
+ 0x0D /* CARRIAGE RETURN (CR) */
+
+#define WHITESPACE_UNICODE_NON_ASCII \
+ 0x0085, /* NEXT LINE (NEL) */ \
+ 0x00A0, /* NO-BREAK SPACE */ \
+ 0x1680, /* OGHAM SPACE MARK */ \
+ 0x2000, /* EN QUAD */ \
+ 0x2001, /* EM QUAD */ \
+ 0x2002, /* EN SPACE */ \
+ 0x2003, /* EM SPACE */ \
+ 0x2004, /* THREE-PER-EM SPACE */ \
+ 0x2005, /* FOUR-PER-EM SPACE */ \
+ 0x2006, /* SIX-PER-EM SPACE */ \
+ 0x2007, /* FIGURE SPACE */ \
+ 0x2008, /* PUNCTUATION SPACE */ \
+ 0x2009, /* THIN SPACE */ \
+ 0x200A, /* HAIR SPACE */ \
+ 0x2028, /* LINE SEPARATOR */ \
+ 0x2029, /* PARAGRAPH SEPARATOR */ \
+ 0x202F, /* NARROW NO-BREAK SPACE */ \
+ 0x205F, /* MEDIUM MATHEMATICAL SPACE */ \
+ 0x3000 /* IDEOGRAPHIC SPACE */
+
+#define WHITESPACE_UNICODE_NO_CR_LF \
+ WHITESPACE_ASCII_NO_CR_LF, WHITESPACE_UNICODE_NON_ASCII
+
+#define WHITESPACE_UNICODE WHITESPACE_ASCII, WHITESPACE_UNICODE_NON_ASCII
+
+const wchar_t kWhitespaceWide[] = {WHITESPACE_UNICODE, 0};
+const char16 kWhitespaceUTF16[] = {WHITESPACE_UNICODE, 0};
+const char16 kWhitespaceNoCrLfUTF16[] = {WHITESPACE_UNICODE_NO_CR_LF, 0};
+const char kWhitespaceASCII[] = {WHITESPACE_ASCII, 0};
+const char16 kWhitespaceASCIIAs16[] = {WHITESPACE_ASCII, 0};
+
+const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/string_util_posix.h b/security/sandbox/chromium/base/strings/string_util_posix.h
new file mode 100644
index 0000000000..8299118e10
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_util_posix.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_UTIL_POSIX_H_
+#define BASE_STRINGS_STRING_UTIL_POSIX_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+ return ::strdup(str);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+ const char* format, va_list arguments) {
+ return ::vsnprintf(buffer, size, format, arguments);
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size,
+ const wchar_t* format, va_list arguments) {
+ DCHECK(IsWprintfFormatPortable(format));
+ return ::vswprintf(buffer, size, format, arguments);
+}
+
+} // namespace base
+
+#endif // BASE_STRINGS_STRING_UTIL_POSIX_H_
diff --git a/security/sandbox/chromium/base/strings/string_util_win.h b/security/sandbox/chromium/base/strings/string_util_win.h
new file mode 100644
index 0000000000..7f260bfc8b
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/string_util_win.h
@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_UTIL_WIN_H_
+#define BASE_STRINGS_STRING_UTIL_WIN_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+ return _strdup(str);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+ const char* format, va_list arguments) {
+ int length = vsnprintf_s(buffer, size, size - 1, format, arguments);
+ if (length < 0)
+ return _vscprintf(format, arguments);
+ return length;
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size,
+ const wchar_t* format, va_list arguments) {
+ DCHECK(IsWprintfFormatPortable(format));
+
+ int length = _vsnwprintf_s(buffer, size, size - 1, format, arguments);
+ if (length < 0)
+ return _vscwprintf(format, arguments);
+ return length;
+}
+
+} // namespace base
+
+#endif // BASE_STRINGS_STRING_UTIL_WIN_H_
diff --git a/security/sandbox/chromium/base/strings/stringprintf.cc b/security/sandbox/chromium/base/strings/stringprintf.cc
new file mode 100644
index 0000000000..738cc63bbe
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/stringprintf.cc
@@ -0,0 +1,225 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+#include <vector>
+
+#include "base/scoped_clear_last_error.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+
+// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
+// is the size of the buffer. These return the number of characters in the
+// formatted string excluding the NUL terminator. If the buffer is not
+// large enough to accommodate the formatted string without truncation, they
+// return the number of characters that would be in the fully-formatted string
+// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
+inline int vsnprintfT(char* buffer,
+ size_t buf_size,
+ const char* format,
+ va_list argptr) {
+ return base::vsnprintf(buffer, buf_size, format, argptr);
+}
+
+#if defined(OS_WIN)
+inline int vsnprintfT(wchar_t* buffer,
+ size_t buf_size,
+ const wchar_t* format,
+ va_list argptr) {
+ return base::vswprintf(buffer, buf_size, format, argptr);
+}
+inline int vsnprintfT(char16_t* buffer,
+ size_t buf_size,
+ const char16_t* format,
+ va_list argptr) {
+ return base::vswprintf(reinterpret_cast<wchar_t*>(buffer), buf_size,
+ reinterpret_cast<const wchar_t*>(format), argptr);
+}
+#endif
+
+// Templatized backend for StringPrintF/StringAppendF. This does not finalize
+// the va_list, the caller is expected to do that.
+template <class CharT>
+static void StringAppendVT(std::basic_string<CharT>* dst,
+ const CharT* format,
+ va_list ap) {
+ // First try with a small fixed size buffer.
+ // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
+ // and StringUtilTest.StringPrintfBounds.
+ CharT stack_buf[1024];
+
+ va_list ap_copy;
+ va_copy(ap_copy, ap);
+
+ base::internal::ScopedClearLastError last_error;
+ int result = vsnprintfT(stack_buf, base::size(stack_buf), format, ap_copy);
+ va_end(ap_copy);
+
+ if (result >= 0 && result < static_cast<int>(base::size(stack_buf))) {
+ // It fit.
+ dst->append(stack_buf, result);
+ return;
+ }
+
+ // Repeatedly increase buffer size until it fits.
+ int mem_length = base::size(stack_buf);
+ while (true) {
+ if (result < 0) {
+#if defined(OS_WIN)
+ // On Windows, vsnprintfT always returns the number of characters in a
+ // fully-formatted string, so if we reach this point, something else is
+ // wrong and no amount of buffer-doubling is going to fix it.
+ return;
+#else
+ if (errno != 0 && errno != EOVERFLOW)
+ return;
+ // Try doubling the buffer size.
+ mem_length *= 2;
+#endif
+ } else {
+ // We need exactly "result + 1" characters.
+ mem_length = result + 1;
+ }
+
+ if (mem_length > 32 * 1024 * 1024) {
+ // That should be plenty, don't try anything larger. This protects
+ // against huge allocations when using vsnprintfT implementations that
+ // return -1 for reasons other than overflow without setting errno.
+ DLOG(WARNING) << "Unable to printf the requested string due to size.";
+ return;
+ }
+
+ std::vector<CharT> mem_buf(mem_length);
+
+ // NOTE: You can only use a va_list once. Since we're in a while loop, we
+ // need to make a new copy each time so we don't use up the original.
+ va_copy(ap_copy, ap);
+ result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
+ va_end(ap_copy);
+
+ if ((result >= 0) && (result < mem_length)) {
+ // It fit.
+ dst->append(&mem_buf[0], result);
+ return;
+ }
+ }
+}
+
+} // namespace
+
+std::string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+#if defined(OS_WIN)
+std::wstring StringPrintf(const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::wstring result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+std::u16string StringPrintf(const char16_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::u16string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+#endif
+
+std::string StringPrintV(const char* format, va_list ap) {
+ std::string result;
+ StringAppendV(&result, format, ap);
+ return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+#if defined(OS_WIN)
+const std::wstring& SStringPrintf(std::wstring* dst,
+ const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+const std::u16string& SStringPrintf(std::u16string* dst,
+ const char16_t* format,
+ ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+#endif
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+#if defined(OS_WIN)
+void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+void StringAppendF(std::u16string* dst, const char16_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+#endif
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+ StringAppendVT(dst, format, ap);
+}
+
+#if defined(OS_WIN)
+void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
+ StringAppendVT(dst, format, ap);
+}
+
+void StringAppendV(std::u16string* dst, const char16_t* format, va_list ap) {
+ StringAppendVT(dst, format, ap);
+}
+#endif
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/stringprintf.h b/security/sandbox/chromium/base/strings/stringprintf.h
new file mode 100644
index 0000000000..a8d5bc84e9
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/stringprintf.h
@@ -0,0 +1,74 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRINGPRINTF_H_
+#define BASE_STRINGS_STRINGPRINTF_H_
+
+#include <stdarg.h> // va_list
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Return a C++ string given printf-like input.
+BASE_EXPORT std::string StringPrintf(const char* format, ...)
+ PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+#if defined(OS_WIN)
+// Note: Unfortunately compile time checking of the format string for UTF-16
+// strings is not supported by any compiler, thus these functions should be used
+// carefully and sparingly. Also applies to SStringPrintf and StringAppendV
+// below.
+BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
+ WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+BASE_EXPORT std::u16string StringPrintf(const char16_t* format, ...)
+ WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+#endif
+
+// Return a C++ string given vprintf-like input.
+BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
+ PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT;
+
+// Store result into a supplied string and return it.
+BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
+ const char* format,
+ ...) PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
+ const wchar_t* format,
+ ...) WPRINTF_FORMAT(2, 3);
+BASE_EXPORT const std::u16string& SStringPrintf(std::u16string* dst,
+ const char16_t* format,
+ ...) WPRINTF_FORMAT(2, 3);
+#endif
+
+// Append result to a supplied string.
+BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
+ PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
+ WPRINTF_FORMAT(2, 3);
+BASE_EXPORT void StringAppendF(std::u16string* dst, const char16_t* format, ...)
+ WPRINTF_FORMAT(2, 3);
+#endif
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string. All other routines are just convenience wrappers around it.
+BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
+ PRINTF_FORMAT(2, 0);
+#if defined(OS_WIN)
+BASE_EXPORT void StringAppendV(std::wstring* dst,
+ const wchar_t* format,
+ va_list ap) WPRINTF_FORMAT(2, 0);
+BASE_EXPORT void StringAppendV(std::u16string* dst,
+ const char16_t* format,
+ va_list ap) WPRINTF_FORMAT(2, 0);
+#endif
+
+} // namespace base
+
+#endif // BASE_STRINGS_STRINGPRINTF_H_
diff --git a/security/sandbox/chromium/base/strings/utf_string_conversion_utils.cc b/security/sandbox/chromium/base/strings/utf_string_conversion_utils.cc
new file mode 100644
index 0000000000..f7682c1be9
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/utf_string_conversion_utils.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_string_conversion_utils.h"
+
+#include "base/third_party/icu/icu_utf.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+bool ReadUnicodeCharacter(const char* src,
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point_out) {
+ // U8_NEXT expects to be able to use -1 to signal an error, so we must
+ // use a signed type for code_point. But this function returns false
+ // on error anyway, so code_point_out is unsigned.
+ int32_t code_point;
+ CBU8_NEXT(src, *char_index, src_len, code_point);
+ *code_point_out = static_cast<uint32_t>(code_point);
+
+ // The ICU macro above moves to the next char, we want to point to the last
+ // char consumed.
+ (*char_index)--;
+
+ // Validate the decoded value.
+ return IsValidCodepoint(code_point);
+}
+
+bool ReadUnicodeCharacter(const char16* src,
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point) {
+ if (CBU16_IS_SURROGATE(src[*char_index])) {
+ if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) ||
+ *char_index + 1 >= src_len ||
+ !CBU16_IS_TRAIL(src[*char_index + 1])) {
+ // Invalid surrogate pair.
+ return false;
+ }
+
+ // Valid surrogate pair.
+ *code_point = CBU16_GET_SUPPLEMENTARY(src[*char_index],
+ src[*char_index + 1]);
+ (*char_index)++;
+ } else {
+ // Not a surrogate, just one 16-bit word.
+ *code_point = src[*char_index];
+ }
+
+ return IsValidCodepoint(*code_point);
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+bool ReadUnicodeCharacter(const wchar_t* src,
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point) {
+ // Conversion is easy since the source is 32-bit.
+ *code_point = src[*char_index];
+
+ // Validate the value.
+ return IsValidCodepoint(*code_point);
+}
+#endif // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+size_t WriteUnicodeCharacter(uint32_t code_point, std::string* output) {
+ if (code_point <= 0x7f) {
+ // Fast path the common case of one byte.
+ output->push_back(static_cast<char>(code_point));
+ return 1;
+ }
+
+
+ // CBU8_APPEND_UNSAFE can append up to 4 bytes.
+ size_t char_offset = output->length();
+ size_t original_char_offset = char_offset;
+ output->resize(char_offset + CBU8_MAX_LENGTH);
+
+ CBU8_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+
+ // CBU8_APPEND_UNSAFE will advance our pointer past the inserted character, so
+ // it will represent the new length of the string.
+ output->resize(char_offset);
+ return char_offset - original_char_offset;
+}
+
+size_t WriteUnicodeCharacter(uint32_t code_point, string16* output) {
+ if (CBU16_LENGTH(code_point) == 1) {
+ // Thie code point is in the Basic Multilingual Plane (BMP).
+ output->push_back(static_cast<char16>(code_point));
+ return 1;
+ }
+ // Non-BMP characters use a double-character encoding.
+ size_t char_offset = output->length();
+ output->resize(char_offset + CBU16_MAX_LENGTH);
+ CBU16_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+ return CBU16_MAX_LENGTH;
+}
+
+// Generalized Unicode converter -----------------------------------------------
+
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src,
+ size_t src_len,
+ std::string* output) {
+ output->clear();
+ if (src_len == 0)
+ return;
+ if (src[0] < 0x80) {
+ // Assume that the entire input will be ASCII.
+ output->reserve(src_len);
+ } else {
+ // Assume that the entire input is non-ASCII and will have 3 bytes per char.
+ output->reserve(src_len * 3);
+ }
+}
+
+// Instantiate versions we know callers will need.
+#if !defined(OS_WIN)
+// wchar_t and char16 are the same thing on Windows.
+template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*);
+#endif
+template void PrepareForUTF8Output(const char16*, size_t, std::string*);
+
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src,
+ size_t src_len,
+ STRING* output) {
+ output->clear();
+ if (src_len == 0)
+ return;
+ if (static_cast<unsigned char>(src[0]) < 0x80) {
+ // Assume the input is all ASCII, which means 1:1 correspondence.
+ output->reserve(src_len);
+ } else {
+ // Otherwise assume that the UTF-8 sequences will have 2 bytes for each
+ // character.
+ output->reserve(src_len / 2);
+ }
+}
+
+// Instantiate versions we know callers will need.
+#if !defined(OS_WIN)
+// std::wstring and string16 are the same thing on Windows.
+template void PrepareForUTF16Or32Output(const char*, size_t, std::wstring*);
+#endif
+template void PrepareForUTF16Or32Output(const char*, size_t, string16*);
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/utf_string_conversion_utils.h b/security/sandbox/chromium/base/strings/utf_string_conversion_utils.h
new file mode 100644
index 0000000000..01d24c3e2e
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/utf_string_conversion_utils.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
+#define BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
+
+// Low-level UTF handling functions. Most code will want to use the functions
+// in utf_string_conversions.h
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+inline bool IsValidCodepoint(uint32_t code_point) {
+ // Excludes code points that are not Unicode scalar values, i.e.
+ // surrogate code points ([0xD800, 0xDFFF]). Additionally, excludes
+ // code points larger than 0x10FFFF (the highest codepoint allowed).
+ // Non-characters and unassigned code points are allowed.
+ // https://unicode.org/glossary/#unicode_scalar_value
+ return code_point < 0xD800u ||
+ (code_point >= 0xE000u && code_point <= 0x10FFFFu);
+}
+
+inline bool IsValidCharacter(uint32_t code_point) {
+ // Excludes non-characters (U+FDD0..U+FDEF, and all code points
+ // ending in 0xFFFE or 0xFFFF) from the set of valid code points.
+ // https://unicode.org/faq/private_use.html#nonchar1
+ return code_point < 0xD800u || (code_point >= 0xE000u &&
+ code_point < 0xFDD0u) || (code_point > 0xFDEFu &&
+ code_point <= 0x10FFFFu && (code_point & 0xFFFEu) != 0xFFFEu);
+}
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+// Reads a UTF-8 stream, placing the next code point into the given output
+// |*code_point|. |src| represents the entire string to read, and |*char_index|
+// is the character offset within the string to start reading at. |*char_index|
+// will be updated to index the last character read, such that incrementing it
+// (as in a for loop) will take the reader to the next character.
+//
+// Returns true on success. On false, |*code_point| will be invalid.
+BASE_EXPORT bool ReadUnicodeCharacter(const char* src,
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point_out);
+
+// Reads a UTF-16 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const char16* src,
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Reads UTF-32 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const wchar_t* src,
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point);
+#endif // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+// Appends a UTF-8 character to the given 8-bit string. Returns the number of
+// bytes written.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t code_point,
+ std::string* output);
+
+// Appends the given code point as a UTF-16 character to the given 16-bit
+// string. Returns the number of 16-bit values written.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t code_point, string16* output);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Appends the given UTF-32 character to the given 32-bit string. Returns the
+// number of 32-bit values written.
+inline size_t WriteUnicodeCharacter(uint32_t code_point, std::wstring* output) {
+ // This is the easy case, just append the character.
+ output->push_back(code_point);
+ return 1;
+}
+#endif // defined(WCHAR_T_IS_UTF32)
+
+// Generalized Unicode converter -----------------------------------------------
+
+// Guesses the length of the output in UTF-8 in bytes, clears that output
+// string, and reserves that amount of space. We assume that the input
+// character types are unsigned, which will be true for UTF-16 and -32 on our
+// systems.
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src, size_t src_len, std::string* output);
+
+// Prepares an output buffer (containing either UTF-16 or -32 data) given some
+// UTF-8 input that will be converted to it. See PrepareForUTF8Output().
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src, size_t src_len, STRING* output);
+
+} // namespace base
+
+#endif // BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
diff --git a/security/sandbox/chromium/base/strings/utf_string_conversions.cc b/security/sandbox/chromium/base/strings/utf_string_conversions.cc
new file mode 100644
index 0000000000..9a79889159
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/utf_string_conversions.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/utf_string_conversions.h"
+
+#include <limits.h>
+#include <stdint.h>
+
+#include <type_traits>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+
+constexpr int32_t kErrorCodePoint = 0xFFFD;
+
+// Size coefficient ----------------------------------------------------------
+// The maximum number of codeunits in the destination encoding corresponding to
+// one codeunit in the source encoding.
+
+template <typename SrcChar, typename DestChar>
+struct SizeCoefficient {
+ static_assert(sizeof(SrcChar) < sizeof(DestChar),
+ "Default case: from a smaller encoding to the bigger one");
+
+ // ASCII symbols are encoded by one codeunit in all encodings.
+ static constexpr int value = 1;
+};
+
+template <>
+struct SizeCoefficient<char16, char> {
+ // One UTF-16 codeunit corresponds to at most 3 codeunits in UTF-8.
+ static constexpr int value = 3;
+};
+
+#if defined(WCHAR_T_IS_UTF32)
+template <>
+struct SizeCoefficient<wchar_t, char> {
+ // UTF-8 uses at most 4 codeunits per character.
+ static constexpr int value = 4;
+};
+
+template <>
+struct SizeCoefficient<wchar_t, char16> {
+ // UTF-16 uses at most 2 codeunits per character.
+ static constexpr int value = 2;
+};
+#endif // defined(WCHAR_T_IS_UTF32)
+
+template <typename SrcChar, typename DestChar>
+constexpr int size_coefficient_v =
+ SizeCoefficient<std::decay_t<SrcChar>, std::decay_t<DestChar>>::value;
+
+// UnicodeAppendUnsafe --------------------------------------------------------
+// Function overloads that write code_point to the output string. Output string
+// has to have enough space for the codepoint.
+
+// Convenience typedef that checks whether the passed in type is integral (i.e.
+// bool, char, int or their extended versions) and is of the correct size.
+template <typename Char, size_t N>
+using EnableIfBitsAre = std::enable_if_t<std::is_integral<Char>::value &&
+ CHAR_BIT * sizeof(Char) == N,
+ bool>;
+
+template <typename Char, EnableIfBitsAre<Char, 8> = true>
+void UnicodeAppendUnsafe(Char* out, int32_t* size, uint32_t code_point) {
+ CBU8_APPEND_UNSAFE(out, *size, code_point);
+}
+
+template <typename Char, EnableIfBitsAre<Char, 16> = true>
+void UnicodeAppendUnsafe(Char* out, int32_t* size, uint32_t code_point) {
+ CBU16_APPEND_UNSAFE(out, *size, code_point);
+}
+
+template <typename Char, EnableIfBitsAre<Char, 32> = true>
+void UnicodeAppendUnsafe(Char* out, int32_t* size, uint32_t code_point) {
+ out[(*size)++] = code_point;
+}
+
+// DoUTFConversion ------------------------------------------------------------
+// Main driver of UTFConversion specialized for different Src encodings.
+// dest has to have enough room for the converted text.
+
+template <typename DestChar>
+bool DoUTFConversion(const char* src,
+ int32_t src_len,
+ DestChar* dest,
+ int32_t* dest_len) {
+ bool success = true;
+
+ for (int32_t i = 0; i < src_len;) {
+ int32_t code_point;
+ CBU8_NEXT(src, i, src_len, code_point);
+
+ if (!IsValidCodepoint(code_point)) {
+ success = false;
+ code_point = kErrorCodePoint;
+ }
+
+ UnicodeAppendUnsafe(dest, dest_len, code_point);
+ }
+
+ return success;
+}
+
+template <typename DestChar>
+bool DoUTFConversion(const char16* src,
+ int32_t src_len,
+ DestChar* dest,
+ int32_t* dest_len) {
+ bool success = true;
+
+ auto ConvertSingleChar = [&success](char16 in) -> int32_t {
+ if (!CBU16_IS_SINGLE(in) || !IsValidCodepoint(in)) {
+ success = false;
+ return kErrorCodePoint;
+ }
+ return in;
+ };
+
+ int32_t i = 0;
+
+ // Always have another symbol in order to avoid checking boundaries in the
+ // middle of the surrogate pair.
+ while (i < src_len - 1) {
+ int32_t code_point;
+
+ if (CBU16_IS_LEAD(src[i]) && CBU16_IS_TRAIL(src[i + 1])) {
+ code_point = CBU16_GET_SUPPLEMENTARY(src[i], src[i + 1]);
+ if (!IsValidCodepoint(code_point)) {
+ code_point = kErrorCodePoint;
+ success = false;
+ }
+ i += 2;
+ } else {
+ code_point = ConvertSingleChar(src[i]);
+ ++i;
+ }
+
+ UnicodeAppendUnsafe(dest, dest_len, code_point);
+ }
+
+ if (i < src_len)
+ UnicodeAppendUnsafe(dest, dest_len, ConvertSingleChar(src[i]));
+
+ return success;
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+
+template <typename DestChar>
+bool DoUTFConversion(const wchar_t* src,
+ int32_t src_len,
+ DestChar* dest,
+ int32_t* dest_len) {
+ bool success = true;
+
+ for (int32_t i = 0; i < src_len; ++i) {
+ int32_t code_point = src[i];
+
+ if (!IsValidCodepoint(code_point)) {
+ success = false;
+ code_point = kErrorCodePoint;
+ }
+
+ UnicodeAppendUnsafe(dest, dest_len, code_point);
+ }
+
+ return success;
+}
+
+#endif // defined(WCHAR_T_IS_UTF32)
+
+// UTFConversion --------------------------------------------------------------
+// Function template for generating all UTF conversions.
+
+template <typename InputString, typename DestString>
+bool UTFConversion(const InputString& src_str, DestString* dest_str) {
+ if (IsStringASCII(src_str)) {
+ dest_str->assign(src_str.begin(), src_str.end());
+ return true;
+ }
+
+ dest_str->resize(src_str.length() *
+ size_coefficient_v<typename InputString::value_type,
+ typename DestString::value_type>);
+
+ // Empty string is ASCII => it OK to call operator[].
+ auto* dest = &(*dest_str)[0];
+
+ // ICU requires 32 bit numbers.
+ int32_t src_len32 = static_cast<int32_t>(src_str.length());
+ int32_t dest_len32 = 0;
+
+ bool res = DoUTFConversion(src_str.data(), src_len32, dest, &dest_len32);
+
+ dest_str->resize(dest_len32);
+ dest_str->shrink_to_fit();
+
+ return res;
+}
+
+} // namespace
+
+// UTF16 <-> UTF8 --------------------------------------------------------------
+
+bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
+ return UTFConversion(StringPiece(src, src_len), output);
+}
+
+string16 UTF8ToUTF16(StringPiece utf8) {
+ string16 ret;
+ // Ignore the success flag of this call, it will do the best it can for
+ // invalid input, which is what we want here.
+ UTF8ToUTF16(utf8.data(), utf8.size(), &ret);
+ return ret;
+}
+
+bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
+ return UTFConversion(StringPiece16(src, src_len), output);
+}
+
+std::string UTF16ToUTF8(StringPiece16 utf16) {
+ std::string ret;
+ // Ignore the success flag of this call, it will do the best it can for
+ // invalid input, which is what we want here.
+ UTF16ToUTF8(utf16.data(), utf16.length(), &ret);
+ return ret;
+}
+
+// UTF-16 <-> Wide -------------------------------------------------------------
+
+#if defined(WCHAR_T_IS_UTF16)
+// When wide == UTF-16 the conversions are a NOP.
+
+bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) {
+ output->assign(src, src + src_len);
+ return true;
+}
+
+string16 WideToUTF16(WStringPiece wide) {
+ return string16(wide.begin(), wide.end());
+}
+
+bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) {
+ output->assign(src, src + src_len);
+ return true;
+}
+
+std::wstring UTF16ToWide(StringPiece16 utf16) {
+ return std::wstring(utf16.begin(), utf16.end());
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) {
+ return UTFConversion(base::WStringPiece(src, src_len), output);
+}
+
+string16 WideToUTF16(WStringPiece wide) {
+ string16 ret;
+ // Ignore the success flag of this call, it will do the best it can for
+ // invalid input, which is what we want here.
+ WideToUTF16(wide.data(), wide.length(), &ret);
+ return ret;
+}
+
+bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) {
+ return UTFConversion(StringPiece16(src, src_len), output);
+}
+
+std::wstring UTF16ToWide(StringPiece16 utf16) {
+ std::wstring ret;
+ // Ignore the success flag of this call, it will do the best it can for
+ // invalid input, which is what we want here.
+ UTF16ToWide(utf16.data(), utf16.length(), &ret);
+ return ret;
+}
+
+#endif // defined(WCHAR_T_IS_UTF32)
+
+// UTF-8 <-> Wide --------------------------------------------------------------
+
+// UTF8ToWide is the same code, regardless of whether wide is 16 or 32 bits
+
+bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output) {
+ return UTFConversion(StringPiece(src, src_len), output);
+}
+
+std::wstring UTF8ToWide(StringPiece utf8) {
+ std::wstring ret;
+ // Ignore the success flag of this call, it will do the best it can for
+ // invalid input, which is what we want here.
+ UTF8ToWide(utf8.data(), utf8.length(), &ret);
+ return ret;
+}
+
+#if defined(WCHAR_T_IS_UTF16)
+// Easy case since we can use the "utf" versions we already wrote above.
+
+bool WideToUTF8(const wchar_t* src, size_t src_len, std::string* output) {
+ return UTF16ToUTF8(as_u16cstr(src), src_len, output);
+}
+
+std::string WideToUTF8(WStringPiece wide) {
+ return UTF16ToUTF8(StringPiece16(as_u16cstr(wide), wide.size()));
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+bool WideToUTF8(const wchar_t* src, size_t src_len, std::string* output) {
+ return UTFConversion(WStringPiece(src, src_len), output);
+}
+
+std::string WideToUTF8(WStringPiece wide) {
+ std::string ret;
+ // Ignore the success flag of this call, it will do the best it can for
+ // invalid input, which is what we want here.
+ WideToUTF8(wide.data(), wide.length(), &ret);
+ return ret;
+}
+
+#endif // defined(WCHAR_T_IS_UTF32)
+
+string16 ASCIIToUTF16(StringPiece ascii) {
+ DCHECK(IsStringASCII(ascii)) << ascii;
+ return string16(ascii.begin(), ascii.end());
+}
+
+std::string UTF16ToASCII(StringPiece16 utf16) {
+ DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
+ return std::string(utf16.begin(), utf16.end());
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/strings/utf_string_conversions.h b/security/sandbox/chromium/base/strings/utf_string_conversions.h
new file mode 100644
index 0000000000..f780fb4f4f
--- /dev/null
+++ b/security/sandbox/chromium/base/strings/utf_string_conversions.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// These convert between UTF-8, -16, and -32 strings. They are potentially slow,
+// so avoid unnecessary conversions. The low-level versions return a boolean
+// indicating whether the conversion was 100% valid. In this case, it will still
+// do the best it can and put the result in the output buffer. The versions that
+// return strings ignore this error and just return the best conversion
+// possible.
+BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len,
+ std::string* output);
+BASE_EXPORT std::string WideToUTF8(WStringPiece wide) WARN_UNUSED_RESULT;
+BASE_EXPORT bool UTF8ToWide(const char* src, size_t src_len,
+ std::wstring* output);
+BASE_EXPORT std::wstring UTF8ToWide(StringPiece utf8) WARN_UNUSED_RESULT;
+
+BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len,
+ string16* output);
+BASE_EXPORT string16 WideToUTF16(WStringPiece wide) WARN_UNUSED_RESULT;
+BASE_EXPORT bool UTF16ToWide(const char16* src, size_t src_len,
+ std::wstring* output);
+BASE_EXPORT std::wstring UTF16ToWide(StringPiece16 utf16) WARN_UNUSED_RESULT;
+
+BASE_EXPORT bool UTF8ToUTF16(const char* src, size_t src_len, string16* output);
+BASE_EXPORT string16 UTF8ToUTF16(StringPiece utf8) WARN_UNUSED_RESULT;
+BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
+ std::string* output);
+BASE_EXPORT std::string UTF16ToUTF8(StringPiece16 utf16) WARN_UNUSED_RESULT;
+
+// This converts an ASCII string, typically a hardcoded constant, to a UTF16
+// string.
+BASE_EXPORT string16 ASCIIToUTF16(StringPiece ascii) WARN_UNUSED_RESULT;
+
+// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
+// beforehand.
+BASE_EXPORT std::string UTF16ToASCII(StringPiece16 utf16) WARN_UNUSED_RESULT;
+
+} // namespace base
+
+#endif // BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
diff --git a/security/sandbox/chromium/base/synchronization/atomic_flag.h b/security/sandbox/chromium/base/synchronization/atomic_flag.h
new file mode 100644
index 0000000000..f386a16cbd
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/atomic_flag.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_ATOMIC_FLAG_H_
+#define BASE_SYNCHRONIZATION_ATOMIC_FLAG_H_
+
+#include <stdint.h>
+
+#include <atomic>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
+
+namespace base {
+
+// A flag that can safely be set from one thread and read from other threads.
+//
+// This class IS NOT intended for synchronization between threads.
+class BASE_EXPORT AtomicFlag {
+ public:
+ AtomicFlag();
+ ~AtomicFlag();
+
+ // Set the flag. Must always be called from the same sequence.
+ void Set();
+
+ // Returns true iff the flag was set. If this returns true, the current thread
+ // is guaranteed to be synchronized with all memory operations on the sequence
+ // which invoked Set() up until at least the first call to Set() on it.
+ bool IsSet() const {
+ // Inline here: this has a measurable performance impact on base::WeakPtr.
+ return flag_.load(std::memory_order_acquire) != 0;
+ }
+
+ // Resets the flag. Be careful when using this: callers might not expect
+ // IsSet() to return false after returning true once.
+ void UnsafeResetForTesting();
+
+ private:
+ std::atomic<uint_fast8_t> flag_{0};
+ SEQUENCE_CHECKER(set_sequence_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(AtomicFlag);
+};
+
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_ATOMIC_FLAG_H_
diff --git a/security/sandbox/chromium/base/synchronization/condition_variable.h b/security/sandbox/chromium/base/synchronization/condition_variable.h
new file mode 100644
index 0000000000..d92b738081
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/condition_variable.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ConditionVariable wraps pthreads condition variable synchronization or, on
+// Windows, simulates it. This functionality is very helpful for having
+// several threads wait for an event, as is common with a thread pool managed
+// by a master. The meaning of such an event in the (worker) thread pool
+// scenario is that additional tasks are now available for processing. It is
+// used in Chrome in the DNS prefetching system to notify worker threads that
+// a queue now has items (tasks) which need to be tended to. A related use
+// would have a pool manager waiting on a ConditionVariable, waiting for a
+// thread in the pool to announce (signal) that there is now more room in a
+// (bounded size) communications queue for the manager to deposit tasks, or,
+// as a second example, that the queue of tasks is completely empty and all
+// workers are waiting.
+//
+// USAGE NOTE 1: spurious signal events are possible with this and
+// most implementations of condition variables. As a result, be
+// *sure* to retest your condition before proceeding. The following
+// is a good example of doing this correctly:
+//
+// while (!work_to_be_done()) Wait(...);
+//
+// In contrast do NOT do the following:
+//
+// if (!work_to_be_done()) Wait(...); // Don't do this.
+//
+// Especially avoid the above if you are relying on some other thread only
+// issuing a signal up *if* there is work-to-do. There can/will
+// be spurious signals. Recheck state on waiting thread before
+// assuming the signal was intentional. Caveat caller ;-).
+//
+// USAGE NOTE 2: Broadcast() frees up all waiting threads at once,
+// which leads to contention for the locks they all held when they
+// called Wait(). This results in POOR performance. A much better
+// approach to getting a lot of threads out of Wait() is to have each
+// thread (upon exiting Wait()) call Signal() to free up another
+// Wait'ing thread. Look at condition_variable_unittest.cc for
+// both examples.
+//
+// Broadcast() can be used nicely during teardown, as it gets the job
+// done, and leaves no sleeping threads... and performance is less
+// critical at that point.
+//
+// The semantics of Broadcast() are carefully crafted so that *all*
+// threads that were waiting when the request was made will indeed
+// get signaled. Some implementations mess up, and don't signal them
+// all, while others allow the wait to be effectively turned off (for
+// a while while waiting threads come around). This implementation
+// appears correct, as it will not "lose" any signals, and will guarantee
+// that all threads get signaled by Broadcast().
+//
+// This implementation offers support for "performance" in its selection of
+// which thread to revive. Performance, in direct contrast with "fairness,"
+// assures that the thread that most recently began to Wait() is selected by
+// Signal to revive. Fairness would (if publicly supported) assure that the
+// thread that has Wait()ed the longest is selected. The default policy
+// may improve performance, as the selected thread may have a greater chance of
+// having some of its stack data in various CPU caches.
+
+#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_types.h"
+#endif
+
+namespace base {
+
+class TimeDelta;
+
+class BASE_EXPORT ConditionVariable {
+ public:
+ // Construct a cv for use with ONLY one user lock.
+ explicit ConditionVariable(Lock* user_lock);
+
+ ~ConditionVariable();
+
+ // Wait() releases the caller's critical section atomically as it starts to
+ // sleep, and the reacquires it when it is signaled. The wait functions are
+ // susceptible to spurious wakeups. (See usage note 1 for more details.)
+ void Wait();
+ void TimedWait(const TimeDelta& max_time);
+
+ // Broadcast() revives all waiting threads. (See usage note 2 for more
+ // details.)
+ void Broadcast();
+ // Signal() revives one waiting thread.
+ void Signal();
+
+ // Declares that this ConditionVariable will only ever be used by a thread
+ // that is idle at the bottom of its stack and waiting for work (in
+ // particular, it is not synchronously waiting on this ConditionVariable
+ // before resuming ongoing work). This is useful to avoid telling
+ // base-internals that this thread is "blocked" when it's merely idle and
+ // ready to do work. As such, this is only expected to be used by thread and
+ // thread pool impls.
+ void declare_only_used_while_idle() { waiting_is_blocking_ = false; }
+
+ private:
+
+#if defined(OS_WIN)
+ CHROME_CONDITION_VARIABLE cv_;
+ CHROME_SRWLOCK* const srwlock_;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ pthread_cond_t condition_;
+ pthread_mutex_t* user_mutex_;
+#endif
+
+#if DCHECK_IS_ON()
+ base::Lock* const user_lock_; // Needed to adjust shadow lock state on wait.
+#endif
+
+ // Whether a thread invoking Wait() on this ConditionalVariable should be
+ // considered blocked as opposed to idle (and potentially replaced if part of
+ // a pool).
+ bool waiting_is_blocking_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
+};
+
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
diff --git a/security/sandbox/chromium/base/synchronization/condition_variable_posix.cc b/security/sandbox/chromium/base/synchronization/condition_variable_posix.cc
new file mode 100644
index 0000000000..189eb360d2
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/condition_variable_posix.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/condition_variable.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "base/optional.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+ : user_mutex_(user_lock->lock_.native_handle())
+#if DCHECK_IS_ON()
+ , user_lock_(user_lock)
+#endif
+{
+ int rv = 0;
+ // http://crbug.com/293736
+ // NaCl doesn't support monotonic clock based absolute deadlines.
+ // On older Android platform versions, it's supported through the
+ // non-standard pthread_cond_timedwait_monotonic_np. Newer platform
+ // versions have pthread_condattr_setclock.
+ // Mac can use relative time deadlines.
+#if !defined(OS_MACOSX) && !defined(OS_NACL) && \
+ !(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+ pthread_condattr_t attrs;
+ rv = pthread_condattr_init(&attrs);
+ DCHECK_EQ(0, rv);
+ pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
+ rv = pthread_cond_init(&condition_, &attrs);
+ pthread_condattr_destroy(&attrs);
+#else
+ rv = pthread_cond_init(&condition_, NULL);
+#endif
+ DCHECK_EQ(0, rv);
+}
+
+ConditionVariable::~ConditionVariable() {
+#if defined(OS_MACOSX)
+ // This hack is necessary to avoid a fatal pthreads subsystem bug in the
+ // Darwin kernel. http://crbug.com/517681.
+ {
+ base::Lock lock;
+ base::AutoLock l(lock);
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1;
+ pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
+ &ts);
+ }
+#endif
+
+ int rv = pthread_cond_destroy(&condition_);
+ DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Wait() {
+ Optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
+ scoped_blocking_call;
+ if (waiting_is_blocking_)
+ scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
+
+#if DCHECK_IS_ON()
+ user_lock_->CheckHeldAndUnmark();
+#endif
+ int rv = pthread_cond_wait(&condition_, user_mutex_);
+ DCHECK_EQ(0, rv);
+#if DCHECK_IS_ON()
+ user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+ Optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
+ scoped_blocking_call;
+ if (waiting_is_blocking_)
+ scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
+
+ int64_t usecs = max_time.InMicroseconds();
+ struct timespec relative_time;
+ relative_time.tv_sec = usecs / Time::kMicrosecondsPerSecond;
+ relative_time.tv_nsec =
+ (usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
+
+#if DCHECK_IS_ON()
+ user_lock_->CheckHeldAndUnmark();
+#endif
+
+#if defined(OS_MACOSX)
+ int rv = pthread_cond_timedwait_relative_np(
+ &condition_, user_mutex_, &relative_time);
+#else
+ // The timeout argument to pthread_cond_timedwait is in absolute time.
+ struct timespec absolute_time;
+#if defined(OS_NACL)
+ // See comment in constructor for why this is different in NaCl.
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ absolute_time.tv_sec = now.tv_sec;
+ absolute_time.tv_nsec = now.tv_usec * Time::kNanosecondsPerMicrosecond;
+#else
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ absolute_time.tv_sec = now.tv_sec;
+ absolute_time.tv_nsec = now.tv_nsec;
+#endif
+
+ absolute_time.tv_sec += relative_time.tv_sec;
+ absolute_time.tv_nsec += relative_time.tv_nsec;
+ absolute_time.tv_sec += absolute_time.tv_nsec / Time::kNanosecondsPerSecond;
+ absolute_time.tv_nsec %= Time::kNanosecondsPerSecond;
+ DCHECK_GE(absolute_time.tv_sec, now.tv_sec); // Overflow paranoia
+
+#if defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+ int rv = pthread_cond_timedwait_monotonic_np(
+ &condition_, user_mutex_, &absolute_time);
+#else
+ int rv = pthread_cond_timedwait(&condition_, user_mutex_, &absolute_time);
+#endif // OS_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+#endif // OS_MACOSX
+
+ // On failure, we only expect the CV to timeout. Any other error value means
+ // that we've unexpectedly woken up.
+ DCHECK(rv == 0 || rv == ETIMEDOUT);
+#if DCHECK_IS_ON()
+ user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::Broadcast() {
+ int rv = pthread_cond_broadcast(&condition_);
+ DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Signal() {
+ int rv = pthread_cond_signal(&condition_);
+ DCHECK_EQ(0, rv);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/synchronization/lock.cc b/security/sandbox/chromium/base/synchronization/lock.cc
new file mode 100644
index 0000000000..03297ada52
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/lock.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is used for debugging assertion support. The Lock class
+// is functionally a wrapper around the LockImpl class, so the only
+// real intelligence in the class is in the debugging logic.
+
+#include "base/synchronization/lock.h"
+
+#if DCHECK_IS_ON()
+
+namespace base {
+
+Lock::Lock() : lock_() {
+}
+
+Lock::~Lock() {
+ DCHECK(owning_thread_ref_.is_null());
+}
+
+void Lock::AssertAcquired() const {
+ DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+}
+
+void Lock::CheckHeldAndUnmark() {
+ DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+ owning_thread_ref_ = PlatformThreadRef();
+}
+
+void Lock::CheckUnheldAndMark() {
+ DCHECK(owning_thread_ref_.is_null());
+ owning_thread_ref_ = PlatformThread::CurrentRef();
+}
+
+} // namespace base
+
+#endif // DCHECK_IS_ON()
diff --git a/security/sandbox/chromium/base/synchronization/lock.h b/security/sandbox/chromium/base/synchronization/lock.h
new file mode 100644
index 0000000000..00095ab3af
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/lock.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_H_
+#define BASE_SYNCHRONIZATION_LOCK_H_
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/thread_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// A convenient wrapper for an OS specific critical section. The only real
+// intelligence in this class is in debug mode for the support for the
+// AssertAcquired() method.
+class LOCKABLE BASE_EXPORT Lock {
+ public:
+#if !DCHECK_IS_ON()
+ // Optimized wrapper implementation
+ Lock() : lock_() {}
+ ~Lock() {}
+
+ // TODO(lukasza): https://crbug.com/831825: Add EXCLUSIVE_LOCK_FUNCTION
+ // annotation to Acquire method and similar annotations to Release and Try
+ // methods (here and in the #else branch).
+ void Acquire() { lock_.Lock(); }
+ void Release() { lock_.Unlock(); }
+
+ // If the lock is not held, take it and return true. If the lock is already
+ // held by another thread, immediately return false. This must not be called
+ // by a thread already holding the lock (what happens is undefined and an
+ // assertion may fail).
+ bool Try() { return lock_.Try(); }
+
+ // Null implementation if not debug.
+ void AssertAcquired() const ASSERT_EXCLUSIVE_LOCK() {}
+#else
+ Lock();
+ ~Lock();
+
+ // NOTE: We do not permit recursive locks and will commonly fire a DCHECK() if
+ // a thread attempts to acquire the lock a second time (while already holding
+ // it).
+ void Acquire() {
+ lock_.Lock();
+ CheckUnheldAndMark();
+ }
+ void Release() {
+ CheckHeldAndUnmark();
+ lock_.Unlock();
+ }
+
+ bool Try() {
+ bool rv = lock_.Try();
+ if (rv) {
+ CheckUnheldAndMark();
+ }
+ return rv;
+ }
+
+ void AssertAcquired() const ASSERT_EXCLUSIVE_LOCK();
+#endif // DCHECK_IS_ON()
+
+ // Whether Lock mitigates priority inversion when used from different thread
+ // priorities.
+ static bool HandlesMultipleThreadPriorities() {
+#if defined(OS_WIN)
+ // Windows mitigates priority inversion by randomly boosting the priority of
+ // ready threads.
+ // https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx
+ return true;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // POSIX mitigates priority inversion by setting the priority of a thread
+ // holding a Lock to the maximum priority of any other thread waiting on it.
+ return internal::LockImpl::PriorityInheritanceAvailable();
+#else
+#error Unsupported platform
+#endif
+ }
+
+ // Both Windows and POSIX implementations of ConditionVariable need to be
+ // able to see our lock and tweak our debugging counters, as they release and
+ // acquire locks inside of their condition variable APIs.
+ friend class ConditionVariable;
+
+ private:
+#if DCHECK_IS_ON()
+ // Members and routines taking care of locks assertions.
+ // Note that this checks for recursive locks and allows them
+ // if the variable is set. This is allowed by the underlying implementation
+ // on windows but not on Posix, so we're doing unneeded checks on Posix.
+ // It's worth it to share the code.
+ void CheckHeldAndUnmark();
+ void CheckUnheldAndMark();
+
+ // All private data is implicitly protected by lock_.
+ // Be VERY careful to only access members under that lock.
+ base::PlatformThreadRef owning_thread_ref_;
+#endif // DCHECK_IS_ON()
+
+ // Platform specific underlying lock implementation.
+ internal::LockImpl lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(Lock);
+};
+
+// A helper class that acquires the given Lock while the AutoLock is in scope.
+using AutoLock = internal::BasicAutoLock<Lock>;
+
+// AutoUnlock is a helper that will Release() the |lock| argument in the
+// constructor, and re-Acquire() it in the destructor.
+using AutoUnlock = internal::BasicAutoUnlock<Lock>;
+
+// Like AutoLock but is a no-op when the provided Lock* is null. Inspired from
+// absl::MutexLockMaybe. Use this instead of base::Optional<base::AutoLock> to
+// get around -Wthread-safety-analysis warnings for conditional locking.
+using AutoLockMaybe = internal::BasicAutoLockMaybe<Lock>;
+
+// Like AutoLock but permits Release() of its mutex before destruction.
+// Release() may be called at most once. Inspired from
+// absl::ReleasableMutexLock. Use this instead of base::Optional<base::AutoLock>
+// to get around -Wthread-safety-analysis warnings for AutoLocks that are
+// explicitly released early (prefer proper scoping to this).
+using ReleasableAutoLock = internal::BasicReleasableAutoLock<Lock>;
+
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_LOCK_H_
diff --git a/security/sandbox/chromium/base/synchronization/lock_impl.h b/security/sandbox/chromium/base/synchronization/lock_impl.h
new file mode 100644
index 0000000000..830b878e8e
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/lock_impl.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/thread_annotations.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_types.h"
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <errno.h>
+#include <pthread.h>
+#endif
+
+namespace base {
+namespace internal {
+
+// This class implements the underlying platform-specific spin-lock mechanism
+// used for the Lock class. Most users should not use LockImpl directly, but
+// should instead use Lock.
+class BASE_EXPORT LockImpl {
+ public:
+#if defined(OS_WIN)
+ using NativeHandle = CHROME_SRWLOCK;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ using NativeHandle = pthread_mutex_t;
+#endif
+
+ LockImpl();
+ ~LockImpl();
+
+ // If the lock is not held, take it and return true. If the lock is already
+ // held by something else, immediately return false.
+ bool Try();
+
+ // Take the lock, blocking until it is available if necessary.
+ void Lock();
+
+ // Release the lock. This must only be called by the lock's holder: after
+ // a successful call to Try, or a call to Lock.
+ inline void Unlock();
+
+ // Return the native underlying lock.
+ // TODO(awalker): refactor lock and condition variables so that this is
+ // unnecessary.
+ NativeHandle* native_handle() { return &native_handle_; }
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // Whether this lock will attempt to use priority inheritance.
+ static bool PriorityInheritanceAvailable();
+#endif
+
+ private:
+ NativeHandle native_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockImpl);
+};
+
+#if defined(OS_WIN)
+void LockImpl::Unlock() {
+ ::ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&native_handle_));
+}
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+void LockImpl::Unlock() {
+ int rv = pthread_mutex_unlock(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+#endif
+
+// This is an implementation used for AutoLock templated on the lock type.
+template <class LockType>
+class SCOPED_LOCKABLE BasicAutoLock {
+ public:
+ struct AlreadyAcquired {};
+
+ explicit BasicAutoLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock)
+ : lock_(lock) {
+ lock_.Acquire();
+ }
+
+ BasicAutoLock(LockType& lock, const AlreadyAcquired&)
+ EXCLUSIVE_LOCKS_REQUIRED(lock)
+ : lock_(lock) {
+ lock_.AssertAcquired();
+ }
+
+ ~BasicAutoLock() UNLOCK_FUNCTION() {
+ lock_.AssertAcquired();
+ lock_.Release();
+ }
+
+ private:
+ LockType& lock_;
+ DISALLOW_COPY_AND_ASSIGN(BasicAutoLock);
+};
+
+// This is an implementation used for AutoUnlock templated on the lock type.
+template <class LockType>
+class BasicAutoUnlock {
+ public:
+ explicit BasicAutoUnlock(LockType& lock) : lock_(lock) {
+ // We require our caller to have the lock.
+ lock_.AssertAcquired();
+ lock_.Release();
+ }
+
+ ~BasicAutoUnlock() { lock_.Acquire(); }
+
+ private:
+ LockType& lock_;
+ DISALLOW_COPY_AND_ASSIGN(BasicAutoUnlock);
+};
+
+// This is an implementation used for AutoLockMaybe templated on the lock type.
+template <class LockType>
+class SCOPED_LOCKABLE BasicAutoLockMaybe {
+ public:
+ explicit BasicAutoLockMaybe(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
+ : lock_(lock) {
+ if (lock_)
+ lock_->Acquire();
+ }
+
+ ~BasicAutoLockMaybe() UNLOCK_FUNCTION() {
+ if (lock_) {
+ lock_->AssertAcquired();
+ lock_->Release();
+ }
+ }
+
+ private:
+ LockType* const lock_;
+ DISALLOW_COPY_AND_ASSIGN(BasicAutoLockMaybe);
+};
+
+// This is an implementation used for ReleasableAutoLock templated on the lock
+// type.
+template <class LockType>
+class SCOPED_LOCKABLE BasicReleasableAutoLock {
+ public:
+ explicit BasicReleasableAutoLock(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
+ : lock_(lock) {
+ DCHECK(lock_);
+ lock_->Acquire();
+ }
+
+ ~BasicReleasableAutoLock() UNLOCK_FUNCTION() {
+ if (lock_) {
+ lock_->AssertAcquired();
+ lock_->Release();
+ }
+ }
+
+ void Release() UNLOCK_FUNCTION() {
+ DCHECK(lock_);
+ lock_->AssertAcquired();
+ lock_->Release();
+ lock_ = nullptr;
+ }
+
+ private:
+ LockType* lock_;
+ DISALLOW_COPY_AND_ASSIGN(BasicReleasableAutoLock);
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_
diff --git a/security/sandbox/chromium/base/synchronization/lock_impl_posix.cc b/security/sandbox/chromium/base/synchronization/lock_impl_posix.cc
new file mode 100644
index 0000000000..7571f68a9a
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/lock_impl_posix.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/lock_impl.h"
+
+#include <string>
+
+#include "base/debug/activity_tracker.h"
+#include "base/logging.h"
+#include "base/posix/safe_strerror.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/synchronization_buildflags.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+#if DCHECK_IS_ON()
+const char* AdditionalHintForSystemErrorCode(int error_code) {
+ switch (error_code) {
+ case EINVAL:
+ return "Hint: This is often related to a use-after-free.";
+ default:
+ return "";
+ }
+}
+#endif // DCHECK_IS_ON()
+
+std::string SystemErrorCodeToString(int error_code) {
+#if DCHECK_IS_ON()
+ return base::safe_strerror(error_code) + ". " +
+ AdditionalHintForSystemErrorCode(error_code);
+#else // DCHECK_IS_ON()
+ return std::string();
+#endif // DCHECK_IS_ON()
+}
+
+} // namespace
+
+// Determines which platforms can consider using priority inheritance locks. Use
+// this define for platform code that may not compile if priority inheritance
+// locks aren't available. For this platform code,
+// PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
+// Lock::PriorityInheritanceAvailable still must be checked as the code may
+// compile but the underlying platform still may not correctly support priority
+// inheritance locks.
+#if defined(OS_NACL) || defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
+#else
+#define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
+#endif
+
+LockImpl::LockImpl() {
+ pthread_mutexattr_t mta;
+ int rv = pthread_mutexattr_init(&mta);
+ DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
+#if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
+ if (PriorityInheritanceAvailable()) {
+ rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
+ DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
+ }
+#endif
+#ifndef NDEBUG
+ // In debug, setup attributes for lock error checking.
+ rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
+ DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
+#endif
+ rv = pthread_mutex_init(&native_handle_, &mta);
+ DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
+ rv = pthread_mutexattr_destroy(&mta);
+ DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
+}
+
+LockImpl::~LockImpl() {
+ int rv = pthread_mutex_destroy(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
+}
+
+bool LockImpl::Try() {
+ int rv = pthread_mutex_trylock(&native_handle_);
+ DCHECK(rv == 0 || rv == EBUSY) << ". " << SystemErrorCodeToString(rv);
+ return rv == 0;
+}
+
+void LockImpl::Lock() {
+ // The ScopedLockAcquireActivity below is relatively expensive and so its
+ // actions can become significant due to the very large number of locks
+ // that tend to be used throughout the build. To avoid this cost in the
+ // vast majority of the calls, simply "try" the lock first and only do the
+ // (tracked) blocking call if that fails. Since "try" itself is a system
+ // call, and thus also somewhat expensive, don't bother with it unless
+ // tracking is actually enabled.
+ if (base::debug::GlobalActivityTracker::IsEnabled())
+ if (Try())
+ return;
+
+ base::debug::ScopedLockAcquireActivity lock_activity(this);
+ int rv = pthread_mutex_lock(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << SystemErrorCodeToString(rv);
+}
+
+// static
+bool LockImpl::PriorityInheritanceAvailable() {
+#if BUILDFLAG(ENABLE_MUTEX_PRIORITY_INHERITANCE)
+ return true;
+#elif PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX)
+ return true;
+#else
+ // Security concerns prevent the use of priority inheritance mutexes on Linux.
+ // * CVE-2010-0622 - Linux < 2.6.33-rc7, wake_futex_pi possible DoS.
+ // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
+ // * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
+ // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
+ // * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
+ // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
+ //
+ // If the above were all addressed, we still need a runtime check to deal with
+ // the bug below.
+ // * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
+ // Fixed in glibc 2.17.
+ // Priority inheritance mutexes may deadlock with condition variables
+ // during reacquisition of the mutex after the condition variable is
+ // signalled.
+ return false;
+#endif
+}
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/synchronization/lock_impl_win.cc b/security/sandbox/chromium/base/synchronization/lock_impl_win.cc
new file mode 100644
index 0000000000..e0c4e9d7fc
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/lock_impl_win.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/synchronization/lock_impl.h"
+
+#include "base/debug/activity_tracker.h"
+
+#include <windows.h>
+
+namespace base {
+namespace internal {
+
+LockImpl::LockImpl() : native_handle_(SRWLOCK_INIT) {}
+
+LockImpl::~LockImpl() = default;
+
+bool LockImpl::Try() {
+ return !!::TryAcquireSRWLockExclusive(
+ reinterpret_cast<PSRWLOCK>(&native_handle_));
+}
+
+void LockImpl::Lock() {
+ // The ScopedLockAcquireActivity below is relatively expensive and so its
+ // actions can become significant due to the very large number of locks
+ // that tend to be used throughout the build. To avoid this cost in the
+ // vast majority of the calls, simply "try" the lock first and only do the
+ // (tracked) blocking call if that fails. Since "try" itself is a system
+ // call, and thus also somewhat expensive, don't bother with it unless
+ // tracking is actually enabled.
+ if (base::debug::GlobalActivityTracker::IsEnabled())
+ if (Try())
+ return;
+
+ base::debug::ScopedLockAcquireActivity lock_activity(this);
+ ::AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&native_handle_));
+}
+
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/synchronization/waitable_event.h b/security/sandbox/chromium/base/synchronization/waitable_event.h
new file mode 100644
index 0000000000..8f78084e0d
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/waitable_event.h
@@ -0,0 +1,291 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#elif defined(OS_MACOSX)
+#include <mach/mach.h>
+
+#include <list>
+#include <memory>
+
+#include "base/callback_forward.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <list>
+#include <utility>
+
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#endif
+
+namespace base {
+
+class TimeDelta;
+
+// A WaitableEvent can be a useful thread synchronization tool when you want to
+// allow one thread to wait for another thread to finish some work. For
+// non-Windows systems, this can only be used from within a single address
+// space.
+//
+// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
+// protect a simple boolean value. However, if you find yourself using a
+// WaitableEvent in conjunction with a Lock to wait for a more complex state
+// change (e.g., for an item to be added to a queue), then you should probably
+// be using a ConditionVariable instead of a WaitableEvent.
+//
+// NOTE: On Windows, this class provides a subset of the functionality afforded
+// by a Windows event object. This is intentional. If you are writing Windows
+// specific code and you need other features of a Windows event, then you might
+// be better off just using an Windows event directly.
+class BASE_EXPORT WaitableEvent {
+ public:
+ // Indicates whether a WaitableEvent should automatically reset the event
+ // state after a single waiting thread has been released or remain signaled
+ // until Reset() is manually invoked.
+ enum class ResetPolicy { MANUAL, AUTOMATIC };
+
+ // Indicates whether a new WaitableEvent should start in a signaled state or
+ // not.
+ enum class InitialState { SIGNALED, NOT_SIGNALED };
+
+ // Constructs a WaitableEvent with policy and initial state as detailed in
+ // the above enums.
+ WaitableEvent(ResetPolicy reset_policy = ResetPolicy::MANUAL,
+ InitialState initial_state = InitialState::NOT_SIGNALED);
+
+#if defined(OS_WIN)
+ // Create a WaitableEvent from an Event HANDLE which has already been
+ // created. This objects takes ownership of the HANDLE and will close it when
+ // deleted.
+ explicit WaitableEvent(win::ScopedHandle event_handle);
+#endif
+
+ ~WaitableEvent();
+
+ // Put the event in the un-signaled state.
+ void Reset();
+
+ // Put the event in the signaled state. Causing any thread blocked on Wait
+ // to be woken up.
+ void Signal();
+
+ // Returns true if the event is in the signaled state, else false. If this
+ // is not a manual reset event, then this test will cause a reset.
+ bool IsSignaled();
+
+ // Wait indefinitely for the event to be signaled. Wait's return "happens
+ // after" |Signal| has completed. This means that it's safe for a
+ // WaitableEvent to synchronise its own destruction, like this:
+ //
+ // WaitableEvent *e = new WaitableEvent;
+ // SendToOtherThread(e);
+ // e->Wait();
+ // delete e;
+ void Wait();
+
+ // Wait up until wait_delta has passed for the event to be signaled
+ // (real-time; ignores time overrides). Returns true if the event was
+ // signaled. Handles spurious wakeups and guarantees that |wait_delta| will
+ // have elapsed if this returns false.
+ //
+ // TimedWait can synchronise its own destruction like |Wait|.
+ bool TimedWait(const TimeDelta& wait_delta);
+
+#if defined(OS_WIN)
+ HANDLE handle() const { return handle_.Get(); }
+#endif
+
+ // Declares that this WaitableEvent will only ever be used by a thread that is
+ // idle at the bottom of its stack and waiting for work (in particular, it is
+ // not synchronously waiting on this event before resuming ongoing work). This
+ // is useful to avoid telling base-internals that this thread is "blocked"
+ // when it's merely idle and ready to do work. As such, this is only expected
+ // to be used by thread and thread pool impls.
+ void declare_only_used_while_idle() { waiting_is_blocking_ = false; }
+
+ // Wait, synchronously, on multiple events.
+ // waitables: an array of WaitableEvent pointers
+ // count: the number of elements in @waitables
+ //
+ // returns: the index of a WaitableEvent which has been signaled.
+ //
+ // You MUST NOT delete any of the WaitableEvent objects while this wait is
+ // happening, however WaitMany's return "happens after" the |Signal| call
+ // that caused it has completed, like |Wait|.
+ //
+ // If more than one WaitableEvent is signaled to unblock WaitMany, the lowest
+ // index among them is returned.
+ static size_t WaitMany(WaitableEvent** waitables, size_t count);
+
+ // For asynchronous waiting, see WaitableEventWatcher
+
+ // This is a private helper class. It's here because it's used by friends of
+ // this class (such as WaitableEventWatcher) to be able to enqueue elements
+ // of the wait-list
+ class Waiter {
+ public:
+ // Signal the waiter to wake up.
+ //
+ // Consider the case of a Waiter which is in multiple WaitableEvent's
+ // wait-lists. Each WaitableEvent is automatic-reset and two of them are
+ // signaled at the same time. Now, each will wake only the first waiter in
+ // the wake-list before resetting. However, if those two waiters happen to
+ // be the same object (as can happen if another thread didn't have a chance
+ // to dequeue the waiter from the other wait-list in time), two auto-resets
+ // will have happened, but only one waiter has been signaled!
+ //
+ // Because of this, a Waiter may "reject" a wake by returning false. In
+ // this case, the auto-reset WaitableEvent shouldn't act as if anything has
+ // been notified.
+ virtual bool Fire(WaitableEvent* signaling_event) = 0;
+
+ // Waiters may implement this in order to provide an extra condition for
+ // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
+ // pointers match then this function is called as a final check. See the
+ // comments in ~Handle for why.
+ virtual bool Compare(void* tag) = 0;
+
+ protected:
+ virtual ~Waiter() = default;
+ };
+
+ private:
+ friend class WaitableEventWatcher;
+
+#if defined(OS_WIN)
+ win::ScopedHandle handle_;
+#elif defined(OS_MACOSX)
+ // Prior to macOS 10.12, a TYPE_MACH_RECV dispatch source may not be invoked
+ // immediately. If a WaitableEventWatcher is used on a manual-reset event,
+ // and another thread that is Wait()ing on the event calls Reset()
+ // immediately after waking up, the watcher may not receive the callback.
+ // On macOS 10.12 and higher, dispatch delivery is reliable. But for OSes
+ // prior, a lock-protected list of callbacks is used for manual-reset event
+ // watchers. Automatic-reset events are not prone to this issue, since the
+ // first thread to wake will claim the event.
+ static bool UseSlowWatchList(ResetPolicy policy);
+
+ // Peeks the message queue named by |port| and returns true if a message
+ // is present and false if not. If |dequeue| is true, the messsage will be
+ // drained from the queue. If |dequeue| is false, the queue will only be
+ // peeked. |port| must be a receive right.
+ static bool PeekPort(mach_port_t port, bool dequeue);
+
+ // The Mach receive right is waited on by both WaitableEvent and
+ // WaitableEventWatcher. It is valid to signal and then delete an event, and
+ // a watcher should still be notified. If the right were to be destroyed
+ // immediately, the watcher would not receive the signal. Because Mach
+ // receive rights cannot have a user refcount greater than one, the right
+ // must be reference-counted manually.
+ class ReceiveRight : public RefCountedThreadSafe<ReceiveRight> {
+ public:
+ ReceiveRight(mach_port_t name, bool create_slow_watch_list);
+
+ mach_port_t Name() const { return right_.get(); }
+
+ // This structure is used iff UseSlowWatchList() is true. See the comment
+ // in Signal() for details.
+ struct WatchList {
+ WatchList();
+ ~WatchList();
+
+ // The lock protects a list of closures to be run when the event is
+ // Signal()ed. The closures are invoked on the signaling thread, so they
+ // must be safe to be called from any thread.
+ Lock lock;
+ std::list<OnceClosure> list;
+ };
+
+ WatchList* SlowWatchList() const { return slow_watch_list_.get(); }
+
+ private:
+ friend class RefCountedThreadSafe<ReceiveRight>;
+ ~ReceiveRight();
+
+ mac::ScopedMachReceiveRight right_;
+
+ // This is allocated iff UseSlowWatchList() is true. It is created on the
+ // heap to avoid performing initialization when not using the slow path.
+ std::unique_ptr<WatchList> slow_watch_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReceiveRight);
+ };
+
+ const ResetPolicy policy_;
+
+ // The receive right for the event.
+ scoped_refptr<ReceiveRight> receive_right_;
+
+ // The send right used to signal the event. This can be disposed of with
+ // the event, unlike the receive right, since a deleted event cannot be
+ // signaled.
+ mac::ScopedMachSendRight send_right_;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // On Windows, you must not close a HANDLE which is currently being waited on.
+ // The MSDN documentation says that the resulting behaviour is 'undefined'.
+ // To solve that issue each WaitableEventWatcher duplicates the given event
+ // handle.
+
+ // However, if we were to include the following members
+ // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
+ // event which gets deleted. This mismatch has bitten us several times now,
+ // so we have a kernel of the WaitableEvent, which is reference counted.
+ // WaitableEventWatchers may then take a reference and thus match the Windows
+ // behaviour.
+ struct WaitableEventKernel :
+ public RefCountedThreadSafe<WaitableEventKernel> {
+ public:
+ WaitableEventKernel(ResetPolicy reset_policy, InitialState initial_state);
+
+ bool Dequeue(Waiter* waiter, void* tag);
+
+ base::Lock lock_;
+ const bool manual_reset_;
+ bool signaled_;
+ std::list<Waiter*> waiters_;
+
+ private:
+ friend class RefCountedThreadSafe<WaitableEventKernel>;
+ ~WaitableEventKernel();
+ };
+
+ typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
+
+ // When dealing with arrays of WaitableEvent*, we want to sort by the address
+ // of the WaitableEvent in order to have a globally consistent locking order.
+ // In that case we keep them, in sorted order, in an array of pairs where the
+ // second element is the index of the WaitableEvent in the original,
+ // unsorted, array.
+ static size_t EnqueueMany(WaiterAndIndex* waitables,
+ size_t count, Waiter* waiter);
+
+ bool SignalAll();
+ bool SignalOne();
+ void Enqueue(Waiter* waiter);
+
+ scoped_refptr<WaitableEventKernel> kernel_;
+#endif
+
+ // Whether a thread invoking Wait() on this WaitableEvent should be considered
+ // blocked as opposed to idle (and potentially replaced if part of a pool).
+ bool waiting_is_blocking_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
+};
+
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
diff --git a/security/sandbox/chromium/base/synchronization/waitable_event_posix.cc b/security/sandbox/chromium/base/synchronization/waitable_event_posix.cc
new file mode 100644
index 0000000000..effa899191
--- /dev/null
+++ b/security/sandbox/chromium/base/synchronization/waitable_event_posix.cc
@@ -0,0 +1,445 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/debug/activity_tracker.h"
+#include "base/logging.h"
+#include "base/optional.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/time/time_override.h"
+
+// -----------------------------------------------------------------------------
+// A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't
+// support cross-process events (where one process can signal an event which
+// others are waiting on). Because of this, we can avoid having one thread per
+// listener in several cases.
+//
+// The WaitableEvent maintains a list of waiters, protected by a lock. Each
+// waiter is either an async wait, in which case we have a Task and the
+// MessageLoop to run it on, or a blocking wait, in which case we have the
+// condition variable to signal.
+//
+// Waiting involves grabbing the lock and adding oneself to the wait list. Async
+// waits can be canceled, which means grabbing the lock and removing oneself
+// from the list.
+//
+// Waiting on multiple events is handled by adding a single, synchronous wait to
+// the wait-list of many events. An event passes a pointer to itself when
+// firing a waiter and so we can store that pointer to find out which event
+// triggered.
+// -----------------------------------------------------------------------------
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// This is just an abstract base class for waking the two types of waiters
+// -----------------------------------------------------------------------------
+WaitableEvent::WaitableEvent(ResetPolicy reset_policy,
+ InitialState initial_state)
+ : kernel_(new WaitableEventKernel(reset_policy, initial_state)) {}
+
+WaitableEvent::~WaitableEvent() = default;
+
+void WaitableEvent::Reset() {
+ base::AutoLock locked(kernel_->lock_);
+ kernel_->signaled_ = false;
+}
+
+void WaitableEvent::Signal() {
+ base::AutoLock locked(kernel_->lock_);
+
+ if (kernel_->signaled_)
+ return;
+
+ if (kernel_->manual_reset_) {
+ SignalAll();
+ kernel_->signaled_ = true;
+ } else {
+ // In the case of auto reset, if no waiters were woken, we remain
+ // signaled.
+ if (!SignalOne())
+ kernel_->signaled_ = true;
+ }
+}
+
+bool WaitableEvent::IsSignaled() {
+ base::AutoLock locked(kernel_->lock_);
+
+ const bool result = kernel_->signaled_;
+ if (result && !kernel_->manual_reset_)
+ kernel_->signaled_ = false;
+ return result;
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waits
+
+// -----------------------------------------------------------------------------
+// This is a synchronous waiter. The thread is waiting on the given condition
+// variable and the fired flag in this object.
+// -----------------------------------------------------------------------------
+class SyncWaiter : public WaitableEvent::Waiter {
+ public:
+ SyncWaiter()
+ : fired_(false), signaling_event_(nullptr), lock_(), cv_(&lock_) {}
+
+ bool Fire(WaitableEvent* signaling_event) override {
+ base::AutoLock locked(lock_);
+
+ if (fired_)
+ return false;
+
+ fired_ = true;
+ signaling_event_ = signaling_event;
+
+ cv_.Broadcast();
+
+ // Unlike AsyncWaiter objects, SyncWaiter objects are stack-allocated on
+ // the blocking thread's stack. There is no |delete this;| in Fire. The
+ // SyncWaiter object is destroyed when it goes out of scope.
+
+ return true;
+ }
+
+ WaitableEvent* signaling_event() const {
+ return signaling_event_;
+ }
+
+ // ---------------------------------------------------------------------------
+ // These waiters are always stack allocated and don't delete themselves. Thus
+ // there's no problem and the ABA tag is the same as the object pointer.
+ // ---------------------------------------------------------------------------
+ bool Compare(void* tag) override { return this == tag; }
+
+ // ---------------------------------------------------------------------------
+ // Called with lock held.
+ // ---------------------------------------------------------------------------
+ bool fired() const {
+ return fired_;
+ }
+
+ // ---------------------------------------------------------------------------
+ // During a TimedWait, we need a way to make sure that an auto-reset
+ // WaitableEvent doesn't think that this event has been signaled between
+ // unlocking it and removing it from the wait-list. Called with lock held.
+ // ---------------------------------------------------------------------------
+ void Disable() {
+ fired_ = true;
+ }
+
+ base::Lock* lock() {
+ return &lock_;
+ }
+
+ base::ConditionVariable* cv() {
+ return &cv_;
+ }
+
+ private:
+ bool fired_;
+ WaitableEvent* signaling_event_; // The WaitableEvent which woke us
+ base::Lock lock_;
+ base::ConditionVariable cv_;
+};
+
+void WaitableEvent::Wait() {
+ bool result = TimedWait(TimeDelta::Max());
+ DCHECK(result) << "TimedWait() should never fail with infinite timeout";
+}
+
+bool WaitableEvent::TimedWait(const TimeDelta& wait_delta) {
+ if (wait_delta <= TimeDelta())
+ return IsSignaled();
+
+ // Record the event that this thread is blocking upon (for hang diagnosis) and
+ // consider it blocked for scheduling purposes. Ignore this for non-blocking
+ // WaitableEvents.
+ Optional<debug::ScopedEventWaitActivity> event_activity;
+ Optional<internal::ScopedBlockingCallWithBaseSyncPrimitives>
+ scoped_blocking_call;
+ if (waiting_is_blocking_) {
+ event_activity.emplace(this);
+ scoped_blocking_call.emplace(FROM_HERE, BlockingType::MAY_BLOCK);
+ }
+
+ kernel_->lock_.Acquire();
+ if (kernel_->signaled_) {
+ if (!kernel_->manual_reset_) {
+ // In this case we were signaled when we had no waiters. Now that
+ // someone has waited upon us, we can automatically reset.
+ kernel_->signaled_ = false;
+ }
+
+ kernel_->lock_.Release();
+ return true;
+ }
+
+ SyncWaiter sw;
+ if (!waiting_is_blocking_)
+ sw.cv()->declare_only_used_while_idle();
+ sw.lock()->Acquire();
+
+ Enqueue(&sw);
+ kernel_->lock_.Release();
+ // We are violating locking order here by holding the SyncWaiter lock but not
+ // the WaitableEvent lock. However, this is safe because we don't lock |lock_|
+ // again before unlocking it.
+
+ // TimeTicks takes care of overflow but we special case is_max() nonetheless
+ // to avoid invoking TimeTicksNowIgnoringOverride() unnecessarily (same for
+ // the increment step of the for loop if the condition variable returns
+ // early). Ref: https://crbug.com/910524#c7
+ const TimeTicks end_time =
+ wait_delta.is_max() ? TimeTicks::Max()
+ : subtle::TimeTicksNowIgnoringOverride() + wait_delta;
+ for (TimeDelta remaining = wait_delta; remaining > TimeDelta() && !sw.fired();
+ remaining = end_time.is_max()
+ ? TimeDelta::Max()
+ : end_time - subtle::TimeTicksNowIgnoringOverride()) {
+ if (end_time.is_max())
+ sw.cv()->Wait();
+ else
+ sw.cv()->TimedWait(remaining);
+ }
+
+ // Get the SyncWaiter signaled state before releasing the lock.
+ const bool return_value = sw.fired();
+
+ // We can't acquire |lock_| before releasing the SyncWaiter lock (because of
+ // locking order), however, in between the two a signal could be fired and
+ // |sw| would accept it, however we will still return false, so the signal
+ // would be lost on an auto-reset WaitableEvent. Thus we call Disable which
+ // makes sw::Fire return false.
+ sw.Disable();
+ sw.lock()->Release();
+
+ // This is a bug that has been enshrined in the interface of WaitableEvent
+ // now: |Dequeue| is called even when |sw.fired()| is true, even though it'll
+ // always return false in that case. However, taking the lock ensures that
+ // |Signal| has completed before we return and means that a WaitableEvent can
+ // synchronise its own destruction.
+ kernel_->lock_.Acquire();
+ kernel_->Dequeue(&sw, &sw);
+ kernel_->lock_.Release();
+
+ return return_value;
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waiting on multiple objects.
+
+static bool // StrictWeakOrdering
+cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a,
+ const std::pair<WaitableEvent*, unsigned> &b) {
+ return a.first < b.first;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
+ size_t count) {
+ DCHECK(count) << "Cannot wait on no events";
+ internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
+ FROM_HERE, BlockingType::MAY_BLOCK);
+ // Record an event (the first) that this thread is blocking upon.
+ debug::ScopedEventWaitActivity event_activity(raw_waitables[0]);
+
+ // We need to acquire the locks in a globally consistent order. Thus we sort
+ // the array of waitables by address. We actually sort a pairs so that we can
+ // map back to the original index values later.
+ std::vector<std::pair<WaitableEvent*, size_t> > waitables;
+ waitables.reserve(count);
+ for (size_t i = 0; i < count; ++i)
+ waitables.push_back(std::make_pair(raw_waitables[i], i));
+
+ DCHECK_EQ(count, waitables.size());
+
+ sort(waitables.begin(), waitables.end(), cmp_fst_addr);
+
+ // The set of waitables must be distinct. Since we have just sorted by
+ // address, we can check this cheaply by comparing pairs of consecutive
+ // elements.
+ for (size_t i = 0; i < waitables.size() - 1; ++i) {
+ DCHECK(waitables[i].first != waitables[i+1].first);
+ }
+
+ SyncWaiter sw;
+
+ const size_t r = EnqueueMany(&waitables[0], count, &sw);
+ if (r < count) {
+ // One of the events is already signaled. The SyncWaiter has not been
+ // enqueued anywhere.
+ return waitables[r].second;
+ }
+
+ // At this point, we hold the locks on all the WaitableEvents and we have
+ // enqueued our waiter in them all.
+ sw.lock()->Acquire();
+ // Release the WaitableEvent locks in the reverse order
+ for (size_t i = 0; i < count; ++i) {
+ waitables[count - (1 + i)].first->kernel_->lock_.Release();
+ }
+
+ for (;;) {
+ if (sw.fired())
+ break;
+
+ sw.cv()->Wait();
+ }
+ sw.lock()->Release();
+
+ // The address of the WaitableEvent which fired is stored in the SyncWaiter.
+ WaitableEvent *const signaled_event = sw.signaling_event();
+ // This will store the index of the raw_waitables which fired.
+ size_t signaled_index = 0;
+
+ // Take the locks of each WaitableEvent in turn (except the signaled one) and
+ // remove our SyncWaiter from the wait-list
+ for (size_t i = 0; i < count; ++i) {
+ if (raw_waitables[i] != signaled_event) {
+ raw_waitables[i]->kernel_->lock_.Acquire();
+ // There's no possible ABA issue with the address of the SyncWaiter here
+ // because it lives on the stack. Thus the tag value is just the pointer
+ // value again.
+ raw_waitables[i]->kernel_->Dequeue(&sw, &sw);
+ raw_waitables[i]->kernel_->lock_.Release();
+ } else {
+ // By taking this lock here we ensure that |Signal| has completed by the
+ // time we return, because |Signal| holds this lock. This matches the
+ // behaviour of |Wait| and |TimedWait|.
+ raw_waitables[i]->kernel_->lock_.Acquire();
+ raw_waitables[i]->kernel_->lock_.Release();
+ signaled_index = i;
+ }
+ }
+
+ return signaled_index;
+}
+
+// -----------------------------------------------------------------------------
+// If return value == count:
+// The locks of the WaitableEvents have been taken in order and the Waiter has
+// been enqueued in the wait-list of each. None of the WaitableEvents are
+// currently signaled
+// else:
+// None of the WaitableEvent locks are held. The Waiter has not been enqueued
+// in any of them and the return value is the index of the WaitableEvent which
+// was signaled with the lowest input index from the original WaitMany call.
+// -----------------------------------------------------------------------------
+// static
+size_t WaitableEvent::EnqueueMany(std::pair<WaitableEvent*, size_t>* waitables,
+ size_t count,
+ Waiter* waiter) {
+ size_t winner = count;
+ size_t winner_index = count;
+ for (size_t i = 0; i < count; ++i) {
+ auto& kernel = waitables[i].first->kernel_;
+ kernel->lock_.Acquire();
+ if (kernel->signaled_ && waitables[i].second < winner) {
+ winner = waitables[i].second;
+ winner_index = i;
+ }
+ }
+
+ // No events signaled. All locks acquired. Enqueue the Waiter on all of them
+ // and return.
+ if (winner == count) {
+ for (size_t i = 0; i < count; ++i)
+ waitables[i].first->Enqueue(waiter);
+ return count;
+ }
+
+ // Unlock in reverse order and possibly clear the chosen winner's signal
+ // before returning its index.
+ for (auto* w = waitables + count - 1; w >= waitables; --w) {
+ auto& kernel = w->first->kernel_;
+ if (w->second == winner) {
+ if (!kernel->manual_reset_)
+ kernel->signaled_ = false;
+ }
+ kernel->lock_.Release();
+ }
+
+ return winner_index;
+}
+
+// -----------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// Private functions...
+
+WaitableEvent::WaitableEventKernel::WaitableEventKernel(
+ ResetPolicy reset_policy,
+ InitialState initial_state)
+ : manual_reset_(reset_policy == ResetPolicy::MANUAL),
+ signaled_(initial_state == InitialState::SIGNALED) {}
+
+WaitableEvent::WaitableEventKernel::~WaitableEventKernel() = default;
+
+// -----------------------------------------------------------------------------
+// Wake all waiting waiters. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::SignalAll() {
+ bool signaled_at_least_one = false;
+
+ for (auto* i : kernel_->waiters_) {
+ if (i->Fire(this))
+ signaled_at_least_one = true;
+ }
+
+ kernel_->waiters_.clear();
+ return signaled_at_least_one;
+}
+
+// ---------------------------------------------------------------------------
+// Try to wake a single waiter. Return true if one was woken. Called with lock
+// held.
+// ---------------------------------------------------------------------------
+bool WaitableEvent::SignalOne() {
+ for (;;) {
+ if (kernel_->waiters_.empty())
+ return false;
+
+ const bool r = (*kernel_->waiters_.begin())->Fire(this);
+ kernel_->waiters_.pop_front();
+ if (r)
+ return true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Add a waiter to the list of those waiting. Called with lock held.
+// -----------------------------------------------------------------------------
+void WaitableEvent::Enqueue(Waiter* waiter) {
+ kernel_->waiters_.push_back(waiter);
+}
+
+// -----------------------------------------------------------------------------
+// Remove a waiter from the list of those waiting. Return true if the waiter was
+// actually removed. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
+ for (auto i = waiters_.begin(); i != waiters_.end(); ++i) {
+ if (*i == waiter && (*i)->Compare(tag)) {
+ waiters_.erase(i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/task_runner.h b/security/sandbox/chromium/base/task_runner.h
new file mode 100644
index 0000000000..8abf5ef4ba
--- /dev/null
+++ b/security/sandbox/chromium/base/task_runner.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TASK_RUNNER_H_
+#define BASE_TASK_RUNNER_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+
+namespace base {
+
+struct TaskRunnerTraits;
+
+// A TaskRunner is an object that runs posted tasks (in the form of
+// OnceClosure objects). The TaskRunner interface provides a way of
+// decoupling task posting from the mechanics of how each task will be
+// run. TaskRunner provides very weak guarantees as to how posted
+// tasks are run (or if they're run at all). In particular, it only
+// guarantees:
+//
+// - Posting a task will not run it synchronously. That is, no
+// Post*Task method will call task.Run() directly.
+//
+// - Increasing the delay can only delay when the task gets run.
+// That is, increasing the delay may not affect when the task gets
+// run, or it could make it run later than it normally would, but
+// it won't make it run earlier than it normally would.
+//
+// TaskRunner does not guarantee the order in which posted tasks are
+// run, whether tasks overlap, or whether they're run on a particular
+// thread. Also it does not guarantee a memory model for shared data
+// between tasks. (In other words, you should use your own
+// synchronization/locking primitives if you need to share data
+// between tasks.)
+//
+// Implementations of TaskRunner should be thread-safe in that all
+// methods must be safe to call on any thread. Ownership semantics
+// for TaskRunners are in general not clear, which is why the
+// interface itself is RefCountedThreadSafe.
+//
+// Some theoretical implementations of TaskRunner:
+//
+// - A TaskRunner that uses a thread pool to run posted tasks.
+//
+// - A TaskRunner that, for each task, spawns a non-joinable thread
+// to run that task and immediately quit.
+//
+// - A TaskRunner that stores the list of posted tasks and has a
+// method Run() that runs each runnable task in random order.
+class BASE_EXPORT TaskRunner
+ : public RefCountedThreadSafe<TaskRunner, TaskRunnerTraits> {
+ public:
+ // Posts the given task to be run. Returns true if the task may be
+ // run at some point in the future, and false if the task definitely
+ // will not be run.
+ //
+ // Equivalent to PostDelayedTask(from_here, task, 0).
+ bool PostTask(const Location& from_here, OnceClosure task);
+
+ // Like PostTask, but tries to run the posted task only after |delay_ms|
+ // has passed. Implementations should use a tick clock, rather than wall-
+ // clock time, to implement |delay|.
+ virtual bool PostDelayedTask(const Location& from_here,
+ OnceClosure task,
+ base::TimeDelta delay) = 0;
+
+ // Posts |task| on the current TaskRunner. On completion, |reply|
+ // is posted to the thread that called PostTaskAndReply(). Both
+ // |task| and |reply| are guaranteed to be deleted on the thread
+ // from which PostTaskAndReply() is invoked. This allows objects
+ // that must be deleted on the originating thread to be bound into
+ // the |task| and |reply| OnceClosures. In particular, it can be useful
+ // to use WeakPtr<> in the |reply| OnceClosure so that the reply
+ // operation can be canceled. See the following pseudo-code:
+ //
+ // class DataBuffer : public RefCountedThreadSafe<DataBuffer> {
+ // public:
+ // // Called to add data into a buffer.
+ // void AddData(void* buf, size_t length);
+ // ...
+ // };
+ //
+ //
+ // class DataLoader : public SupportsWeakPtr<DataLoader> {
+ // public:
+ // void GetData() {
+ // scoped_refptr<DataBuffer> buffer = new DataBuffer();
+ // target_thread_.task_runner()->PostTaskAndReply(
+ // FROM_HERE,
+ // base::BindOnce(&DataBuffer::AddData, buffer),
+ // base::BindOnce(&DataLoader::OnDataReceived, AsWeakPtr(), buffer));
+ // }
+ //
+ // private:
+ // void OnDataReceived(scoped_refptr<DataBuffer> buffer) {
+ // // Do something with buffer.
+ // }
+ // };
+ //
+ //
+ // Things to notice:
+ // * Results of |task| are shared with |reply| by binding a shared argument
+ // (a DataBuffer instance).
+ // * The DataLoader object has no special thread safety.
+ // * The DataLoader object can be deleted while |task| is still running,
+ // and the reply will cancel itself safely because it is bound to a
+ // WeakPtr<>.
+ bool PostTaskAndReply(const Location& from_here,
+ OnceClosure task,
+ OnceClosure reply);
+
+ protected:
+ friend struct TaskRunnerTraits;
+
+ TaskRunner();
+ virtual ~TaskRunner();
+
+ // Called when this object should be destroyed. By default simply
+ // deletes |this|, but can be overridden to do something else, like
+ // delete on a certain thread.
+ virtual void OnDestruct() const;
+};
+
+struct BASE_EXPORT TaskRunnerTraits {
+ static void Destruct(const TaskRunner* task_runner);
+};
+
+} // namespace base
+
+#endif // BASE_TASK_RUNNER_H_
diff --git a/security/sandbox/chromium/base/template_util.h b/security/sandbox/chromium/base/template_util.h
new file mode 100644
index 0000000000..51bd085279
--- /dev/null
+++ b/security/sandbox/chromium/base/template_util.h
@@ -0,0 +1,188 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEMPLATE_UTIL_H_
+#define BASE_TEMPLATE_UTIL_H_
+
+#include <stddef.h>
+#include <iosfwd>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "build/build_config.h"
+
+// Some versions of libstdc++ have partial support for type_traits, but misses
+// a smaller subset while removing some of the older non-standard stuff. Assume
+// that all versions below 5.0 fall in this category, along with one 5.0
+// experimental release. Test for this by consulting compiler major version,
+// the only reliable option available, so theoretically this could fail should
+// you attempt to mix an earlier version of libstdc++ with >= GCC5. But
+// that's unlikely to work out, especially as GCC5 changed ABI.
+#define CR_GLIBCXX_5_0_0 20150123
+#if (defined(__GNUC__) && __GNUC__ < 5) || \
+ (defined(__GLIBCXX__) && __GLIBCXX__ == CR_GLIBCXX_5_0_0)
+#define CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
+#endif
+
+// This hacks around using gcc with libc++ which has some incompatibilies.
+// - is_trivially_* doesn't work: https://llvm.org/bugs/show_bug.cgi?id=27538
+// TODO(danakj): Remove this when android builders are all using a newer version
+// of gcc, or the android ndk is updated to a newer libc++ that works with older
+// gcc versions.
+#if !defined(__clang__) && defined(_LIBCPP_VERSION)
+#define CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
+#endif
+
+namespace base {
+
+template <class T> struct is_non_const_reference : std::false_type {};
+template <class T> struct is_non_const_reference<T&> : std::true_type {};
+template <class T> struct is_non_const_reference<const T&> : std::false_type {};
+
+namespace internal {
+
+// Implementation detail of base::void_t below.
+template <typename...>
+struct make_void {
+ using type = void;
+};
+
+} // namespace internal
+
+// base::void_t is an implementation of std::void_t from C++17.
+//
+// We use |base::internal::make_void| as a helper struct to avoid a C++14
+// defect:
+// http://en.cppreference.com/w/cpp/types/void_t
+// http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
+template <typename... Ts>
+using void_t = typename ::base::internal::make_void<Ts...>::type;
+
+namespace internal {
+
+// Uses expression SFINAE to detect whether using operator<< would work.
+template <typename T, typename = void>
+struct SupportsOstreamOperator : std::false_type {};
+template <typename T>
+struct SupportsOstreamOperator<T,
+ decltype(void(std::declval<std::ostream&>()
+ << std::declval<T>()))>
+ : std::true_type {};
+
+template <typename T, typename = void>
+struct SupportsToString : std::false_type {};
+template <typename T>
+struct SupportsToString<T, decltype(void(std::declval<T>().ToString()))>
+ : std::true_type {};
+
+// Used to detech whether the given type is an iterator. This is normally used
+// with std::enable_if to provide disambiguation for functions that take
+// templatzed iterators as input.
+template <typename T, typename = void>
+struct is_iterator : std::false_type {};
+
+template <typename T>
+struct is_iterator<T,
+ void_t<typename std::iterator_traits<T>::iterator_category>>
+ : std::true_type {};
+
+} // namespace internal
+
+// is_trivially_copyable is especially hard to get right.
+// - Older versions of libstdc++ will fail to have it like they do for other
+// type traits. This has become a subset of the second point, but used to be
+// handled independently.
+// - An experimental release of gcc includes most of type_traits but misses
+// is_trivially_copyable, so we still have to avoid using libstdc++ in this
+// case, which is covered by CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX.
+// - When compiling libc++ from before r239653, with a gcc compiler, the
+// std::is_trivially_copyable can fail. So we need to work around that by not
+// using the one in libc++ in this case. This is covered by the
+// CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX define, and is discussed in
+// https://llvm.org/bugs/show_bug.cgi?id=27538#c1 where they point out that
+// in libc++'s commit r239653 this is fixed by libc++ checking for gcc 5.1.
+// - In both of the above cases we are using the gcc compiler. When defining
+// this ourselves on compiler intrinsics, the __is_trivially_copyable()
+// intrinsic is not available on gcc before version 5.1 (see the discussion in
+// https://llvm.org/bugs/show_bug.cgi?id=27538#c1 again), so we must check for
+// that version.
+// - When __is_trivially_copyable() is not available because we are on gcc older
+// than 5.1, we need to fall back to something, so we use __has_trivial_copy()
+// instead based on what was done one-off in bit_cast() previously.
+
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace and it works with gcc as needed.
+#if defined(CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX) || \
+ defined(CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX)
+template <typename T>
+struct is_trivially_copyable {
+// TODO(danakj): Remove this when android builders are all using a newer version
+// of gcc, or the android ndk is updated to a newer libc++ that does this for
+// us.
+#if _GNUC_VER >= 501
+ static constexpr bool value = __is_trivially_copyable(T);
+#else
+ static constexpr bool value =
+ __has_trivial_copy(T) && __has_trivial_destructor(T);
+#endif
+};
+#else
+template <class T>
+using is_trivially_copyable = std::is_trivially_copyable<T>;
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 7
+// Workaround for g++7 and earlier family.
+// Due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654, without this
+// Optional<std::vector<T>> where T is non-copyable causes a compile error.
+// As we know it is not trivially copy constructible, explicitly declare so.
+template <typename T>
+struct is_trivially_copy_constructible
+ : std::is_trivially_copy_constructible<T> {};
+
+template <typename... T>
+struct is_trivially_copy_constructible<std::vector<T...>> : std::false_type {};
+#else
+// Otherwise use std::is_trivially_copy_constructible as is.
+template <typename T>
+using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
+#endif
+
+// base::in_place_t is an implementation of std::in_place_t from
+// C++17. A tag type used to request in-place construction in template vararg
+// constructors.
+
+// Specification:
+// https://en.cppreference.com/w/cpp/utility/in_place
+struct in_place_t {};
+constexpr in_place_t in_place = {};
+
+// base::in_place_type_t is an implementation of std::in_place_type_t from
+// C++17. A tag type used for in-place construction when the type to construct
+// needs to be specified, such as with base::unique_any, designed to be a
+// drop-in replacement.
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/in_place
+template <typename T>
+struct in_place_type_t {};
+
+template <typename T>
+struct is_in_place_type_t {
+ static constexpr bool value = false;
+};
+
+template <typename... Ts>
+struct is_in_place_type_t<in_place_type_t<Ts...>> {
+ static constexpr bool value = true;
+};
+
+} // namespace base
+
+#undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
+#undef CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
+
+#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/security/sandbox/chromium/base/third_party/cityhash/COPYING b/security/sandbox/chromium/base/third_party/cityhash/COPYING
new file mode 100644
index 0000000000..bf15194dd5
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/cityhash/COPYING
@@ -0,0 +1,19 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// 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.
diff --git a/security/sandbox/chromium/base/third_party/cityhash/city.cc b/security/sandbox/chromium/base/third_party/cityhash/city.cc
new file mode 100644
index 0000000000..b0d2294aab
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/cityhash/city.cc
@@ -0,0 +1,532 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// 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.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// This file provides CityHash64() and related functions.
+//
+// It's probably possible to create even faster hash functions by
+// writing a program that systematically explores some of the space of
+// possible hash functions, by using SIMD instructions, or by
+// compromising on hash quality.
+
+#include "city.h"
+
+#include <string.h> // for memcpy and memset
+#include <algorithm>
+
+using std::make_pair;
+using std::pair;
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+#define bswap_32(x) _byteswap_ulong(x)
+#define bswap_64(x) _byteswap_uint64(x)
+
+#elif defined(__APPLE__)
+
+// Mac OS X / Darwin features
+#include <libkern/OSByteOrder.h>
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#elif defined(__sun) || defined(sun)
+
+#include <sys/byteorder.h>
+#define bswap_32(x) BSWAP_32(x)
+#define bswap_64(x) BSWAP_64(x)
+
+#elif defined(__FreeBSD__)
+
+#include <sys/endian.h>
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+
+#elif defined(__OpenBSD__)
+
+#include <sys/types.h>
+#define bswap_32(x) swap32(x)
+#define bswap_64(x) swap64(x)
+
+#elif defined(__NetBSD__)
+
+#include <machine/bswap.h>
+#include <sys/types.h>
+#if defined(__BSWAP_RENAME) && !defined(__bswap_32)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+
+#else
+
+// XXX(cavalcanti): building 'native_client' fails with this header.
+//#include <byteswap.h>
+
+// Falling back to compiler builtins instead.
+#define bswap_32(x) __builtin_bswap32(x)
+#define bswap_64(x) __builtin_bswap64(x)
+
+#endif
+
+namespace base {
+namespace internal {
+namespace cityhash_v111 {
+
+#ifdef WORDS_BIGENDIAN
+#define uint32_in_expected_order(x) (bswap_32(x))
+#define uint64_in_expected_order(x) (bswap_64(x))
+#else
+#define uint32_in_expected_order(x) (x)
+#define uint64_in_expected_order(x) (x)
+#endif
+
+#if !defined(LIKELY)
+#if HAVE_BUILTIN_EXPECT
+#define LIKELY(x) (__builtin_expect(!!(x), 1))
+#else
+#define LIKELY(x) (x)
+#endif
+#endif
+
+static uint64 UNALIGNED_LOAD64(const char* p) {
+ uint64 result;
+ memcpy(&result, p, sizeof(result));
+ return result;
+}
+
+static uint32 UNALIGNED_LOAD32(const char* p) {
+ uint32 result;
+ memcpy(&result, p, sizeof(result));
+ return result;
+}
+
+static uint64 Fetch64(const char* p) {
+ return uint64_in_expected_order(UNALIGNED_LOAD64(p));
+}
+
+static uint32 Fetch32(const char* p) {
+ return uint32_in_expected_order(UNALIGNED_LOAD32(p));
+}
+
+// Some primes between 2^63 and 2^64 for various uses.
+static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
+static const uint64 k1 = 0xb492b66fbe98f273ULL;
+static const uint64 k2 = 0x9ae16a3b2f90404fULL;
+
+// Magic numbers for 32-bit hashing. Copied from Murmur3.
+static const uint32 c1 = 0xcc9e2d51;
+static const uint32 c2 = 0x1b873593;
+
+// A 32-bit to 32-bit integer hash copied from Murmur3.
+static uint32 fmix(uint32 h) {
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+}
+
+static uint32 Rotate32(uint32 val, int shift) {
+ // Avoid shifting by 32: doing so yields an undefined result.
+ return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
+}
+
+#undef PERMUTE3
+#define PERMUTE3(a, b, c) \
+ do { \
+ std::swap(a, b); \
+ std::swap(a, c); \
+ } while (0)
+
+static uint32 Mur(uint32 a, uint32 h) {
+ // Helper from Murmur3 for combining two 32-bit values.
+ a *= c1;
+ a = Rotate32(a, 17);
+ a *= c2;
+ h ^= a;
+ h = Rotate32(h, 19);
+ return h * 5 + 0xe6546b64;
+}
+
+static uint32 Hash32Len13to24(const char* s, size_t len) {
+ uint32 a = Fetch32(s - 4 + (len >> 1));
+ uint32 b = Fetch32(s + 4);
+ uint32 c = Fetch32(s + len - 8);
+ uint32 d = Fetch32(s + (len >> 1));
+ uint32 e = Fetch32(s);
+ uint32 f = Fetch32(s + len - 4);
+ uint32 h = len;
+
+ return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));
+}
+
+static uint32 Hash32Len0to4(const char* s, size_t len) {
+ uint32 b = 0;
+ uint32 c = 9;
+ for (size_t i = 0; i < len; i++) {
+ signed char v = s[i];
+ b = b * c1 + v;
+ c ^= b;
+ }
+ return fmix(Mur(b, Mur(len, c)));
+}
+
+static uint32 Hash32Len5to12(const char* s, size_t len) {
+ uint32 a = len, b = len * 5, c = 9, d = b;
+ a += Fetch32(s);
+ b += Fetch32(s + len - 4);
+ c += Fetch32(s + ((len >> 1) & 4));
+ return fmix(Mur(c, Mur(b, Mur(a, d))));
+}
+
+uint32 CityHash32(const char* s, size_t len) {
+ if (len <= 24) {
+ return len <= 12
+ ? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len))
+ : Hash32Len13to24(s, len);
+ }
+
+ // len > 24
+ uint32 h = len, g = c1 * len, f = g;
+ uint32 a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;
+ uint32 a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;
+ uint32 a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;
+ uint32 a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;
+ uint32 a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;
+ h ^= a0;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ h ^= a2;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ g ^= a1;
+ g = Rotate32(g, 19);
+ g = g * 5 + 0xe6546b64;
+ g ^= a3;
+ g = Rotate32(g, 19);
+ g = g * 5 + 0xe6546b64;
+ f += a4;
+ f = Rotate32(f, 19);
+ f = f * 5 + 0xe6546b64;
+ size_t iters = (len - 1) / 20;
+ do {
+ a0 = Rotate32(Fetch32(s) * c1, 17) * c2;
+ a1 = Fetch32(s + 4);
+ a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2;
+ a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2;
+ a4 = Fetch32(s + 16);
+ h ^= a0;
+ h = Rotate32(h, 18);
+ h = h * 5 + 0xe6546b64;
+ f += a1;
+ f = Rotate32(f, 19);
+ f = f * c1;
+ g += a2;
+ g = Rotate32(g, 18);
+ g = g * 5 + 0xe6546b64;
+ h ^= a3 + a1;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ g ^= a4;
+ g = bswap_32(g) * 5;
+ h += a4 * 5;
+ h = bswap_32(h);
+ f += a0;
+ PERMUTE3(f, h, g);
+ s += 20;
+ } while (--iters != 0);
+ g = Rotate32(g, 11) * c1;
+ g = Rotate32(g, 17) * c1;
+ f = Rotate32(f, 11) * c1;
+ f = Rotate32(f, 17) * c1;
+ h = Rotate32(h + g, 19);
+ h = h * 5 + 0xe6546b64;
+ h = Rotate32(h, 17) * c1;
+ h = Rotate32(h + f, 19);
+ h = h * 5 + 0xe6546b64;
+ h = Rotate32(h, 17) * c1;
+ return h;
+}
+
+// Bitwise right rotate. Normally this will compile to a single
+// instruction, especially if the shift is a manifest constant.
+static uint64 Rotate(uint64 val, int shift) {
+ // Avoid shifting by 64: doing so yields an undefined result.
+ return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
+}
+
+static uint64 ShiftMix(uint64 val) {
+ return val ^ (val >> 47);
+}
+
+static uint64 HashLen16(uint64 u, uint64 v) {
+ return Hash128to64(uint128(u, v));
+}
+
+static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
+ // Murmur-inspired hashing.
+ uint64 a = (u ^ v) * mul;
+ a ^= (a >> 47);
+ uint64 b = (v ^ a) * mul;
+ b ^= (b >> 47);
+ b *= mul;
+ return b;
+}
+
+static uint64 HashLen0to16(const char* s, size_t len) {
+ if (len >= 8) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) + k2;
+ uint64 b = Fetch64(s + len - 8);
+ uint64 c = Rotate(b, 37) * mul + a;
+ uint64 d = (Rotate(a, 25) + b) * mul;
+ return HashLen16(c, d, mul);
+ }
+ if (len >= 4) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch32(s);
+ return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
+ }
+ if (len > 0) {
+ uint8 a = s[0];
+ uint8 b = s[len >> 1];
+ uint8 c = s[len - 1];
+ uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
+ uint32 z = len + (static_cast<uint32>(c) << 2);
+ return ShiftMix(y * k2 ^ z * k0) * k2;
+ }
+ return k2;
+}
+
+// This probably works well for 16-byte strings as well, but it may be overkill
+// in that case.
+static uint64 HashLen17to32(const char* s, size_t len) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) * k1;
+ uint64 b = Fetch64(s + 8);
+ uint64 c = Fetch64(s + len - 8) * mul;
+ uint64 d = Fetch64(s + len - 16) * k2;
+ return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d,
+ a + Rotate(b + k2, 18) + c, mul);
+}
+
+// Return a 16-byte hash for 48 bytes. Quick and dirty.
+// Callers do best to use "random-looking" values for a and b.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w,
+ uint64 x,
+ uint64 y,
+ uint64 z,
+ uint64 a,
+ uint64 b) {
+ a += w;
+ b = Rotate(b + a + z, 21);
+ uint64 c = a;
+ a += x;
+ a += y;
+ b += Rotate(a, 44);
+ return make_pair(a + z, b + c);
+}
+
+// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s,
+ uint64 a,
+ uint64 b) {
+ return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
+ Fetch64(s + 24), a, b);
+}
+
+// Return an 8-byte hash for 33 to 64 bytes.
+static uint64 HashLen33to64(const char* s, size_t len) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) * k2;
+ uint64 b = Fetch64(s + 8);
+ uint64 c = Fetch64(s + len - 24);
+ uint64 d = Fetch64(s + len - 32);
+ uint64 e = Fetch64(s + 16) * k2;
+ uint64 f = Fetch64(s + 24) * 9;
+ uint64 g = Fetch64(s + len - 8);
+ uint64 h = Fetch64(s + len - 16) * mul;
+ uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
+ uint64 v = ((a + g) ^ d) + f + 1;
+ uint64 w = bswap_64((u + v) * mul) + h;
+ uint64 x = Rotate(e + f, 42) + c;
+ uint64 y = (bswap_64((v + w) * mul) + g) * mul;
+ uint64 z = e + f + c;
+ a = bswap_64((x + z) * mul + y) + b;
+ b = ShiftMix((z + a) * mul + d + h) * mul;
+ return b + x;
+}
+
+uint64 CityHash64(const char* s, size_t len) {
+ if (len <= 32) {
+ if (len <= 16) {
+ return HashLen0to16(s, len);
+ } else {
+ return HashLen17to32(s, len);
+ }
+ } else if (len <= 64) {
+ return HashLen33to64(s, len);
+ }
+
+ // For strings over 64 bytes we hash the end first, and then as we
+ // loop we keep 56 bytes of state: v, w, x, y, and z.
+ uint64 x = Fetch64(s + len - 40);
+ uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
+ uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
+ pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
+ pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+ x = x * k1 + Fetch64(s);
+
+ // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
+ len = (len - 1) & ~static_cast<size_t>(63);
+ do {
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ len -= 64;
+ } while (len != 0);
+ return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
+ HashLen16(v.second, w.second) + x);
+}
+
+uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) {
+ return CityHash64WithSeeds(s, len, k2, seed);
+}
+
+uint64 CityHash64WithSeeds(const char* s,
+ size_t len,
+ uint64 seed0,
+ uint64 seed1) {
+ return HashLen16(CityHash64(s, len) - seed0, seed1);
+}
+
+// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
+// of any length representable in signed long. Based on City and Murmur.
+static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
+ uint64 a = Uint128Low64(seed);
+ uint64 b = Uint128High64(seed);
+ uint64 c = 0;
+ uint64 d = 0;
+ signed long l = len - 16;
+ if (l <= 0) { // len <= 16
+ a = ShiftMix(a * k1) * k1;
+ c = b * k1 + HashLen0to16(s, len);
+ d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
+ } else { // len > 16
+ c = HashLen16(Fetch64(s + len - 8) + k1, a);
+ d = HashLen16(b + len, c + Fetch64(s + len - 16));
+ a += d;
+ do {
+ a ^= ShiftMix(Fetch64(s) * k1) * k1;
+ a *= k1;
+ b ^= a;
+ c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
+ c *= k1;
+ d ^= c;
+ s += 16;
+ l -= 16;
+ } while (l > 0);
+ }
+ a = HashLen16(a, c);
+ b = HashLen16(d, b);
+ return uint128(a ^ b, HashLen16(b, a));
+}
+
+uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
+ if (len < 128) {
+ return CityMurmur(s, len, seed);
+ }
+
+ // We expect len >= 128 to be the common case. Keep 56 bytes of state:
+ // v, w, x, y, and z.
+ pair<uint64, uint64> v, w;
+ uint64 x = Uint128Low64(seed);
+ uint64 y = Uint128High64(seed);
+ uint64 z = len * k1;
+ v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
+ v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
+ w.first = Rotate(y + z, 35) * k1 + x;
+ w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
+
+ // This is the same inner loop as CityHash64(), manually unrolled.
+ do {
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ len -= 128;
+ } while (LIKELY(len >= 128));
+ x += Rotate(v.first + z, 49) * k0;
+ y = y * k0 + Rotate(w.second, 37);
+ z = z * k0 + Rotate(w.first, 27);
+ w.first *= 9;
+ v.first *= k0;
+ // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
+ for (size_t tail_done = 0; tail_done < len;) {
+ tail_done += 32;
+ y = Rotate(x + y, 42) * k0 + v.second;
+ w.first += Fetch64(s + len - tail_done + 16);
+ x = x * k0 + w.first;
+ z += w.second + Fetch64(s + len - tail_done);
+ w.second += v.first;
+ v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
+ v.first *= k0;
+ }
+ // At this point our 56 bytes of state should contain more than
+ // enough information for a strong 128-bit hash. We use two
+ // different 56-byte-to-8-byte hashes to get a 16-byte final result.
+ x = HashLen16(x, v.first);
+ y = HashLen16(y + z, w.first);
+ return uint128(HashLen16(x + v.second, w.second) + y,
+ HashLen16(x + w.second, y + v.second));
+}
+
+uint128 CityHash128(const char* s, size_t len) {
+ return len >= 16
+ ? CityHash128WithSeed(s + 16, len - 16,
+ uint128(Fetch64(s), Fetch64(s + 8) + k0))
+ : CityHash128WithSeed(s, len, uint128(k0, k1));
+}
+
+} // namespace cityhash_v111
+} // namespace internal
+} // namespace base
diff --git a/security/sandbox/chromium/base/third_party/cityhash/city.h b/security/sandbox/chromium/base/third_party/cityhash/city.h
new file mode 100644
index 0000000000..3e3dcaaaa9
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/cityhash/city.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// 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.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// http://code.google.com/p/cityhash/
+//
+// This file provides a few functions for hashing strings. All of them are
+// high-quality functions in the sense that they pass standard tests such
+// as Austin Appleby's SMHasher. They are also fast.
+//
+// For 64-bit x86 code, on short strings, we don't know of anything faster than
+// CityHash64 that is of comparable quality. We believe our nearest competitor
+// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
+// tables and most other hashing (excluding cryptography).
+//
+// For 64-bit x86 code, on long strings, the picture is more complicated.
+// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
+// CityHashCrc128 appears to be faster than all competitors of comparable
+// quality. CityHash128 is also good but not quite as fast. We believe our
+// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
+// other 64-bit CPUs, but for long strings we know that Spooky is slightly
+// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
+// Note that CityHashCrc128 is declared in citycrc.h.
+//
+// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
+// is of comparable quality. We believe our nearest competitor is Murmur3A.
+// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
+//
+// Functions in the CityHash family are not suitable for cryptography.
+//
+// Please see CityHash's README file for more details on our performance
+// measurements and so on.
+//
+// WARNING: This code has been only lightly tested on big-endian platforms!
+// It is known to work well on little-endian platforms that have a small penalty
+// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
+// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
+// bug reports are welcome.
+//
+// By the way, for some hash functions, given strings a and b, the hash
+// of a+b is easily derived from the hashes of a and b. This property
+// doesn't hold for any hash functions in this file.
+
+#ifndef BASE_THIRD_PARTY_CITYHASH_CITY_H_
+#define BASE_THIRD_PARTY_CITYHASH_CITY_H_
+
+#include <stdint.h>
+#include <stdlib.h> // for size_t.
+#include <utility>
+
+// XXX(cavalcantii): Declaring it inside of the 'base' namespace allows to
+// handle linker symbol clash error with deprecated CityHash from
+// third_party/smhasher in a few unit tests.
+namespace base {
+namespace internal {
+namespace cityhash_v111 {
+
+typedef uint8_t uint8;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef std::pair<uint64, uint64> uint128;
+
+inline uint64 Uint128Low64(const uint128& x) {
+ return x.first;
+}
+inline uint64 Uint128High64(const uint128& x) {
+ return x.second;
+}
+
+// Hash function for a byte array.
+uint64 CityHash64(const char* buf, size_t len);
+
+// Hash function for a byte array. For convenience, a 64-bit seed is also
+// hashed into the result.
+uint64 CityHash64WithSeed(const char* buf, size_t len, uint64 seed);
+
+// Hash function for a byte array. For convenience, two seeds are also
+// hashed into the result.
+uint64 CityHash64WithSeeds(const char* buf,
+ size_t len,
+ uint64 seed0,
+ uint64 seed1);
+
+// Hash function for a byte array.
+uint128 CityHash128(const char* s, size_t len);
+
+// Hash function for a byte array. For convenience, a 128-bit seed is also
+// hashed into the result.
+uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed);
+
+// Hash function for a byte array. Most useful in 32-bit binaries.
+uint32 CityHash32(const char* buf, size_t len);
+
+// Hash 128 input bits down to 64 bits of output.
+// This is intended to be a reasonably good hash function.
+inline uint64 Hash128to64(const uint128& x) {
+ // Murmur-inspired hashing.
+ const uint64 kMul = 0x9ddfea08eb382d69ULL;
+ uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
+ a ^= (a >> 47);
+ uint64 b = (Uint128High64(x) ^ a) * kMul;
+ b ^= (b >> 47);
+ b *= kMul;
+ return b;
+}
+
+} // namespace cityhash_v111
+} // namespace internal
+} // namespace base
+
+#endif // CITY_HASH_H_
diff --git a/security/sandbox/chromium/base/third_party/dynamic_annotations/LICENSE b/security/sandbox/chromium/base/third_party/dynamic_annotations/LICENSE
new file mode 100644
index 0000000000..5c581a9391
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/dynamic_annotations/LICENSE
@@ -0,0 +1,28 @@
+/* Copyright (c) 2008-2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Kostya Serebryany
+ */
diff --git a/security/sandbox/chromium/base/third_party/dynamic_annotations/dynamic_annotations.h b/security/sandbox/chromium/base/third_party/dynamic_annotations/dynamic_annotations.h
new file mode 100644
index 0000000000..8d7f05202b
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/dynamic_annotations/dynamic_annotations.h
@@ -0,0 +1,595 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This file defines dynamic annotations for use with dynamic analysis
+ tool such as valgrind, PIN, etc.
+
+ Dynamic annotation is a source code annotation that affects
+ the generated code (that is, the annotation is not a comment).
+ Each such annotation is attached to a particular
+ instruction and/or to a particular object (address) in the program.
+
+ The annotations that should be used by users are macros in all upper-case
+ (e.g., ANNOTATE_NEW_MEMORY).
+
+ Actual implementation of these macros may differ depending on the
+ dynamic analysis tool being used.
+
+ See http://code.google.com/p/data-race-test/ for more information.
+
+ This file supports the following dynamic analysis tools:
+ - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero).
+ Macros are defined empty.
+ - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1).
+ Macros are defined as calls to non-inlinable empty functions
+ that are intercepted by Valgrind. */
+
+#ifndef __DYNAMIC_ANNOTATIONS_H__
+#define __DYNAMIC_ANNOTATIONS_H__
+
+#ifndef DYNAMIC_ANNOTATIONS_PREFIX
+# define DYNAMIC_ANNOTATIONS_PREFIX
+#endif
+
+#ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND
+# define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1
+#endif
+
+#ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK
+# ifdef __GNUC__
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak))
+# else
+/* TODO(glider): for Windows support we may want to change this macro in order
+ to prepend __declspec(selectany) to the annotations' declarations. */
+# error weak annotations are not supported for your compiler
+# endif
+#else
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK
+#endif
+
+/* The following preprocessor magic prepends the value of
+ DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */
+#define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B
+#define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B)
+#define DYNAMIC_ANNOTATIONS_NAME(name) \
+ DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name)
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+# define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+ /* -------------------------------------------------------------
+ Annotations useful when implementing condition variables such as CondVar,
+ using conditional critical sections (Await/LockWhen) and when constructing
+ user-defined synchronization mechanisms.
+
+ The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can
+ be used to define happens-before arcs in user-defined synchronization
+ mechanisms: the race detector will infer an arc from the former to the
+ latter when they share the same argument pointer.
+
+ Example 1 (reference counting):
+
+ void Unref() {
+ ANNOTATE_HAPPENS_BEFORE(&refcount_);
+ if (AtomicDecrementByOne(&refcount_) == 0) {
+ ANNOTATE_HAPPENS_AFTER(&refcount_);
+ delete this;
+ }
+ }
+
+ Example 2 (message queue):
+
+ void MyQueue::Put(Type *e) {
+ MutexLock lock(&mu_);
+ ANNOTATE_HAPPENS_BEFORE(e);
+ PutElementIntoMyQueue(e);
+ }
+
+ Type *MyQueue::Get() {
+ MutexLock lock(&mu_);
+ Type *e = GetElementFromMyQueue();
+ ANNOTATE_HAPPENS_AFTER(e);
+ return e;
+ }
+
+ Note: when possible, please use the existing reference counting and message
+ queue implementations instead of inventing new ones. */
+
+ /* Report that wait on the condition variable at address "cv" has succeeded
+ and the lock at address "lock" is held. */
+ #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock)
+
+ /* Report that wait on the condition variable at "cv" has succeeded. Variant
+ w/o lock. */
+ #define ANNOTATE_CONDVAR_WAIT(cv) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL)
+
+ /* Report that we are about to signal on the condition variable at address
+ "cv". */
+ #define ANNOTATE_CONDVAR_SIGNAL(cv) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv)
+
+ /* Report that we are about to signal_all on the condition variable at address
+ "cv". */
+ #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv)
+
+ /* Annotations for user-defined synchronization mechanisms. */
+ #define ANNOTATE_HAPPENS_BEFORE(obj) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(__FILE__, __LINE__, obj)
+ #define ANNOTATE_HAPPENS_AFTER(obj) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(__FILE__, __LINE__, obj)
+
+ /* DEPRECATED. Don't use it. */
+ #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \
+ pointer, size)
+
+ /* DEPRECATED. Don't use it. */
+ #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \
+ pointer, size)
+
+ /* DEPRECATED. Don't use it. */
+ #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) \
+ do { \
+ ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \
+ ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size); \
+ } while (0)
+
+ /* Instruct the tool to create a happens-before arc between mu->Unlock() and
+ mu->Lock(). This annotation may slow down the race detector and hide real
+ races. Normally it is used only when it would be difficult to annotate each
+ of the mutex's critical sections individually using the annotations above.
+ This annotation makes sense only for hybrid race detectors. For pure
+ happens-before detectors this is a no-op. For more details see
+ http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */
+ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+ mu)
+
+ /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX.
+ Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in
+ pure happens-before mode. For a hybrid mode this is a no-op. */
+ #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu)
+
+ /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */
+ #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+ mu)
+
+ /* -------------------------------------------------------------
+ Annotations useful when defining memory allocators, or when memory that
+ was protected in one way starts to be protected in another. */
+
+ /* Report that a new memory at "address" of size "size" has been allocated.
+ This might be used when the memory has been retrieved from a free list and
+ is about to be reused, or when a the locking discipline for a variable
+ changes. */
+ #define ANNOTATE_NEW_MEMORY(address, size) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \
+ size)
+
+ /* -------------------------------------------------------------
+ Annotations useful when defining FIFO queues that transfer data between
+ threads. */
+
+ /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at
+ address "pcq" has been created. The ANNOTATE_PCQ_* annotations
+ should be used only for FIFO queues. For non-FIFO queues use
+ ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */
+ #define ANNOTATE_PCQ_CREATE(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq)
+
+ /* Report that the queue at address "pcq" is about to be destroyed. */
+ #define ANNOTATE_PCQ_DESTROY(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq)
+
+ /* Report that we are about to put an element into a FIFO queue at address
+ "pcq". */
+ #define ANNOTATE_PCQ_PUT(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq)
+
+ /* Report that we've just got an element from a FIFO queue at address
+ "pcq". */
+ #define ANNOTATE_PCQ_GET(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq)
+
+ /* -------------------------------------------------------------
+ Annotations that suppress errors. It is usually better to express the
+ program's synchronization using the other annotations, but these can
+ be used when all else fails. */
+
+ /* Report that we may have a benign race at "pointer", with size
+ "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the
+ point where "pointer" has been allocated, preferably close to the point
+ where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */
+ #define ANNOTATE_BENIGN_RACE(pointer, description) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+ pointer, sizeof(*(pointer)), description)
+
+ /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
+ the memory range [address, address+size). */
+ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+ address, size, description)
+
+ /* Request the analysis tool to ignore all reads in the current thread
+ until ANNOTATE_IGNORE_READS_END is called.
+ Useful to ignore intentional racey reads, while still checking
+ other reads and all writes.
+ See also ANNOTATE_UNPROTECTED_READ. */
+ #define ANNOTATE_IGNORE_READS_BEGIN() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+ /* Stop ignoring reads. */
+ #define ANNOTATE_IGNORE_READS_END() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+ /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */
+ #define ANNOTATE_IGNORE_WRITES_BEGIN() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+ /* Stop ignoring writes. */
+ #define ANNOTATE_IGNORE_WRITES_END() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+ /* Start ignoring all memory accesses (reads and writes). */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+ do {\
+ ANNOTATE_IGNORE_READS_BEGIN();\
+ ANNOTATE_IGNORE_WRITES_BEGIN();\
+ }while(0)\
+
+ /* Stop ignoring all memory accesses. */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+ do {\
+ ANNOTATE_IGNORE_WRITES_END();\
+ ANNOTATE_IGNORE_READS_END();\
+ }while(0)\
+
+ /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events:
+ RWLOCK* and CONDVAR*. */
+ #define ANNOTATE_IGNORE_SYNC_BEGIN() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__)
+
+ /* Stop ignoring sync events. */
+ #define ANNOTATE_IGNORE_SYNC_END() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__)
+
+
+ /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
+ This annotation could be useful if you want to skip expensive race analysis
+ during some period of program execution, e.g. during initialization. */
+ #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \
+ enable)
+
+ /* -------------------------------------------------------------
+ Annotations useful for debugging. */
+
+ /* Request to trace every access to "address". */
+ #define ANNOTATE_TRACE_MEMORY(address) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address)
+
+ /* Report the current thread name to a race detector. */
+ #define ANNOTATE_THREAD_NAME(name) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+ /* -------------------------------------------------------------
+ Annotations useful when implementing locks. They are not
+ normally needed by modules that merely use locks.
+ The "lock" argument is a pointer to the lock object. */
+
+ /* Report that a lock has been created at address "lock". */
+ #define ANNOTATE_RWLOCK_CREATE(lock) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+ /* Report that the lock at address "lock" is about to be destroyed. */
+ #define ANNOTATE_RWLOCK_DESTROY(lock) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+ /* Report that the lock at address "lock" has been acquired.
+ is_w=1 for writer lock, is_w=0 for reader lock. */
+ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \
+ is_w)
+
+ /* Report that the lock at address "lock" is about to be released. */
+ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \
+ is_w)
+
+ /* -------------------------------------------------------------
+ Annotations useful when implementing barriers. They are not
+ normally needed by modules that merely use barriers.
+ The "barrier" argument is a pointer to the barrier object. */
+
+ /* Report that the "barrier" has been initialized with initial "count".
+ If 'reinitialization_allowed' is true, initialization is allowed to happen
+ multiple times w/o calling barrier_destroy() */
+ #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \
+ count, reinitialization_allowed)
+
+ /* Report that we are about to enter barrier_wait("barrier"). */
+ #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \
+ barrier)
+
+ /* Report that we just exited barrier_wait("barrier"). */
+ #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \
+ barrier)
+
+ /* Report that the "barrier" has been destroyed. */
+ #define ANNOTATE_BARRIER_DESTROY(barrier) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \
+ barrier)
+
+ /* -------------------------------------------------------------
+ Annotations useful for testing race detectors. */
+
+ /* Report that we expect a race on the variable at "address".
+ Use only in unit tests for a race detector. */
+ #define ANNOTATE_EXPECT_RACE(address, description) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \
+ description)
+
+ #define ANNOTATE_FLUSH_EXPECTED_RACES() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__)
+
+ /* A no-op. Insert where you like to test the interceptors. */
+ #define ANNOTATE_NO_OP(arg) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg)
+
+ /* Force the race detector to flush its state. The actual effect depends on
+ * the implementation of the detector. */
+ #define ANNOTATE_FLUSH_STATE() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__)
+
+
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+ #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
+ #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
+ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
+ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
+ #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */
+ #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */
+ #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */
+ #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */
+ #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */
+ #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */
+ #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */
+ #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */
+ #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */
+ #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */
+ #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */
+ #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */
+ #define ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */
+ #define ANNOTATE_PCQ_CREATE(pcq) /* empty */
+ #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */
+ #define ANNOTATE_PCQ_PUT(pcq) /* empty */
+ #define ANNOTATE_PCQ_GET(pcq) /* empty */
+ #define ANNOTATE_NEW_MEMORY(address, size) /* empty */
+ #define ANNOTATE_EXPECT_RACE(address, description) /* empty */
+ #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */
+ #define ANNOTATE_BENIGN_RACE(address, description) /* empty */
+ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
+ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */
+ #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */
+ #define ANNOTATE_TRACE_MEMORY(arg) /* empty */
+ #define ANNOTATE_THREAD_NAME(name) /* empty */
+ #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_READS_END() /* empty */
+ #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_WRITES_END() /* empty */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
+ #define ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_SYNC_END() /* empty */
+ #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+ #define ANNOTATE_NO_OP(arg) /* empty */
+ #define ANNOTATE_FLUSH_STATE() /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+/* Use the macros above rather than using these functions directly. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+ const char *file, int line,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+ const char *file, int line,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+ const char *file, int line,
+ const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+ const char *file, int line,
+ const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+ const char *file, int line, const volatile void *barrier, long count,
+ long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+ const char *file, int line, const volatile void *cv,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+ const char *file, int line,
+ const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+ const char *file, int line,
+ const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+ const char *file, int line,
+ const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+ const char *file, int line,
+ const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+ const char *file, int line,
+ const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+ const char *file, int line,
+ const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+ const char *file, int line,
+ const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+ const char *file, int line, const volatile void *mem, long size,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+ const char *file, int line,
+ const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+ const char *file, int line,
+ const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+ const char *file, int line,
+ const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+ const char *file, int line,
+ const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+ const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+ const char *file, int line,
+ const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+/* Return non-zero value if running under valgrind.
+
+ If "valgrind.h" is included into dynamic_annotations.c,
+ the regular valgrind mechanism will be used.
+ See http://valgrind.org/docs/manual/manual-core-adv.html about
+ RUNNING_ON_VALGRIND and other valgrind "client requests".
+ The file "valgrind.h" may be obtained by doing
+ svn co svn://svn.valgrind.org/valgrind/trunk/include
+
+ If for some reason you can't use "valgrind.h" or want to fake valgrind,
+ there are two ways to make this function return non-zero:
+ - Use environment variable: export RUNNING_ON_VALGRIND=1
+ - Make your tool intercept the function RunningOnValgrind() and
+ change its return value.
+ */
+int RunningOnValgrind(void) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
+
+ /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+
+ Instead of doing
+ ANNOTATE_IGNORE_READS_BEGIN();
+ ... = x;
+ ANNOTATE_IGNORE_READS_END();
+ one can use
+ ... = ANNOTATE_UNPROTECTED_READ(x); */
+ template <class T>
+ inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) {
+ ANNOTATE_IGNORE_READS_BEGIN();
+ T res = x;
+ ANNOTATE_IGNORE_READS_END();
+ return res;
+ }
+ /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
+ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
+ namespace { \
+ class static_var ## _annotator { \
+ public: \
+ static_var ## _annotator() { \
+ ANNOTATE_BENIGN_RACE_SIZED(&static_var, \
+ sizeof(static_var), \
+ # static_var ": " description); \
+ } \
+ }; \
+ static static_var ## _annotator the ## static_var ## _annotator;\
+ }
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+ #define ANNOTATE_UNPROTECTED_READ(x) (x)
+ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+#endif /* __DYNAMIC_ANNOTATIONS_H__ */
diff --git a/security/sandbox/chromium/base/third_party/icu/LICENSE b/security/sandbox/chromium/base/third_party/icu/LICENSE
new file mode 100644
index 0000000000..2882e4ebda
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/icu/LICENSE
@@ -0,0 +1,76 @@
+COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later)
+
+Copyright © 1991-2017 Unicode, Inc. All rights reserved.
+Distributed under the Terms of Use in http://www.unicode.org/copyright.html
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Unicode data files and any associated documentation
+(the "Data Files") or Unicode software and any associated documentation
+(the "Software") to deal in the Data Files or Software
+without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, and/or sell copies of
+the Data Files or Software, and to permit persons to whom the Data Files
+or Software are furnished to do so, provided that either
+(a) this copyright and permission notice appear with all copies
+of the Data Files or Software, or
+(b) this copyright and permission notice appear in associated
+Documentation.
+
+THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale,
+use or other dealings in these Data Files or Software without prior
+written authorization of the copyright holder.
+
+---------------------
+
+Third-Party Software Licenses
+
+This section contains third-party software notices and/or additional
+terms for licensed third-party software components included within ICU
+libraries.
+
+1. ICU License - ICU 1.8.1 to ICU 57.1
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2016 International Business Machines Corporation and others
+All rights reserved.
+
+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, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+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
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
+SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
+
+All trademarks and registered trademarks mentioned herein are the
+property of their respective owners.
diff --git a/security/sandbox/chromium/base/third_party/icu/icu_utf.cc b/security/sandbox/chromium/base/third_party/icu/icu_utf.cc
new file mode 100644
index 0000000000..a3262b04d3
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/icu/icu_utf.cc
@@ -0,0 +1,131 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+*
+* Copyright (C) 1999-2012, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+* file name: utf_impl.cpp
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 1999sep13
+* created by: Markus W. Scherer
+*
+* This file provides implementation functions for macros in the utfXX.h
+* that would otherwise be too long as macros.
+*/
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base_icu {
+
+// source/common/utf_impl.cpp
+
+static const UChar32
+utf8_errorValue[6]={
+ // Same values as UTF8_ERROR_VALUE_1, UTF8_ERROR_VALUE_2, UTF_ERROR_VALUE,
+ // but without relying on the obsolete unicode/utf_old.h.
+ 0x15, 0x9f, 0xffff,
+ 0x10ffff
+};
+
+static UChar32
+errorValue(int32_t count, int8_t strict) {
+ if(strict>=0) {
+ return utf8_errorValue[count];
+ } else if(strict==-3) {
+ return 0xfffd;
+ } else {
+ return CBU_SENTINEL;
+ }
+}
+
+/*
+ * Handle the non-inline part of the U8_NEXT() and U8_NEXT_FFFD() macros
+ * and their obsolete sibling UTF8_NEXT_CHAR_SAFE().
+ *
+ * U8_NEXT() supports NUL-terminated strings indicated via length<0.
+ *
+ * The "strict" parameter controls the error behavior:
+ * <0 "Safe" behavior of U8_NEXT():
+ * -1: All illegal byte sequences yield U_SENTINEL=-1.
+ * -2: Same as -1, except for lenient treatment of surrogate code points as legal.
+ * Some implementations use this for roundtripping of
+ * Unicode 16-bit strings that are not well-formed UTF-16, that is, they
+ * contain unpaired surrogates.
+ * -3: All illegal byte sequences yield U+FFFD.
+ * 0 Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., FALSE):
+ * All illegal byte sequences yield a positive code point such that this
+ * result code point would be encoded with the same number of bytes as
+ * the illegal sequence.
+ * >0 Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., TRUE):
+ * Same as the obsolete "safe" behavior, but non-characters are also treated
+ * like illegal sequences.
+ *
+ * Note that a UBool is the same as an int8_t.
+ */
+UChar32
+utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, UChar32 c, UBool strict) {
+ // *pi is one after byte c.
+ int32_t i=*pi;
+ // length can be negative for NUL-terminated strings: Read and validate one byte at a time.
+ if(i==length || c>0xf4) {
+ // end of string, or not a lead byte
+ } else if(c>=0xf0) {
+ // Test for 4-byte sequences first because
+ // U8_NEXT() handles shorter valid sequences inline.
+ uint8_t t1=s[i], t2, t3;
+ c&=7;
+ if(CBU8_IS_VALID_LEAD4_AND_T1(c, t1) &&
+ ++i!=length && (t2=s[i]-0x80)<=0x3f &&
+ ++i!=length && (t3=s[i]-0x80)<=0x3f) {
+ ++i;
+ c=(c<<18)|((t1&0x3f)<<12)|(t2<<6)|t3;
+ // strict: forbid non-characters like U+fffe
+ if(strict<=0 || !CBU_IS_UNICODE_NONCHAR(c)) {
+ *pi=i;
+ return c;
+ }
+ }
+ } else if(c>=0xe0) {
+ c&=0xf;
+ if(strict!=-2) {
+ uint8_t t1=s[i], t2;
+ if(CBU8_IS_VALID_LEAD3_AND_T1(c, t1) &&
+ ++i!=length && (t2=s[i]-0x80)<=0x3f) {
+ ++i;
+ c=(c<<12)|((t1&0x3f)<<6)|t2;
+ // strict: forbid non-characters like U+fffe
+ if(strict<=0 || !CBU_IS_UNICODE_NONCHAR(c)) {
+ *pi=i;
+ return c;
+ }
+ }
+ } else {
+ // strict=-2 -> lenient: allow surrogates
+ uint8_t t1=s[i]-0x80, t2;
+ if(t1<=0x3f && (c>0 || t1>=0x20) &&
+ ++i!=length && (t2=s[i]-0x80)<=0x3f) {
+ *pi=i+1;
+ return (c<<12)|(t1<<6)|t2;
+ }
+ }
+ } else if(c>=0xc2) {
+ uint8_t t1=s[i]-0x80;
+ if(t1<=0x3f) {
+ *pi=i+1;
+ return ((c-0xc0)<<6)|t1;
+ }
+ } // else 0x80<=c<0xc2 is not a lead byte
+
+ /* error handling */
+ c=errorValue(i-*pi, strict);
+ *pi=i;
+ return c;
+}
+
+} // namespace base_icu
diff --git a/security/sandbox/chromium/base/third_party/icu/icu_utf.h b/security/sandbox/chromium/base/third_party/icu/icu_utf.h
new file mode 100644
index 0000000000..2ba82316c2
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/icu/icu_utf.h
@@ -0,0 +1,442 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+*
+* Copyright (C) 1999-2015, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+*/
+
+#ifndef BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+#define BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+
+#include <stdint.h>
+
+namespace base_icu {
+
+// source/common/unicode/umachine.h
+
+/** The ICU boolean type @stable ICU 2.0 */
+typedef int8_t UBool;
+
+/**
+ * Define UChar32 as a type for single Unicode code points.
+ * UChar32 is a signed 32-bit integer (same as int32_t).
+ *
+ * The Unicode code point range is 0..0x10ffff.
+ * All other values (negative or >=0x110000) are illegal as Unicode code points.
+ * They may be used as sentinel values to indicate "done", "error"
+ * or similar non-code point conditions.
+ *
+ * Before ICU 2.4 (Jitterbug 2146), UChar32 was defined
+ * to be wchar_t if that is 32 bits wide (wchar_t may be signed or unsigned)
+ * or else to be uint32_t.
+ * That is, the definition of UChar32 was platform-dependent.
+ *
+ * @see U_SENTINEL
+ * @stable ICU 2.4
+ */
+typedef int32_t UChar32;
+
+/**
+ * This value is intended for sentinel values for APIs that
+ * (take or) return single code points (UChar32).
+ * It is outside of the Unicode code point range 0..0x10ffff.
+ *
+ * For example, a "done" or "error" value in a new API
+ * could be indicated with U_SENTINEL.
+ *
+ * ICU APIs designed before ICU 2.4 usually define service-specific "done"
+ * values, mostly 0xffff.
+ * Those may need to be distinguished from
+ * actual U+ffff text contents by calling functions like
+ * CharacterIterator::hasNext() or UnicodeString::length().
+ *
+ * @return -1
+ * @see UChar32
+ * @stable ICU 2.4
+ */
+#define CBU_SENTINEL (-1)
+
+// source/common/unicode/utf.h
+
+/**
+ * Is this code point a Unicode noncharacter?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_NONCHAR(c) \
+ ((c)>=0xfdd0 && \
+ ((c)<=0xfdef || ((c)&0xfffe)==0xfffe) && (c)<=0x10ffff)
+
+/**
+ * Is c a Unicode code point value (0..U+10ffff)
+ * that can be assigned a character?
+ *
+ * Code points that are not characters include:
+ * - single surrogate code points (U+d800..U+dfff, 2048 code points)
+ * - the last two code points on each plane (U+__fffe and U+__ffff, 34 code points)
+ * - U+fdd0..U+fdef (new with Unicode 3.1, 32 code points)
+ * - the highest Unicode code point value is U+10ffff
+ *
+ * This means that all code points below U+d800 are character code points,
+ * and that boundary is tested first for performance.
+ *
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_CHAR(c) \
+ ((uint32_t)(c)<0xd800 || \
+ (0xdfff<(c) && (c)<=0x10ffff && !CBU_IS_UNICODE_NONCHAR(c)))
+
+/**
+ * Is this code point a surrogate (U+d800..U+dfff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
+
+/**
+ * Assuming c is a surrogate code point (U_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+// source/common/unicode/utf8.h
+
+/**
+ * Internal bit vector for 3-byte UTF-8 validity check, for use in U8_IS_VALID_LEAD3_AND_T1.
+ * Each bit indicates whether one lead byte + first trail byte pair starts a valid sequence.
+ * Lead byte E0..EF bits 3..0 are used as byte index,
+ * first trail byte bits 7..5 are used as bit index into that byte.
+ * @see U8_IS_VALID_LEAD3_AND_T1
+ * @internal
+ */
+#define CBU8_LEAD3_T1_BITS "\x20\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x10\x30\x30"
+
+/**
+ * Internal 3-byte UTF-8 validity check.
+ * Non-zero if lead byte E0..EF and first trail byte 00..FF start a valid sequence.
+ * @internal
+ */
+#define CBU8_IS_VALID_LEAD3_AND_T1(lead, t1) (CBU8_LEAD3_T1_BITS[(lead)&0xf]&(1<<((uint8_t)(t1)>>5)))
+
+/**
+ * Internal bit vector for 4-byte UTF-8 validity check, for use in U8_IS_VALID_LEAD4_AND_T1.
+ * Each bit indicates whether one lead byte + first trail byte pair starts a valid sequence.
+ * First trail byte bits 7..4 are used as byte index,
+ * lead byte F0..F4 bits 2..0 are used as bit index into that byte.
+ * @see U8_IS_VALID_LEAD4_AND_T1
+ * @internal
+ */
+#define CBU8_LEAD4_T1_BITS "\x00\x00\x00\x00\x00\x00\x00\x00\x1E\x0F\x0F\x0F\x00\x00\x00\x00"
+
+/**
+ * Internal 4-byte UTF-8 validity check.
+ * Non-zero if lead byte F0..F4 and first trail byte 00..FF start a valid sequence.
+ * @internal
+ */
+#define CBU8_IS_VALID_LEAD4_AND_T1(lead, t1) (CBU8_LEAD4_T1_BITS[(uint8_t)(t1)>>4]&(1<<((lead)&7)))
+
+/**
+ * Function for handling "next code point" with error-checking.
+ *
+ * This is internal since it is not meant to be called directly by external clie
+nts;
+ * however it is U_STABLE (not U_INTERNAL) since it is called by public macros i
+n this
+ * file and thus must remain stable, and should not be hidden when other interna
+l
+ * functions are hidden (otherwise public macros would fail to compile).
+ * @internal
+ */
+UChar32
+utf8_nextCharSafeBody(const uint8_t *s, int32_t *pi, int32_t length, ::base_icu::UChar32 c, ::base_icu::UBool strict);
+
+/**
+ * Does this code unit (byte) encode a code point by itself (US-ASCII 0..0x7f)?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_SINGLE(c) (((c)&0x80)==0)
+
+/**
+ * Is this code unit (byte) a UTF-8 lead byte? (0xC2..0xF4)
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_LEAD(c) ((uint8_t)((c)-0xc2)<=0x32)
+
+/**
+ * Is this code unit (byte) a UTF-8 trail byte? (0x80..0xBF)
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_TRAIL(c) ((int8_t)(c)<-0x40)
+
+/**
+ * How many code units (bytes) are used for the UTF-8 encoding
+ * of this Unicode code point?
+ * @param c 32-bit code point
+ * @return 1..4, or 0 if c is a surrogate or not a Unicode code point
+ * @stable ICU 2.4
+ */
+#define CBU8_LENGTH(c) \
+ ((uint32_t)(c)<=0x7f ? 1 : \
+ ((uint32_t)(c)<=0x7ff ? 2 : \
+ ((uint32_t)(c)<=0xd7ff ? 3 : \
+ ((uint32_t)(c)<=0xdfff || (uint32_t)(c)>0x10ffff ? 0 : \
+ ((uint32_t)(c)<=0xffff ? 3 : 4)\
+ ) \
+ ) \
+ ) \
+ )
+
+/**
+ * The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff).
+ * @return 4
+ * @stable ICU 2.4
+ */
+#define CBU8_MAX_LENGTH 4
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * The length can be negative for a NUL-terminated string.
+ *
+ * The offset may point to the lead byte of a multi-byte sequence,
+ * in which case the macro will read the whole sequence.
+ * If the offset points to a trail byte or an illegal UTF-8 sequence, then
+ * c is set to a negative value.
+ *
+ * @param s const uint8_t * string
+ * @param i int32_t string offset, must be i<length
+ * @param length int32_t string length
+ * @param c output UChar32 variable, set to <0 in case of an error
+ * @see U8_NEXT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define CBU8_NEXT(s, i, length, c) { \
+ (c)=(uint8_t)(s)[(i)++]; \
+ if(!CBU8_IS_SINGLE(c)) { \
+ uint8_t __t1, __t2; \
+ if( /* handle U+0800..U+FFFF inline */ \
+ (0xe0<=(c) && (c)<0xf0) && \
+ (((i)+1)<(length) || (length)<0) && \
+ CBU8_IS_VALID_LEAD3_AND_T1((c), __t1=(s)[i]) && \
+ (__t2=(s)[(i)+1]-0x80)<=0x3f) { \
+ (c)=(((c)&0xf)<<12)|((__t1&0x3f)<<6)|__t2; \
+ (i)+=2; \
+ } else if( /* handle U+0080..U+07FF inline */ \
+ ((c)<0xe0 && (c)>=0xc2) && \
+ ((i)!=(length)) && \
+ (__t1=(s)[i]-0x80)<=0x3f) { \
+ (c)=(((c)&0x1f)<<6)|__t1; \
+ ++(i); \
+ } else { \
+ /* function call for "complicated" and error cases */ \
+ (c)=::base_icu::utf8_nextCharSafeBody((const uint8_t *)s, &(i), (length), c, -1); \
+ } \
+ } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 to 4 bytes.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const uint8_t * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see U8_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU8_APPEND_UNSAFE(s, i, c) { \
+ if((uint32_t)(c)<=0x7f) { \
+ (s)[(i)++]=(uint8_t)(c); \
+ } else { \
+ if((uint32_t)(c)<=0x7ff) { \
+ (s)[(i)++]=(uint8_t)(((c)>>6)|0xc0); \
+ } else { \
+ if((uint32_t)(c)<=0xffff) { \
+ (s)[(i)++]=(uint8_t)(((c)>>12)|0xe0); \
+ } else { \
+ (s)[(i)++]=(uint8_t)(((c)>>18)|0xf0); \
+ (s)[(i)++]=(uint8_t)((((c)>>12)&0x3f)|0x80); \
+ } \
+ (s)[(i)++]=(uint8_t)((((c)>>6)&0x3f)|0x80); \
+ } \
+ (s)[(i)++]=(uint8_t)(((c)&0x3f)|0x80); \
+ } \
+}
+
+// source/common/unicode/utf16.h
+
+/**
+ * Does this code unit alone encode a code point (BMP, not a surrogate)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SINGLE(c) !CBU_IS_SURROGATE(c)
+
+/**
+ * Is this code unit a lead surrogate (U+d800..U+dbff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
+
+/**
+ * Is this code unit a trail surrogate (U+dc00..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
+
+/**
+ * Is this code unit a surrogate (U+d800..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE(c) CBU_IS_SURROGATE(c)
+
+/**
+ * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+/**
+ * Helper constant for U16_GET_SUPPLEMENTARY.
+ * @internal
+ */
+#define CBU16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
+
+/**
+ * Get a supplementary code point value (U+10000..U+10ffff)
+ * from its lead and trail surrogates.
+ * The result is undefined if the input values are not
+ * lead and trail surrogates.
+ *
+ * @param lead lead surrogate (U+d800..U+dbff)
+ * @param trail trail surrogate (U+dc00..U+dfff)
+ * @return supplementary code point (U+10000..U+10ffff)
+ * @stable ICU 2.4
+ */
+#define CBU16_GET_SUPPLEMENTARY(lead, trail) \
+ (((::base_icu::UChar32)(lead)<<10UL)+(::base_icu::UChar32)(trail)-CBU16_SURROGATE_OFFSET)
+
+/**
+ * Get the lead surrogate (0xd800..0xdbff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return lead surrogate (U+d800..U+dbff) for supplementary
+ * @stable ICU 2.4
+ */
+#define CBU16_LEAD(supplementary) (::base_icu::UChar)(((supplementary)>>10)+0xd7c0)
+
+/**
+ * Get the trail surrogate (0xdc00..0xdfff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return trail surrogate (U+dc00..U+dfff) for supplementary
+ * @stable ICU 2.4
+ */
+#define CBU16_TRAIL(supplementary) (::base_icu::UChar)(((supplementary)&0x3ff)|0xdc00)
+
+/**
+ * How many 16-bit code units are used to encode this Unicode code point? (1 or 2)
+ * The result is not defined if c is not a Unicode code point (U+0000..U+10ffff).
+ * @param c 32-bit code point
+ * @return 1 or 2
+ * @stable ICU 2.4
+ */
+#define CBU16_LENGTH(c) ((uint32_t)(c)<=0xffff ? 1 : 2)
+
+/**
+ * The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff).
+ * @return 2
+ * @stable ICU 2.4
+ */
+#define CBU16_MAX_LENGTH 2
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The length can be negative for a NUL-terminated string.
+ *
+ * The offset may point to the lead surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the following trail surrogate as well.
+ * If the offset points to a trail surrogate or
+ * to a single, unpaired lead surrogate, then c is set to that unpaired surrogate.
+ *
+ * @param s const UChar * string
+ * @param i string offset, must be i<length
+ * @param length string length
+ * @param c output UChar32 variable
+ * @see U16_NEXT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define CBU16_NEXT(s, i, length, c) { \
+ (c)=(s)[(i)++]; \
+ if(CBU16_IS_LEAD(c)) { \
+ uint16_t __c2; \
+ if((i)!=(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \
+ ++(i); \
+ (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \
+ } \
+ } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 or 2 code units.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const UChar * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see U16_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU16_APPEND_UNSAFE(s, i, c) { \
+ if((uint32_t)(c)<=0xffff) { \
+ (s)[(i)++]=(uint16_t)(c); \
+ } else { \
+ (s)[(i)++]=(uint16_t)(((c)>>10)+0xd7c0); \
+ (s)[(i)++]=(uint16_t)(((c)&0x3ff)|0xdc00); \
+ } \
+}
+
+} // namesapce base_icu
+
+#endif // BASE_THIRD_PARTY_ICU_ICU_UTF_H_
diff --git a/security/sandbox/chromium/base/third_party/superfasthash/LICENSE b/security/sandbox/chromium/base/third_party/superfasthash/LICENSE
new file mode 100644
index 0000000000..3c40a3ecd7
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/superfasthash/LICENSE
@@ -0,0 +1,27 @@
+Paul Hsieh OLD BSD license
+
+Copyright (c) 2010, Paul Hsieh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+* Neither my name, Paul Hsieh, nor the names of any other contributors to the
+ code use may not be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/security/sandbox/chromium/base/third_party/superfasthash/README.chromium b/security/sandbox/chromium/base/third_party/superfasthash/README.chromium
new file mode 100644
index 0000000000..d41ed7724a
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/superfasthash/README.chromium
@@ -0,0 +1,29 @@
+Name: Paul Hsieh's SuperFastHash
+Short Name: SuperFastHash
+URL: http://www.azillionmonkeys.com/qed/hash.html
+Version: 0
+Date: 2012-02-21
+License: BSD
+License File: LICENSE
+Security Critical: yes
+
+Description:
+A fast string hashing algorithm.
+
+Local Modifications:
+- Added LICENSE.
+- Added license text as a comment to the top of superfasthash.c.
+- #include <stdint.h> instead of "pstdint.h".
+- #include <stdlib.h>.
+
+The license is a standard 3-clause BSD license with the following minor changes:
+
+"nor the names of its contributors may be used"
+is replaced with:
+"nor the names of any other contributors to the code use may not be used"
+
+and
+
+"IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE"
+is replaced with:
+"IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE"
diff --git a/security/sandbox/chromium/base/third_party/superfasthash/superfasthash.c b/security/sandbox/chromium/base/third_party/superfasthash/superfasthash.c
new file mode 100644
index 0000000000..6e7687e131
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/superfasthash/superfasthash.c
@@ -0,0 +1,84 @@
+// Copyright (c) 2010, Paul Hsieh
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+// * Neither my name, Paul Hsieh, nor the names of any other contributors to the
+// code use may not be used to endorse or promote products derived from this
+// software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdint.h>
+#include <stdlib.h>
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t SuperFastHash (const char * data, int len) {
+uint32_t hash = len, tmp;
+int rem;
+
+ if (len <= 0 || data == NULL) return 0;
+
+ rem = len & 3;
+ len >>= 2;
+
+ /* Main loop */
+ for (;len > 0; len--) {
+ hash += get16bits (data);
+ tmp = (get16bits (data+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ data += 2*sizeof (uint16_t);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem) {
+ case 3: hash += get16bits (data);
+ hash ^= hash << 16;
+ hash ^= ((signed char)data[sizeof (uint16_t)]) << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += get16bits (data);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += (signed char)*data;
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
diff --git a/security/sandbox/chromium/base/third_party/valgrind/LICENSE b/security/sandbox/chromium/base/third_party/valgrind/LICENSE
new file mode 100644
index 0000000000..41f677bd17
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/valgrind/LICENSE
@@ -0,0 +1,39 @@
+ Notice that the following BSD-style license applies to the Valgrind header
+ files used by Chromium (valgrind.h and memcheck.h). However, the rest of
+ Valgrind is licensed under the terms of the GNU General Public License,
+ version 2, unless otherwise indicated.
+
+ ----------------------------------------------------------------
+
+ Copyright (C) 2000-2008 Julian Seward. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/security/sandbox/chromium/base/third_party/valgrind/valgrind.h b/security/sandbox/chromium/base/third_party/valgrind/valgrind.h
new file mode 100644
index 0000000000..0bae0aa130
--- /dev/null
+++ b/security/sandbox/chromium/base/third_party/valgrind/valgrind.h
@@ -0,0 +1,4792 @@
+/* -*- c -*-
+ ----------------------------------------------------------------
+
+ Notice that the following BSD-style license applies to this one
+ file (valgrind.h) only. The rest of Valgrind is licensed under the
+ terms of the GNU General Public License, version 2, unless
+ otherwise indicated. See the COPYING file in the source
+ distribution for details.
+
+ ----------------------------------------------------------------
+
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2010 Julian Seward. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. The origin of this software must not be misrepresented; you must
+ not claim that you wrote the original software. If you use this
+ software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 3. Altered source versions must be plainly marked as such, and must
+ not be misrepresented as being the original software.
+
+ 4. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ----------------------------------------------------------------
+
+ Notice that the above BSD-style license applies to this one file
+ (valgrind.h) only. The entire rest of Valgrind is licensed under
+ the terms of the GNU General Public License, version 2. See the
+ COPYING file in the source distribution for details.
+
+ ----------------------------------------------------------------
+*/
+
+
+/* This file is for inclusion into client (your!) code.
+
+ You can use these macros to manipulate and query Valgrind's
+ execution inside your own programs.
+
+ The resulting executables will still run without Valgrind, just a
+ little bit more slowly than they otherwise would, but otherwise
+ unchanged. When not running on valgrind, each client request
+ consumes very few (eg. 7) instructions, so the resulting performance
+ loss is negligible unless you plan to execute client requests
+ millions of times per second. Nevertheless, if that is still a
+ problem, you can compile with the NVALGRIND symbol defined (gcc
+ -DNVALGRIND) so that client requests are not even compiled in. */
+
+#ifndef __VALGRIND_H
+#define __VALGRIND_H
+
+
+/* ------------------------------------------------------------------ */
+/* VERSION NUMBER OF VALGRIND */
+/* ------------------------------------------------------------------ */
+
+/* Specify Valgrind's version number, so that user code can
+ conditionally compile based on our version number. Note that these
+ were introduced at version 3.6 and so do not exist in version 3.5
+ or earlier. The recommended way to use them to check for "version
+ X.Y or later" is (eg)
+
+#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \
+ && (__VALGRIND_MAJOR__ > 3 \
+ || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
+*/
+#define __VALGRIND_MAJOR__ 3
+#define __VALGRIND_MINOR__ 6
+
+
+#include <stdarg.h>
+
+/* Nb: this file might be included in a file compiled with -ansi. So
+ we can't use C++ style "//" comments nor the "asm" keyword (instead
+ use "__asm__"). */
+
+/* Derive some tags indicating what the target platform is. Note
+ that in this file we're using the compiler's CPP symbols for
+ identifying architectures, which are different to the ones we use
+ within the rest of Valgrind. Note, __powerpc__ is active for both
+ 32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+ latter (on Linux, that is).
+
+ Misc note: how to find out what's predefined in gcc by default:
+ gcc -Wp,-dM somefile.c
+*/
+#undef PLAT_ppc64_aix5
+#undef PLAT_ppc32_aix5
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+#undef PLAT_x86_win32
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+
+#if defined(_AIX) && defined(__64BIT__)
+# define PLAT_ppc64_aix5 1
+#elif defined(_AIX) && !defined(__64BIT__)
+# define PLAT_ppc32_aix5 1
+#elif defined(__APPLE__) && defined(__i386__)
+# define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+# define PLAT_amd64_darwin 1
+#elif defined(__MINGW32__) || defined(__CYGWIN32__) || defined(_WIN32) && defined(_M_IX86)
+# define PLAT_x86_win32 1
+#elif defined(__linux__) && defined(__i386__)
+# define PLAT_x86_linux 1
+#elif defined(__linux__) && defined(__x86_64__)
+# define PLAT_amd64_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
+# define PLAT_ppc32_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
+# define PLAT_ppc64_linux 1
+#elif defined(__linux__) && defined(__arm__)
+# define PLAT_arm_linux 1
+#else
+/* If we're not compiling for our target platform, don't generate
+ any inline asms. */
+# if !defined(NVALGRIND)
+# define NVALGRIND 1
+# endif
+#endif
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */
+/* in here of use to end-users -- skip to the next section. */
+/* ------------------------------------------------------------------ */
+
+#if defined(NVALGRIND)
+
+/* Define NVALGRIND to completely remove the Valgrind magic sequence
+ from the compiled code (analogous to NDEBUG's effects on
+ assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ { \
+ (_zzq_rlval) = (_zzq_default); \
+ }
+
+#else /* ! NVALGRIND */
+
+/* The following defines the magic code sequences which the JITter
+ spots and handles magically. Don't look too closely at them as
+ they will rot your brain.
+
+ The assembly code sequences for all architectures is in this one
+ file. This is because this file must be stand-alone, and we don't
+ want to have multiple files.
+
+ For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+ value gets put in the return slot, so that everything works when
+ this is executed not under Valgrind. Args are passed in a memory
+ block, and so there's no intrinsic limit to the number that could
+ be passed, but it's currently five.
+
+ The macro args are:
+ _zzq_rlval result lvalue
+ _zzq_default default value (result returned when running on real CPU)
+ _zzq_request request code
+ _zzq_arg1..5 request params
+
+ The other two macros are used to support function wrapping, and are
+ a lot simpler. VALGRIND_GET_NR_CONTEXT returns the value of the
+ guest's NRADDR pseudo-register and whatever other information is
+ needed to safely run the call original from the wrapper: on
+ ppc64-linux, the R2 value at the divert point is also needed. This
+ information is abstracted into a user-visible type, OrigFn.
+
+ VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
+ guest, but guarantees that the branch instruction will not be
+ redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
+ branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a
+ complete inline asm, since it needs to be combined with more magic
+ inline asm stuff to be useful.
+*/
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \
+ || (defined(PLAT_x86_win32) && defined(__GNUC__))
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "roll $3, %%edi ; roll $13, %%edi\n\t" \
+ "roll $29, %%edi ; roll $19, %%edi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ { volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EDX = client_request ( %EAX ) */ \
+ "xchgl %%ebx,%%ebx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EAX = guest_NRADDR */ \
+ "xchgl %%ecx,%%ecx" \
+ : "=a" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_EAX \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir *%EAX */ \
+ "xchgl %%edx,%%edx\n\t"
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */
+
+/* ------------------------- x86-Win32 ------------------------- */
+
+#if defined(PLAT_x86_win32) && !defined(__GNUC__)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#if defined(_MSC_VER)
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ __asm rol edi, 3 __asm rol edi, 13 \
+ __asm rol edi, 29 __asm rol edi, 19
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ { volatile uintptr_t _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (uintptr_t)(_zzq_request); \
+ _zzq_args[1] = (uintptr_t)(_zzq_arg1); \
+ _zzq_args[2] = (uintptr_t)(_zzq_arg2); \
+ _zzq_args[3] = (uintptr_t)(_zzq_arg3); \
+ _zzq_args[4] = (uintptr_t)(_zzq_arg4); \
+ _zzq_args[5] = (uintptr_t)(_zzq_arg5); \
+ __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EDX = client_request ( %EAX ) */ \
+ __asm xchg ebx,ebx \
+ __asm mov _zzq_result, edx \
+ } \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned int __addr; \
+ __asm { __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %EAX = guest_NRADDR */ \
+ __asm xchg ecx,ecx \
+ __asm mov __addr, eax \
+ } \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_EAX ERROR
+
+#else
+#error Unsupported compiler.
+#endif
+
+#endif /* PLAT_x86_win32 */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin)
+
+typedef
+ struct {
+ unsigned long long int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \
+ "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ { volatile unsigned long long int _zzq_args[6]; \
+ volatile unsigned long long int _zzq_result; \
+ _zzq_args[0] = (unsigned long long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %RDX = client_request ( %RAX ) */ \
+ "xchgq %%rbx,%%rbx" \
+ : "=d" (_zzq_result) \
+ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
+ : "cc", "memory" \
+ ); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ volatile unsigned long long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %RAX = guest_NRADDR */ \
+ "xchgq %%rcx,%%rcx" \
+ : "=a" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_CALL_NOREDIR_RAX \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* call-noredir *%RAX */ \
+ "xchgq %%rdx,%%rdx\n\t"
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \
+ "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned int _zzq_args[6]; \
+ unsigned int _zzq_result; \
+ unsigned int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 3,%1\n\t" /*default*/ \
+ "mr 4,%2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" /*result*/ \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_default), "b" (_zzq_ptr) \
+ : "cc", "memory", "r3", "r4"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+typedef
+ struct {
+ unsigned long long int nraddr; /* where's the code? */
+ unsigned long long int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
+ "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned long long int _zzq_args[6]; \
+ register unsigned long long int _zzq_result __asm__("r3"); \
+ register unsigned long long int* _zzq_ptr __asm__("r4"); \
+ _zzq_args[0] = (unsigned long long int)(_zzq_request); \
+ _zzq_args[1] = (unsigned long long int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned long long int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned long long int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned long long int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned long long int)(_zzq_arg5); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1" \
+ : "=r" (_zzq_result) \
+ : "0" (_zzq_default), "r" (_zzq_ptr) \
+ : "cc", "memory"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ register unsigned long long int __addr __asm__("r3"); \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2" \
+ : "=r" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4" \
+ : "=r" (__addr) \
+ : \
+ : "cc", "memory" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \
+ "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { volatile unsigned int _zzq_args[6]; \
+ volatile unsigned int _zzq_result; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ __asm__ volatile("mov r3, %1\n\t" /*default*/ \
+ "mov r4, %2\n\t" /*ptr*/ \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* R3 = client_request ( R4 ) */ \
+ "orr r10, r10, r10\n\t" \
+ "mov %0, r3" /*result*/ \
+ : "=r" (_zzq_result) \
+ : "r" (_zzq_default), "r" (&_zzq_args[0]) \
+ : "cc","memory", "r3", "r4"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* R3 = guest_NRADDR */ \
+ "orr r11, r11, r11\n\t" \
+ "mov %0, r3" \
+ : "=r" (__addr) \
+ : \
+ : "cc", "memory", "r3" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R4 */ \
+ "orr r12, r12, r12\n\t"
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+typedef
+ struct {
+ unsigned int nraddr; /* where's the code? */
+ unsigned int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \
+ "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned int _zzq_args[7]; \
+ register unsigned int _zzq_result; \
+ register unsigned int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned int)(_zzq_request); \
+ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
+ _zzq_args[6] = (unsigned int)(_zzq_default); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 4,%1\n\t" \
+ "lwz 3, 24(4)\n\t" \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_ptr) \
+ : "r3", "r4", "cc", "memory"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ register unsigned int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+typedef
+ struct {
+ unsigned long long int nraddr; /* where's the code? */
+ unsigned long long int r2; /* what tocptr do we need? */
+ }
+ OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE \
+ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
+ "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST( \
+ _zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ \
+ { unsigned long long int _zzq_args[7]; \
+ register unsigned long long int _zzq_result; \
+ register unsigned long long int* _zzq_ptr; \
+ _zzq_args[0] = (unsigned int long long)(_zzq_request); \
+ _zzq_args[1] = (unsigned int long long)(_zzq_arg1); \
+ _zzq_args[2] = (unsigned int long long)(_zzq_arg2); \
+ _zzq_args[3] = (unsigned int long long)(_zzq_arg3); \
+ _zzq_args[4] = (unsigned int long long)(_zzq_arg4); \
+ _zzq_args[5] = (unsigned int long long)(_zzq_arg5); \
+ _zzq_args[6] = (unsigned int long long)(_zzq_default); \
+ _zzq_ptr = _zzq_args; \
+ __asm__ volatile("mr 4,%1\n\t" \
+ "ld 3, 48(4)\n\t" \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = client_request ( %R4 ) */ \
+ "or 1,1,1\n\t" \
+ "mr %0,3" \
+ : "=b" (_zzq_result) \
+ : "b" (_zzq_ptr) \
+ : "r3", "r4", "cc", "memory"); \
+ _zzq_rlval = _zzq_result; \
+ }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
+ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
+ register unsigned long long int __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR */ \
+ "or 2,2,2\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->nraddr = __addr; \
+ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
+ /* %R3 = guest_NRADDR_GPR2 */ \
+ "or 4,4,4\n\t" \
+ "mr %0,3" \
+ : "=b" (__addr) \
+ : \
+ : "r3", "cc", "memory" \
+ ); \
+ _zzq_orig->r2 = __addr; \
+ }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ __SPECIAL_INSTRUCTION_PREAMBLE \
+ /* branch-and-link-to-noredir *%R11 */ \
+ "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_aix5 */
+
+/* Insert assembly code for other platforms here... */
+
+#endif /* NVALGRIND */
+
+
+/* ------------------------------------------------------------------ */
+/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */
+/* ugly. It's the least-worst tradeoff I can think of. */
+/* ------------------------------------------------------------------ */
+
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+ guaranteed-no-redirection macros, so as to get from function
+ wrappers to the functions they are wrapping. The whole point is to
+ construct standard call sequences, but to do the call itself with a
+ special no-redirect call pseudo-instruction that the JIT
+ understands and handles specially. This section is long and
+ repetitious, and I can't see a way to make it shorter.
+
+ The naming scheme is as follows:
+
+ CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc}
+
+ 'W' stands for "word" and 'v' for "void". Hence there are
+ different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+ and for each, the possibility of returning a word-typed result, or
+ no result.
+*/
+
+/* Use these to write the name of your wrapper. NOTE: duplicates
+ VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
+
+/* Use an extra level of macroisation so as to ensure the soname/fnname
+ args are fully macro-expanded before pasting them together. */
+#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \
+ VG_CONCAT4(_vgwZU_,soname,_,fnname)
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \
+ VG_CONCAT4(_vgwZZ_,soname,_,fnname)
+
+/* Use this macro from within a wrapper function to collect the
+ context (address and possibly other info) of the original function.
+ Once you have that you can then use it in one of the CALL_FN_
+ macros. The type of the argument _lval is OrigFn. */
+#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval)
+
+/* Derivatives of the main macros below, for calling functions
+ returning void. */
+
+#define CALL_FN_v_v(fnptr) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_v_W(fnptr, arg1) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
+
+#define CALL_FN_v_WW(fnptr, arg1,arg2) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
+
+#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
+
+#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0)
+
+#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0)
+
+#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0)
+
+#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \
+ do { volatile unsigned long _junk; \
+ CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin)
+
+/* These regs are trashed by the hidden call. No need to mention eax
+ as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ "subl $12, %%esp\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $16, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ "subl $8, %%esp\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $16, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ "subl $4, %%esp\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $16, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $16, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ "subl $12, %%esp\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $32, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ "subl $8, %%esp\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $32, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ "subl $4, %%esp\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $32, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $32, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ "subl $12, %%esp\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $48, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ "subl $8, %%esp\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $48, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ "subl $4, %%esp\n\t" \
+ "pushl 44(%%eax)\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $48, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ "pushl 48(%%eax)\n\t" \
+ "pushl 44(%%eax)\n\t" \
+ "pushl 40(%%eax)\n\t" \
+ "pushl 36(%%eax)\n\t" \
+ "pushl 32(%%eax)\n\t" \
+ "pushl 28(%%eax)\n\t" \
+ "pushl 24(%%eax)\n\t" \
+ "pushl 20(%%eax)\n\t" \
+ "pushl 16(%%eax)\n\t" \
+ "pushl 12(%%eax)\n\t" \
+ "pushl 8(%%eax)\n\t" \
+ "pushl 4(%%eax)\n\t" \
+ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
+ VALGRIND_CALL_NOREDIR_EAX \
+ "addl $48, %%esp\n" \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin)
+
+/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \
+ "rdi", "r8", "r9", "r10", "r11"
+
+/* This is all pretty complex. It's so as to make stack unwinding
+ work reliably. See bug 243270. The basic problem is the sub and
+ add of 128 of %rsp in all of the following macros. If gcc believes
+ the CFA is in %rsp, then unwinding may fail, because what's at the
+ CFA is not what gcc "expected" when it constructs the CFIs for the
+ places where the macros are instantiated.
+
+ But we can't just add a CFI annotation to increase the CFA offset
+ by 128, to match the sub of 128 from %rsp, because we don't know
+ whether gcc has chosen %rsp as the CFA at that point, or whether it
+ has chosen some other register (eg, %rbp). In the latter case,
+ adding a CFI annotation to change the CFA offset is simply wrong.
+
+ So the solution is to get hold of the CFA using
+ __builtin_dwarf_cfa(), put it in a known register, and add a
+ CFI annotation to say what the register is. We choose %rbp for
+ this (perhaps perversely), because:
+
+ (1) %rbp is already subject to unwinding. If a new register was
+ chosen then the unwinder would have to unwind it in all stack
+ traces, which is expensive, and
+
+ (2) %rbp is already subject to precise exception updates in the
+ JIT. If a new register was chosen, we'd have to have precise
+ exceptions for it too, which reduces performance of the
+ generated code.
+
+ However .. one extra complication. We can't just whack the result
+ of __builtin_dwarf_cfa() into %rbp and then add %rbp to the
+ list of trashed registers at the end of the inline assembly
+ fragments; gcc won't allow %rbp to appear in that list. Hence
+ instead we need to stash %rbp in %r15 for the duration of the asm,
+ and say that %r15 is trashed instead. gcc seems happy to go with
+ that.
+
+ Oh .. and this all needs to be conditionalised so that it is
+ unchanged from before this commit, when compiled with older gccs
+ that don't support __builtin_dwarf_cfa. Furthermore, since
+ this header file is freestanding, it has to be independent of
+ config.h, and so the following conditionalisation cannot depend on
+ configure time checks.
+
+ Although it's not clear from
+ 'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)',
+ this expression excludes Darwin.
+ .cfi directives in Darwin assembly appear to be completely
+ different and I haven't investigated how they work.
+
+ For even more entertainment value, note we have to use the
+ completely undocumented __builtin_dwarf_cfa(), which appears to
+ really compute the CFA, whereas __builtin_frame_address(0) claims
+ to but actually doesn't. See
+ https://bugs.kde.org/show_bug.cgi?id=243270#c47
+*/
+#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
+# define __FRAME_POINTER \
+ ,"r"(__builtin_dwarf_cfa())
+# define VALGRIND_CFI_PROLOGUE \
+ "movq %%rbp, %%r15\n\t" \
+ "movq %2, %%rbp\n\t" \
+ ".cfi_remember_state\n\t" \
+ ".cfi_def_cfa rbp, 0\n\t"
+# define VALGRIND_CFI_EPILOGUE \
+ "movq %%r15, %%rbp\n\t" \
+ ".cfi_restore_state\n\t"
+#else
+# define __FRAME_POINTER
+# define VALGRIND_CFI_PROLOGUE
+# define VALGRIND_CFI_EPILOGUE
+#endif
+
+
+/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
+ long) == 8. */
+
+/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_
+ macros. In order not to trash the stack redzone, we need to drop
+ %rsp by 128 before the hidden call, and restore afterwards. The
+ nastyness is that it is only by luck that the stack still appears
+ to be unwindable during the hidden call - since then the behaviour
+ of any routine using this macro does not match what the CFI data
+ says. Sigh.
+
+ Why is this important? Imagine that a wrapper has a stack
+ allocated local, and passes to the hidden call, a pointer to it.
+ Because gcc does not know about the hidden call, it may allocate
+ that local in the redzone. Unfortunately the hidden call may then
+ trash it before it comes to use it. So we must step clear of the
+ redzone, for the duration of the hidden call, to make it safe.
+
+ Probably the same problem afflicts the other redzone-style ABIs too
+ (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is
+ self describing (none of this CFI nonsense) so at least messing
+ with the stack pointer doesn't give a danger of non-unwindable
+ stack. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $136,%%rsp\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $8, %%rsp\n" \
+ "addq $136,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $16, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $136,%%rsp\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $24, %%rsp\n" \
+ "addq $136,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $32, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $136,%%rsp\n\t" \
+ "pushq 88(%%rax)\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $40, %%rsp\n" \
+ "addq $136,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ VALGRIND_CFI_PROLOGUE \
+ "subq $128,%%rsp\n\t" \
+ "pushq 96(%%rax)\n\t" \
+ "pushq 88(%%rax)\n\t" \
+ "pushq 80(%%rax)\n\t" \
+ "pushq 72(%%rax)\n\t" \
+ "pushq 64(%%rax)\n\t" \
+ "pushq 56(%%rax)\n\t" \
+ "movq 48(%%rax), %%r9\n\t" \
+ "movq 40(%%rax), %%r8\n\t" \
+ "movq 32(%%rax), %%rcx\n\t" \
+ "movq 24(%%rax), %%rdx\n\t" \
+ "movq 16(%%rax), %%rsi\n\t" \
+ "movq 8(%%rax), %%rdi\n\t" \
+ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
+ VALGRIND_CALL_NOREDIR_RAX \
+ "addq $48, %%rsp\n" \
+ "addq $128,%%rsp\n\t" \
+ VALGRIND_CFI_EPILOGUE \
+ : /*out*/ "=a" (_res) \
+ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+/* This is useful for finding out about the on-stack stuff:
+
+ extern int f9 ( int,int,int,int,int,int,int,int,int );
+ extern int f10 ( int,int,int,int,int,int,int,int,int,int );
+ extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
+ extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int );
+
+ int g9 ( void ) {
+ return f9(11,22,33,44,55,66,77,88,99);
+ }
+ int g10 ( void ) {
+ return f10(11,22,33,44,55,66,77,88,99,110);
+ }
+ int g11 ( void ) {
+ return f11(11,22,33,44,55,66,77,88,99,110,121);
+ }
+ int g12 ( void ) {
+ return f12(11,22,33,44,55,66,77,88,99,110,121,132);
+ }
+*/
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc32-linux,
+ sizeof(unsigned long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-16\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,16\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-16\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,16\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-32\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,16(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,32\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)arg1; \
+ _argvec[2] = (unsigned long)arg2; \
+ _argvec[3] = (unsigned long)arg3; \
+ _argvec[4] = (unsigned long)arg4; \
+ _argvec[5] = (unsigned long)arg5; \
+ _argvec[6] = (unsigned long)arg6; \
+ _argvec[7] = (unsigned long)arg7; \
+ _argvec[8] = (unsigned long)arg8; \
+ _argvec[9] = (unsigned long)arg9; \
+ _argvec[10] = (unsigned long)arg10; \
+ _argvec[11] = (unsigned long)arg11; \
+ _argvec[12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "addi 1,1,-32\n\t" \
+ /* arg12 */ \
+ "lwz 3,48(11)\n\t" \
+ "stw 3,20(1)\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,16(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,12(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,8(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3,4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4,8(11)\n\t" \
+ "lwz 5,12(11)\n\t" \
+ "lwz 6,16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7,20(11)\n\t" \
+ "lwz 8,24(11)\n\t" \
+ "lwz 9,28(11)\n\t" \
+ "lwz 10,32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11,0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "addi 1,1,32\n\t" \
+ "mr %0,3" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+ long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)" /* restore tocptr */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,128" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-128\n\t" /* expand stack frame */ \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,128" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,144" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "addi 1,1,-144\n\t" /* expand stack frame */ \
+ /* arg12 */ \
+ "ld 3,96(11)\n\t" \
+ "std 3,136(1)\n\t" \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ "addi 1,1,144" /* restore frame */ \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14"
+
+/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[1]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[2]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[4]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "mov %0, r0\n" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[5]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[6]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #20] \n\t" \
+ "push {r0} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #4 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[7]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "push {r0, r1} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #8 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[8]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "push {r0, r1, r2} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #12 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[9]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "push {r0, r1, r2, r3} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #16 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[10]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #20 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[11]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #40] \n\t" \
+ "push {r0} \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #24 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[12]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #40] \n\t" \
+ "ldr r1, [%1, #44] \n\t" \
+ "push {r0, r1} \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #28 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory",__CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
+ arg6,arg7,arg8,arg9,arg10, \
+ arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[13]; \
+ volatile unsigned long _res; \
+ _argvec[0] = (unsigned long)_orig.nraddr; \
+ _argvec[1] = (unsigned long)(arg1); \
+ _argvec[2] = (unsigned long)(arg2); \
+ _argvec[3] = (unsigned long)(arg3); \
+ _argvec[4] = (unsigned long)(arg4); \
+ _argvec[5] = (unsigned long)(arg5); \
+ _argvec[6] = (unsigned long)(arg6); \
+ _argvec[7] = (unsigned long)(arg7); \
+ _argvec[8] = (unsigned long)(arg8); \
+ _argvec[9] = (unsigned long)(arg9); \
+ _argvec[10] = (unsigned long)(arg10); \
+ _argvec[11] = (unsigned long)(arg11); \
+ _argvec[12] = (unsigned long)(arg12); \
+ __asm__ volatile( \
+ "ldr r0, [%1, #40] \n\t" \
+ "ldr r1, [%1, #44] \n\t" \
+ "ldr r2, [%1, #48] \n\t" \
+ "push {r0, r1, r2} \n\t" \
+ "ldr r0, [%1, #20] \n\t" \
+ "ldr r1, [%1, #24] \n\t" \
+ "ldr r2, [%1, #28] \n\t" \
+ "ldr r3, [%1, #32] \n\t" \
+ "ldr r4, [%1, #36] \n\t" \
+ "push {r0, r1, r2, r3, r4} \n\t" \
+ "ldr r0, [%1, #4] \n\t" \
+ "ldr r1, [%1, #8] \n\t" \
+ "ldr r2, [%1, #12] \n\t" \
+ "ldr r3, [%1, #16] \n\t" \
+ "ldr r4, [%1] \n\t" /* target->r4 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
+ "add sp, sp, #32 \n\t" \
+ "mov %0, r0" \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "0" (&_argvec[0]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+ still works. Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \
+ "addi 1,1,-" #_n_fr "\n\t" \
+ "lwz 3," #_n_fr "(1)\n\t" \
+ "stw 3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr) \
+ "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned
+ long) == 4. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(64) \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(64) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(64) \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,60(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(64) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(72) \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,64(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,60(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(72) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "stw 2,-8(11)\n\t" /* save tocptr */ \
+ "lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(72) \
+ /* arg12 */ \
+ "lwz 3,48(11)\n\t" \
+ "stw 3,68(1)\n\t" \
+ /* arg11 */ \
+ "lwz 3,44(11)\n\t" \
+ "stw 3,64(1)\n\t" \
+ /* arg10 */ \
+ "lwz 3,40(11)\n\t" \
+ "stw 3,60(1)\n\t" \
+ /* arg9 */ \
+ "lwz 3,36(11)\n\t" \
+ "stw 3,56(1)\n\t" \
+ /* args1-8 */ \
+ "lwz 3, 4(11)\n\t" /* arg1->r3 */ \
+ "lwz 4, 8(11)\n\t" /* arg2->r4 */ \
+ "lwz 5, 12(11)\n\t" /* arg3->r5 */ \
+ "lwz 6, 16(11)\n\t" /* arg4->r6 */ \
+ "lwz 7, 20(11)\n\t" /* arg5->r7 */ \
+ "lwz 8, 24(11)\n\t" /* arg6->r8 */ \
+ "lwz 9, 28(11)\n\t" /* arg7->r9 */ \
+ "lwz 10, 32(11)\n\t" /* arg8->r10 */ \
+ "lwz 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "lwz 2,-8(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(72) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS \
+ "lr", "ctr", "xer", \
+ "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
+ "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
+ "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+ still works. Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \
+ "addi 1,1,-" #_n_fr "\n\t" \
+ "ld 3," #_n_fr "(1)\n\t" \
+ "std 3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr) \
+ "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned
+ long) == 8. */
+
+#define CALL_FN_W_v(lval, orig) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+0]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+1]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+2]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+3]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+4]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+5]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+6]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+7]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+8]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+9]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(128) \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(128) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+10]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(128) \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(128) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+11]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(144) \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(144) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
+ arg7,arg8,arg9,arg10,arg11,arg12) \
+ do { \
+ volatile OrigFn _orig = (orig); \
+ volatile unsigned long _argvec[3+12]; \
+ volatile unsigned long _res; \
+ /* _argvec[0] holds current r2 across the call */ \
+ _argvec[1] = (unsigned long)_orig.r2; \
+ _argvec[2] = (unsigned long)_orig.nraddr; \
+ _argvec[2+1] = (unsigned long)arg1; \
+ _argvec[2+2] = (unsigned long)arg2; \
+ _argvec[2+3] = (unsigned long)arg3; \
+ _argvec[2+4] = (unsigned long)arg4; \
+ _argvec[2+5] = (unsigned long)arg5; \
+ _argvec[2+6] = (unsigned long)arg6; \
+ _argvec[2+7] = (unsigned long)arg7; \
+ _argvec[2+8] = (unsigned long)arg8; \
+ _argvec[2+9] = (unsigned long)arg9; \
+ _argvec[2+10] = (unsigned long)arg10; \
+ _argvec[2+11] = (unsigned long)arg11; \
+ _argvec[2+12] = (unsigned long)arg12; \
+ __asm__ volatile( \
+ "mr 11,%1\n\t" \
+ VG_EXPAND_FRAME_BY_trashes_r3(512) \
+ "std 2,-16(11)\n\t" /* save tocptr */ \
+ "ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
+ VG_EXPAND_FRAME_BY_trashes_r3(144) \
+ /* arg12 */ \
+ "ld 3,96(11)\n\t" \
+ "std 3,136(1)\n\t" \
+ /* arg11 */ \
+ "ld 3,88(11)\n\t" \
+ "std 3,128(1)\n\t" \
+ /* arg10 */ \
+ "ld 3,80(11)\n\t" \
+ "std 3,120(1)\n\t" \
+ /* arg9 */ \
+ "ld 3,72(11)\n\t" \
+ "std 3,112(1)\n\t" \
+ /* args1-8 */ \
+ "ld 3, 8(11)\n\t" /* arg1->r3 */ \
+ "ld 4, 16(11)\n\t" /* arg2->r4 */ \
+ "ld 5, 24(11)\n\t" /* arg3->r5 */ \
+ "ld 6, 32(11)\n\t" /* arg4->r6 */ \
+ "ld 7, 40(11)\n\t" /* arg5->r7 */ \
+ "ld 8, 48(11)\n\t" /* arg6->r8 */ \
+ "ld 9, 56(11)\n\t" /* arg7->r9 */ \
+ "ld 10, 64(11)\n\t" /* arg8->r10 */ \
+ "ld 11, 0(11)\n\t" /* target->r11 */ \
+ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
+ "mr 11,%1\n\t" \
+ "mr %0,3\n\t" \
+ "ld 2,-16(11)\n\t" /* restore tocptr */ \
+ VG_CONTRACT_FRAME_BY(144) \
+ VG_CONTRACT_FRAME_BY(512) \
+ : /*out*/ "=r" (_res) \
+ : /*in*/ "r" (&_argvec[2]) \
+ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
+ ); \
+ lval = (__typeof__(lval)) _res; \
+ } while (0)
+
+#endif /* PLAT_ppc64_aix5 */
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */
+/* */
+/* ------------------------------------------------------------------ */
+
+/* Some request codes. There are many more of these, but most are not
+ exposed to end-user view. These are the public ones, all of the
+ form 0x1000 + small_number.
+
+ Core ones are in the range 0x00000000--0x0000ffff. The non-public
+ ones start at 0x2000.
+*/
+
+/* These macros are used by tools -- they must be public, but don't
+ embed them into other programs. */
+#define VG_USERREQ_TOOL_BASE(a,b) \
+ ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
+#define VG_IS_TOOL_USERREQ(a, b, v) \
+ (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !!
+ This enum comprises an ABI exported by Valgrind to programs
+ which use client requests. DO NOT CHANGE THE ORDER OF THESE
+ ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+ enum { VG_USERREQ__RUNNING_ON_VALGRIND = 0x1001,
+ VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
+
+ /* These allow any function to be called from the simulated
+ CPU but run on the real CPU. Nb: the first arg passed to
+ the function is always the ThreadId of the running
+ thread! So CLIENT_CALL0 actually requires a 1 arg
+ function, etc. */
+ VG_USERREQ__CLIENT_CALL0 = 0x1101,
+ VG_USERREQ__CLIENT_CALL1 = 0x1102,
+ VG_USERREQ__CLIENT_CALL2 = 0x1103,
+ VG_USERREQ__CLIENT_CALL3 = 0x1104,
+
+ /* Can be useful in regression testing suites -- eg. can
+ send Valgrind's output to /dev/null and still count
+ errors. */
+ VG_USERREQ__COUNT_ERRORS = 0x1201,
+
+ /* These are useful and can be interpreted by any tool that
+ tracks malloc() et al, by using vg_replace_malloc.c. */
+ VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
+ VG_USERREQ__FREELIKE_BLOCK = 0x1302,
+ /* Memory pool support. */
+ VG_USERREQ__CREATE_MEMPOOL = 0x1303,
+ VG_USERREQ__DESTROY_MEMPOOL = 0x1304,
+ VG_USERREQ__MEMPOOL_ALLOC = 0x1305,
+ VG_USERREQ__MEMPOOL_FREE = 0x1306,
+ VG_USERREQ__MEMPOOL_TRIM = 0x1307,
+ VG_USERREQ__MOVE_MEMPOOL = 0x1308,
+ VG_USERREQ__MEMPOOL_CHANGE = 0x1309,
+ VG_USERREQ__MEMPOOL_EXISTS = 0x130a,
+
+ /* Allow printfs to valgrind log. */
+ /* The first two pass the va_list argument by value, which
+ assumes it is the same size as or smaller than a UWord,
+ which generally isn't the case. Hence are deprecated.
+ The second two pass the vargs by reference and so are
+ immune to this problem. */
+ /* both :: char* fmt, va_list vargs (DEPRECATED) */
+ VG_USERREQ__PRINTF = 0x1401,
+ VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
+ /* both :: char* fmt, va_list* vargs */
+ VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403,
+ VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404,
+
+ /* Stack support. */
+ VG_USERREQ__STACK_REGISTER = 0x1501,
+ VG_USERREQ__STACK_DEREGISTER = 0x1502,
+ VG_USERREQ__STACK_CHANGE = 0x1503,
+
+ /* Wine support */
+ VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601,
+
+ /* Querying of debug info. */
+ VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701
+ } Vg_ClientRequest;
+
+#if !defined(__GNUC__)
+# define __extension__ /* */
+#endif
+
+
+/*
+ * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind
+ * client request and whose value equals the client request result.
+ */
+
+#if defined(NVALGRIND)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ (_zzq_default)
+
+#else /*defined(NVALGRIND)*/
+
+#if defined(_MSC_VER)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ (vg_VALGRIND_DO_CLIENT_REQUEST_EXPR((uintptr_t)(_zzq_default), \
+ (_zzq_request), (uintptr_t)(_zzq_arg1), (uintptr_t)(_zzq_arg2), \
+ (uintptr_t)(_zzq_arg3), (uintptr_t)(_zzq_arg4), \
+ (uintptr_t)(_zzq_arg5)))
+
+static __inline unsigned
+vg_VALGRIND_DO_CLIENT_REQUEST_EXPR(uintptr_t _zzq_default,
+ unsigned _zzq_request, uintptr_t _zzq_arg1,
+ uintptr_t _zzq_arg2, uintptr_t _zzq_arg3,
+ uintptr_t _zzq_arg4, uintptr_t _zzq_arg5)
+{
+ unsigned _zzq_rlval;
+ VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request,
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5);
+ return _zzq_rlval;
+}
+
+#else /*defined(_MSC_VER)*/
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
+ _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ (__extension__({unsigned int _zzq_rlval; \
+ VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request, \
+ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+ _zzq_rlval; \
+ }))
+
+#endif /*defined(_MSC_VER)*/
+
+#endif /*defined(NVALGRIND)*/
+
+
+/* Returns the number of Valgrinds this code is running under. That
+ is, 0 if running natively, 1 if running under Valgrind, 2 if
+ running under Valgrind which is running under another Valgrind,
+ etc. */
+#define RUNNING_ON_VALGRIND \
+ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \
+ VG_USERREQ__RUNNING_ON_VALGRIND, \
+ 0, 0, 0, 0, 0) \
+
+
+/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
+ _qzz_len - 1]. Useful if you are debugging a JITter or some such,
+ since it provides a way to make sure valgrind will retranslate the
+ invalidated area. Returns no value. */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DISCARD_TRANSLATIONS, \
+ _qzz_addr, _qzz_len, 0, 0, 0); \
+ }
+
+
+/* These requests are for getting Valgrind itself to print something.
+ Possibly with a backtrace. This is a really ugly hack. The return value
+ is the number of characters printed, excluding the "**<pid>** " part at the
+ start and the backtrace (if present). */
+
+#if defined(NVALGRIND)
+
+# define VALGRIND_PRINTF(...)
+# define VALGRIND_PRINTF_BACKTRACE(...)
+
+#else /* NVALGRIND */
+
+#if !defined(_MSC_VER)
+/* Modern GCC will optimize the static routine out if unused,
+ and unused attribute will shut down warnings about it. */
+static int VALGRIND_PRINTF(const char *format, ...)
+ __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF(const char *format, ...)
+{
+ unsigned long _qzz_res;
+ va_list vargs;
+ va_start(vargs, format);
+#if defined(_MSC_VER)
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+ VG_USERREQ__PRINTF_VALIST_BY_REF,
+ (uintptr_t)format,
+ (uintptr_t)&vargs,
+ 0, 0, 0);
+#else
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+ VG_USERREQ__PRINTF_VALIST_BY_REF,
+ (unsigned long)format,
+ (unsigned long)&vargs,
+ 0, 0, 0);
+#endif
+ va_end(vargs);
+ return (int)_qzz_res;
+}
+
+#if !defined(_MSC_VER)
+static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+ __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+{
+ unsigned long _qzz_res;
+ va_list vargs;
+ va_start(vargs, format);
+#if defined(_MSC_VER)
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+ VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+ (uintptr_t)format,
+ (uintptr_t)&vargs,
+ 0, 0, 0);
+#else
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+ VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+ (unsigned long)format,
+ (unsigned long)&vargs,
+ 0, 0, 0);
+#endif
+ va_end(vargs);
+ return (int)_qzz_res;
+}
+
+#endif /* NVALGRIND */
+
+
+/* These requests allow control to move from the simulated CPU to the
+ real CPU, calling an arbitary function.
+
+ Note that the current ThreadId is inserted as the first argument.
+ So this call:
+
+ VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
+
+ requires f to have this signature:
+
+ Word f(Word tid, Word arg1, Word arg2)
+
+ where "Word" is a word-sized type.
+
+ Note that these client requests are not entirely reliable. For example,
+ if you call a function with them that subsequently calls printf(),
+ there's a high chance Valgrind will crash. Generally, your prospects of
+ these working are made higher if the called function does not refer to
+ any global variables, and does not refer to any libc or other functions
+ (printf et al). Any kind of entanglement with libc or dynamic linking is
+ likely to have a bad outcome, for tricky reasons which we've grappled
+ with a lot in the past.
+*/
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL0, \
+ _qyy_fn, \
+ 0, 0, 0, 0); \
+ _qyy_res; \
+ })
+
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL1, \
+ _qyy_fn, \
+ _qyy_arg1, 0, 0, 0); \
+ _qyy_res; \
+ })
+
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL2, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, 0, 0); \
+ _qyy_res; \
+ })
+
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
+ __extension__ \
+ ({unsigned long _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__CLIENT_CALL3, \
+ _qyy_fn, \
+ _qyy_arg1, _qyy_arg2, \
+ _qyy_arg3, 0); \
+ _qyy_res; \
+ })
+
+
+/* Counts the number of errors that have been recorded by a tool. Nb:
+ the tool must record the errors with VG_(maybe_record_error)() or
+ VG_(unique_error)() for them to be counted. */
+#define VALGRIND_COUNT_ERRORS \
+ __extension__ \
+ ({unsigned int _qyy_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
+ VG_USERREQ__COUNT_ERRORS, \
+ 0, 0, 0, 0, 0); \
+ _qyy_res; \
+ })
+
+/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing
+ when heap blocks are allocated in order to give accurate results. This
+ happens automatically for the standard allocator functions such as
+ malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete,
+ delete[], etc.
+
+ But if your program uses a custom allocator, this doesn't automatically
+ happen, and Valgrind will not do as well. For example, if you allocate
+ superblocks with mmap() and then allocates chunks of the superblocks, all
+ Valgrind's observations will be at the mmap() level and it won't know that
+ the chunks should be considered separate entities. In Memcheck's case,
+ that means you probably won't get heap block overrun detection (because
+ there won't be redzones marked as unaddressable) and you definitely won't
+ get any leak detection.
+
+ The following client requests allow a custom allocator to be annotated so
+ that it can be handled accurately by Valgrind.
+
+ VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated
+ by a malloc()-like function. For Memcheck (an illustrative case), this
+ does two things:
+
+ - It records that the block has been allocated. This means any addresses
+ within the block mentioned in error messages will be
+ identified as belonging to the block. It also means that if the block
+ isn't freed it will be detected by the leak checker.
+
+ - It marks the block as being addressable and undefined (if 'is_zeroed' is
+ not set), or addressable and defined (if 'is_zeroed' is set). This
+ controls how accesses to the block by the program are handled.
+
+ 'addr' is the start of the usable block (ie. after any
+ redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocator
+ can apply redzones -- these are blocks of padding at the start and end of
+ each block. Adding redzones is recommended as it makes it much more likely
+ Valgrind will spot block overruns. `is_zeroed' indicates if the memory is
+ zeroed (or filled with another predictable value), as is the case for
+ calloc().
+
+ VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a
+ heap block -- that will be used by the client program -- is allocated.
+ It's best to put it at the outermost level of the allocator if possible;
+ for example, if you have a function my_alloc() which calls
+ internal_alloc(), and the client request is put inside internal_alloc(),
+ stack traces relating to the heap block will contain entries for both
+ my_alloc() and internal_alloc(), which is probably not what you want.
+
+ For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out
+ custom blocks from within a heap block, B, that has been allocated with
+ malloc/calloc/new/etc, then block B will be *ignored* during leak-checking
+ -- the custom blocks will take precedence.
+
+ VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. For
+ Memcheck, it does two things:
+
+ - It records that the block has been deallocated. This assumes that the
+ block was annotated as having been allocated via
+ VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued.
+
+ - It marks the block as being unaddressable.
+
+ VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a
+ heap block is deallocated.
+
+ In many cases, these two client requests will not be enough to get your
+ allocator working well with Memcheck. More specifically, if your allocator
+ writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call
+ will be necessary to mark the memory as addressable just before the zeroing
+ occurs, otherwise you'll get a lot of invalid write errors. For example,
+ you'll need to do this if your allocator recycles freed blocks, but it
+ zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK).
+ Alternatively, if your allocator reuses freed blocks for allocator-internal
+ data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary.
+
+ Really, what's happening is a blurring of the lines between the client
+ program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the
+ memory should be considered unaddressable to the client program, but the
+ allocator knows more than the rest of the client program and so may be able
+ to safely access it. Extra client requests are necessary for Valgrind to
+ understand the distinction between the allocator and the rest of the
+ program.
+
+ Note: there is currently no VALGRIND_REALLOCLIKE_BLOCK client request; it
+ has to be emulated with MALLOCLIKE/FREELIKE and memory copying.
+
+ Ignored if addr == 0.
+*/
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MALLOCLIKE_BLOCK, \
+ addr, sizeB, rzB, is_zeroed, 0); \
+ }
+
+/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
+ Ignored if addr == 0.
+*/
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__FREELIKE_BLOCK, \
+ addr, rzB, 0, 0, 0); \
+ }
+
+/* Create a memory pool. */
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__CREATE_MEMPOOL, \
+ pool, rzB, is_zeroed, 0, 0); \
+ }
+
+/* Destroy a memory pool. */
+#define VALGRIND_DESTROY_MEMPOOL(pool) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__DESTROY_MEMPOOL, \
+ pool, 0, 0, 0, 0); \
+ }
+
+/* Associate a piece of memory with a memory pool. */
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_ALLOC, \
+ pool, addr, size, 0, 0); \
+ }
+
+/* Disassociate a piece of memory from a memory pool. */
+#define VALGRIND_MEMPOOL_FREE(pool, addr) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_FREE, \
+ pool, addr, 0, 0, 0); \
+ }
+
+/* Disassociate any pieces outside a particular range. */
+#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_TRIM, \
+ pool, addr, size, 0, 0); \
+ }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MOVE_MEMPOOL, \
+ poolA, poolB, 0, 0, 0); \
+ }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_CHANGE, \
+ pool, addrA, addrB, size, 0); \
+ }
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool) \
+ __extension__ \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MEMPOOL_EXISTS, \
+ pool, 0, 0, 0, 0); \
+ _qzz_res; \
+ })
+
+/* Mark a piece of memory as being a stack. Returns a stack id. */
+#define VALGRIND_STACK_REGISTER(start, end) \
+ __extension__ \
+ ({unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_REGISTER, \
+ start, end, 0, 0, 0); \
+ _qzz_res; \
+ })
+
+/* Unmark the piece of memory associated with a stack id as being a
+ stack. */
+#define VALGRIND_STACK_DEREGISTER(id) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_DEREGISTER, \
+ id, 0, 0, 0, 0); \
+ }
+
+/* Change the start and end address of the stack id. */
+#define VALGRIND_STACK_CHANGE(id, start, end) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__STACK_CHANGE, \
+ id, start, end, 0, 0); \
+ }
+
+/* Load PDB debug info for Wine PE image_map. */
+#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__LOAD_PDB_DEBUGINFO, \
+ fd, ptr, total_size, delta, 0); \
+ }
+
+/* Map a code address to a source file name and line number. buf64
+ must point to a 64-byte buffer in the caller's address space. The
+ result will be dumped in there and is guaranteed to be zero
+ terminated. If no info is found, the first byte is set to zero. */
+#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \
+ {unsigned int _qzz_res; \
+ VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
+ VG_USERREQ__MAP_IP_TO_SRCLOC, \
+ addr, buf64, 0, 0, 0); \
+ }
+
+
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+#undef PLAT_ppc32_aix5
+#undef PLAT_ppc64_aix5
+
+#endif /* __VALGRIND_H */
diff --git a/security/sandbox/chromium/base/thread_annotations.h b/security/sandbox/chromium/base/thread_annotations.h
new file mode 100644
index 0000000000..fdd32f8490
--- /dev/null
+++ b/security/sandbox/chromium/base/thread_annotations.h
@@ -0,0 +1,264 @@
+// Copyright (c) 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This header file contains macro definitions for thread safety annotations
+// that allow developers to document the locking policies of multi-threaded
+// code. The annotations can also help program analysis tools to identify
+// potential thread safety issues.
+//
+// Note that the annotations we use are described as deprecated in the Clang
+// documentation, linked below. E.g. we use EXCLUSIVE_LOCKS_REQUIRED where the
+// Clang docs use REQUIRES.
+//
+// http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
+//
+// We use the deprecated Clang annotations to match Abseil (relevant header
+// linked below) and its ecosystem of libraries. We will follow Abseil with
+// respect to upgrading to more modern annotations.
+//
+// https://github.com/abseil/abseil-cpp/blob/master/absl/base/thread_annotations.h
+//
+// These annotations are implemented using compiler attributes. Using the macros
+// defined here instead of raw attributes allow for portability and future
+// compatibility.
+//
+// When referring to mutexes in the arguments of the attributes, you should
+// use variable names or more complex expressions (e.g. my_object->mutex_)
+// that evaluate to a concrete mutex object whenever possible. If the mutex
+// you want to refer to is not in scope, you may use a member pointer
+// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
+
+#ifndef BASE_THREAD_ANNOTATIONS_H_
+#define BASE_THREAD_ANNOTATIONS_H_
+
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(__clang__)
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+// GUARDED_BY()
+//
+// Documents if a shared field or global variable needs to be protected by a
+// mutex. GUARDED_BY() allows the user to specify a particular mutex that
+// should be held when accessing the annotated variable.
+//
+// Example:
+//
+// Mutex mu;
+// int p1 GUARDED_BY(mu);
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+// PT_GUARDED_BY()
+//
+// Documents if the memory location pointed to by a pointer should be guarded
+// by a mutex when dereferencing the pointer.
+//
+// Example:
+// Mutex mu;
+// int *p1 PT_GUARDED_BY(mu);
+//
+// Note that a pointer variable to a shared memory location could itself be a
+// shared variable.
+//
+// Example:
+//
+// // `q`, guarded by `mu1`, points to a shared memory location that is
+// // guarded by `mu2`:
+// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+// ACQUIRED_AFTER() / ACQUIRED_BEFORE()
+//
+// Documents the acquisition order between locks that can be held
+// simultaneously by a thread. For any two locks that need to be annotated
+// to establish an acquisition order, only one of them needs the annotation.
+// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
+// and ACQUIRED_BEFORE.)
+//
+// Example:
+//
+// Mutex m1;
+// Mutex m2 ACQUIRED_AFTER(m1);
+#define ACQUIRED_AFTER(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define ACQUIRED_BEFORE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+// EXCLUSIVE_LOCKS_REQUIRED() / SHARED_LOCKS_REQUIRED()
+//
+// Documents a function that expects a mutex to be held prior to entry.
+// The mutex is expected to be held both on entry to, and exit from, the
+// function.
+//
+// Example:
+//
+// Mutex mu1, mu2;
+// int a GUARDED_BY(mu1);
+// int b GUARDED_BY(mu2);
+//
+// void foo() EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... };
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+
+#define SHARED_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+// LOCKS_EXCLUDED()
+//
+// Documents the locks acquired in the body of the function. These locks
+// cannot be held when calling this function (as Abseil's `Mutex` locks are
+// non-reentrant).
+#define LOCKS_EXCLUDED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+// LOCK_RETURNED()
+//
+// Documents a function that returns a mutex without acquiring it. For example,
+// a public getter method that returns a pointer to a private mutex should
+// be annotated with LOCK_RETURNED.
+#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+// LOCKABLE
+//
+// Documents if a class/type is a lockable type (such as the `Mutex` class).
+#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+// SCOPED_LOCKABLE
+//
+// Documents if a class does RAII locking (such as the `MutexLock` class).
+// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
+// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
+// arguments; the analysis will assume that the destructor unlocks whatever the
+// constructor locked.
+#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+// EXCLUSIVE_LOCK_FUNCTION()
+//
+// Documents functions that acquire a lock in the body of a function, and do
+// not release it.
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+// SHARED_LOCK_FUNCTION()
+//
+// Documents functions that acquire a shared (reader) lock in the body of a
+// function, and do not release it.
+#define SHARED_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+// UNLOCK_FUNCTION()
+//
+// Documents functions that expect a lock to be held on entry to the function,
+// and release it in the body of the function.
+#define UNLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+// EXCLUSIVE_TRYLOCK_FUNCTION() / SHARED_TRYLOCK_FUNCTION()
+//
+// Documents functions that try to acquire a lock, and return success or failure
+// (or a non-boolean value that can be interpreted as a boolean).
+// The first argument should be `true` for functions that return `true` on
+// success, or `false` for functions that return `false` on success. The second
+// argument specifies the mutex that is locked on success. If unspecified, this
+// mutex is assumed to be `this`.
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+#define SHARED_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+// ASSERT_EXCLUSIVE_LOCK() / ASSERT_SHARED_LOCK()
+//
+// Documents functions that dynamically check to see if a lock is held, and fail
+// if it is not held.
+#define ASSERT_EXCLUSIVE_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+
+#define ASSERT_SHARED_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+
+// NO_THREAD_SAFETY_ANALYSIS
+//
+// Turns off thread safety checking within the body of a particular function.
+// This annotation is used to mark functions that are known to be correct, but
+// the locking behavior is more complicated than the analyzer can handle.
+#define NO_THREAD_SAFETY_ANALYSIS \
+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+//------------------------------------------------------------------------------
+// Tool-Supplied Annotations
+//------------------------------------------------------------------------------
+
+// TS_UNCHECKED should be placed around lock expressions that are not valid
+// C++ syntax, but which are present for documentation purposes. These
+// annotations will be ignored by the analysis.
+#define TS_UNCHECKED(x) ""
+
+// TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
+// It is used by automated tools to mark and disable invalid expressions.
+// The annotation should either be fixed, or changed to TS_UNCHECKED.
+#define TS_FIXME(x) ""
+
+// Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
+// a particular function. However, this attribute is used to mark functions
+// that are incorrect and need to be fixed. It is used by automated tools to
+// avoid breaking the build when the analysis is updated.
+// Code owners are expected to eventually fix the routine.
+#define NO_THREAD_SAFETY_ANALYSIS_FIXME NO_THREAD_SAFETY_ANALYSIS
+
+// Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
+// annotation that needs to be fixed, because it is producing thread safety
+// warning. It disables the GUARDED_BY.
+#define GUARDED_BY_FIXME(x)
+
+// Disables warnings for a single read operation. This can be used to avoid
+// warnings when it is known that the read is not actually involved in a race,
+// but the compiler cannot confirm that.
+#define TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
+
+namespace thread_safety_analysis {
+
+// Takes a reference to a guarded data member, and returns an unguarded
+// reference.
+template <typename T>
+inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
+ return v;
+}
+
+template <typename T>
+inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
+ return v;
+}
+
+} // namespace thread_safety_analysis
+
+// The above is imported as-is from abseil-cpp. The following Chromium-specific
+// synonyms are added for Chromium concepts (SequenceChecker/ThreadChecker).
+#if DCHECK_IS_ON()
+
+// Equivalent to GUARDED_BY for SequenceChecker/ThreadChecker. Currently,
+// clang's error message "requires holding mutex" is misleading. Usage of this
+// macro is discouraged until the message is updated.
+// TODO(etiennep): Update comment above once clang's error message is updated.
+#define GUARDED_BY_CONTEXT(name) GUARDED_BY(name)
+
+// Equivalent to EXCLUSIVE_LOCKS_REQUIRED for SequenceChecker/ThreadChecker.
+// Currently, clang's error message "requires holding mutex" is misleading.
+// Usage of this macro is discouraged until the message is updated.
+// TODO(etiennep): Update comment above once clang's error message is updated.
+#define VALID_CONTEXT_REQUIRED(name) EXCLUSIVE_LOCKS_REQUIRED(name)
+
+#else // DCHECK_IS_ON()
+
+#define GUARDED_BY_CONTEXT(name)
+#define VALID_CONTEXT_REQUIRED(name)
+
+#endif // DCHECK_IS_ON()
+
+#endif // BASE_THREAD_ANNOTATIONS_H_
diff --git a/security/sandbox/chromium/base/threading/platform_thread.cc b/security/sandbox/chromium/base/threading/platform_thread.cc
new file mode 100644
index 0000000000..ae0a4499e7
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/platform_thread.cc
@@ -0,0 +1,51 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include <atomic>
+#include <memory>
+
+#include "base/feature_list.h"
+
+namespace base {
+
+namespace {
+
+// Whether thread priorities should be used. When disabled,
+// PlatformThread::SetCurrentThreadPriority() no-ops.
+const Feature kThreadPrioritiesFeature{"ThreadPriorities",
+ FEATURE_ENABLED_BY_DEFAULT};
+
+// Whether thread priorities should be used.
+//
+// PlatformThread::SetCurrentThreadPriority() doesn't query the state of the
+// feature directly because FeatureList initialization is not always
+// synchronized with PlatformThread::SetCurrentThreadPriority().
+std::atomic<bool> g_use_thread_priorities(true);
+
+} // namespace
+
+// static
+void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
+ if (g_use_thread_priorities.load())
+ SetCurrentThreadPriorityImpl(priority);
+}
+
+namespace internal {
+
+void InitializeThreadPrioritiesFeature() {
+ // A DCHECK is triggered on FeatureList initialization if the state of a
+ // feature has been checked before. To avoid triggering this DCHECK in unit
+ // tests that call this before initializing the FeatureList, only check the
+ // state of the feature if the FeatureList is initialized.
+ if (FeatureList::GetInstance() &&
+ !FeatureList::IsEnabled(kThreadPrioritiesFeature)) {
+ g_use_thread_priorities.store(false);
+ }
+}
+
+} // namespace internal
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/platform_thread.h b/security/sandbox/chromium/base/threading/platform_thread.h
new file mode 100644
index 0000000000..aa5b9526c1
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/platform_thread.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: You should *NOT* be using this class directly. PlatformThread is
+// the low-level platform-specific abstraction to the OS's threading interface.
+// You should instead be using a message-loop driven Thread, see thread.h.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_H_
+#define BASE_THREADING_PLATFORM_THREAD_H_
+
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_types.h"
+#elif defined(OS_FUCHSIA)
+#include <zircon/types.h>
+#elif defined(OS_MACOSX)
+#include <mach/mach_types.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+// Used for logging. Always an integer value.
+#if defined(OS_WIN)
+typedef DWORD PlatformThreadId;
+#elif defined(OS_FUCHSIA)
+typedef zx_handle_t PlatformThreadId;
+#elif defined(OS_MACOSX)
+typedef mach_port_t PlatformThreadId;
+#elif defined(OS_POSIX)
+typedef pid_t PlatformThreadId;
+#endif
+
+// Used for thread checking and debugging.
+// Meant to be as fast as possible.
+// These are produced by PlatformThread::CurrentRef(), and used to later
+// check if we are on the same thread or not by using ==. These are safe
+// to copy between threads, but can't be copied to another process as they
+// have no meaning there. Also, the internal identifier can be re-used
+// after a thread dies, so a PlatformThreadRef cannot be reliably used
+// to distinguish a new thread from an old, dead thread.
+class PlatformThreadRef {
+ public:
+#if defined(OS_WIN)
+ typedef DWORD RefType;
+#else // OS_POSIX
+ typedef pthread_t RefType;
+#endif
+ constexpr PlatformThreadRef() : id_(0) {}
+
+ explicit constexpr PlatformThreadRef(RefType id) : id_(id) {}
+
+ bool operator==(PlatformThreadRef other) const {
+ return id_ == other.id_;
+ }
+
+ bool operator!=(PlatformThreadRef other) const { return id_ != other.id_; }
+
+ bool is_null() const {
+ return id_ == 0;
+ }
+ private:
+ RefType id_;
+};
+
+// Used to operate on threads.
+class PlatformThreadHandle {
+ public:
+#if defined(OS_WIN)
+ typedef void* Handle;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ typedef pthread_t Handle;
+#endif
+
+ constexpr PlatformThreadHandle() : handle_(0) {}
+
+ explicit constexpr PlatformThreadHandle(Handle handle) : handle_(handle) {}
+
+ bool is_equal(const PlatformThreadHandle& other) const {
+ return handle_ == other.handle_;
+ }
+
+ bool is_null() const {
+ return !handle_;
+ }
+
+ Handle platform_handle() const {
+ return handle_;
+ }
+
+ private:
+ Handle handle_;
+};
+
+const PlatformThreadId kInvalidThreadId(0);
+
+// Valid values for priority of Thread::Options and SimpleThread::Options, and
+// SetCurrentThreadPriority(), listed in increasing order of importance.
+enum class ThreadPriority : int {
+ // Suitable for threads that shouldn't disrupt high priority work.
+ BACKGROUND,
+ // Default priority level.
+ NORMAL,
+ // Suitable for threads which generate data for the display (at ~60Hz).
+ DISPLAY,
+ // Suitable for low-latency, glitch-resistant audio.
+ REALTIME_AUDIO,
+};
+
+// A namespace for low-level thread functions.
+class BASE_EXPORT PlatformThread {
+ public:
+ // Implement this interface to run code on a background thread. Your
+ // ThreadMain method will be called on the newly created thread.
+ class BASE_EXPORT Delegate {
+ public:
+ virtual void ThreadMain() = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ // Gets the current thread id, which may be useful for logging purposes.
+ static PlatformThreadId CurrentId();
+
+ // Gets the current thread reference, which can be used to check if
+ // we're on the right thread quickly.
+ static PlatformThreadRef CurrentRef();
+
+ // Get the handle representing the current thread. On Windows, this is a
+ // pseudo handle constant which will always represent the thread using it and
+ // hence should not be shared with other threads nor be used to differentiate
+ // the current thread from another.
+ static PlatformThreadHandle CurrentHandle();
+
+ // Yield the current thread so another thread can be scheduled.
+ static void YieldCurrentThread();
+
+ // Sleeps for the specified duration (real-time; ignores time overrides).
+ // Note: The sleep duration may be in base::Time or base::TimeTicks, depending
+ // on platform. If you're looking to use this in unit tests testing delayed
+ // tasks, this will be unreliable - instead, use
+ // base::test::TaskEnvironment with MOCK_TIME mode.
+ static void Sleep(base::TimeDelta duration);
+
+ // Sets the thread name visible to debuggers/tools. This will try to
+ // initialize the context for current thread unless it's a WorkerThread.
+ static void SetName(const std::string& name);
+
+ // Gets the thread name, if previously set by SetName.
+ static const char* GetName();
+
+ // Creates a new thread. The |stack_size| parameter can be 0 to indicate
+ // that the default stack size should be used. Upon success,
+ // |*thread_handle| will be assigned a handle to the newly created thread,
+ // and |delegate|'s ThreadMain method will be executed on the newly created
+ // thread.
+ // NOTE: When you are done with the thread handle, you must call Join to
+ // release system resources associated with the thread. You must ensure that
+ // the Delegate object outlives the thread.
+ static bool Create(size_t stack_size,
+ Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+ return CreateWithPriority(stack_size, delegate, thread_handle,
+ ThreadPriority::NORMAL);
+ }
+
+ // CreateWithPriority() does the same thing as Create() except the priority of
+ // the thread is set based on |priority|.
+ static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle,
+ ThreadPriority priority);
+
+ // CreateNonJoinable() does the same thing as Create() except the thread
+ // cannot be Join()'d. Therefore, it also does not output a
+ // PlatformThreadHandle.
+ static bool CreateNonJoinable(size_t stack_size, Delegate* delegate);
+
+ // CreateNonJoinableWithPriority() does the same thing as CreateNonJoinable()
+ // except the priority of the thread is set based on |priority|.
+ static bool CreateNonJoinableWithPriority(size_t stack_size,
+ Delegate* delegate,
+ ThreadPriority priority);
+
+ // Joins with a thread created via the Create function. This function blocks
+ // the caller until the designated thread exits. This will invalidate
+ // |thread_handle|.
+ static void Join(PlatformThreadHandle thread_handle);
+
+ // Detaches and releases the thread handle. The thread is no longer joinable
+ // and |thread_handle| is invalidated after this call.
+ static void Detach(PlatformThreadHandle thread_handle);
+
+ // Returns true if SetCurrentThreadPriority() should be able to increase the
+ // priority of a thread to |priority|.
+ static bool CanIncreaseThreadPriority(ThreadPriority priority);
+
+ // Toggles the current thread's priority at runtime.
+ //
+ // A thread may not be able to raise its priority back up after lowering it if
+ // the process does not have a proper permission, e.g. CAP_SYS_NICE on Linux.
+ // A thread may not be able to lower its priority back down after raising it
+ // to REALTIME_AUDIO.
+ //
+ // This function must not be called from the main thread on Mac. This is to
+ // avoid performance regressions (https://crbug.com/601270).
+ //
+ // Since changing other threads' priority is not permitted in favor of
+ // security, this interface is restricted to change only the current thread
+ // priority (https://crbug.com/399473).
+ static void SetCurrentThreadPriority(ThreadPriority priority);
+
+ static ThreadPriority GetCurrentThreadPriority();
+
+#if defined(OS_LINUX)
+ // Toggles a specific thread's priority at runtime. This can be used to
+ // change the priority of a thread in a different process and will fail
+ // if the calling process does not have proper permissions. The
+ // SetCurrentThreadPriority() function above is preferred in favor of
+ // security but on platforms where sandboxed processes are not allowed to
+ // change priority this function exists to allow a non-sandboxed process
+ // to change the priority of sandboxed threads for improved performance.
+ // Warning: Don't use this for a main thread because that will change the
+ // whole thread group's (i.e. process) priority.
+ static void SetThreadPriority(PlatformThreadId thread_id,
+ ThreadPriority priority);
+#endif
+
+ // Returns the default thread stack size set by chrome. If we do not
+ // explicitly set default size then returns 0.
+ static size_t GetDefaultThreadStackSize();
+
+ private:
+ static void SetCurrentThreadPriorityImpl(ThreadPriority priority);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+namespace internal {
+
+// Initializes the "ThreadPriorities" feature. The feature state is only taken
+// into account after this initialization. This initialization must be
+// synchronized with calls to PlatformThread::SetCurrentThreadPriority().
+void InitializeThreadPrioritiesFeature();
+
+} // namespace internal
+
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/security/sandbox/chromium/base/threading/platform_thread_internal_posix.cc b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.cc
new file mode 100644
index 0000000000..378a24d0d1
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.cc
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread_internal_posix.h"
+
+#include "base/containers/adapters.h"
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+int ThreadPriorityToNiceValue(ThreadPriority priority) {
+ for (const auto& pair : kThreadPriorityToNiceValueMap) {
+ if (pair.priority == priority)
+ return pair.nice_value;
+ }
+ NOTREACHED() << "Unknown ThreadPriority";
+ return 0;
+}
+
+ThreadPriority NiceValueToThreadPriority(int nice_value) {
+ // Try to find a priority that best describes |nice_value|. If there isn't
+ // an exact match, this method returns the closest priority whose nice value
+ // is higher (lower priority) than |nice_value|.
+ for (const auto& pair : Reversed(kThreadPriorityToNiceValueMap)) {
+ if (pair.nice_value >= nice_value)
+ return pair.priority;
+ }
+
+ // Reaching here means |nice_value| is more than any of the defined
+ // priorities. The lowest priority is suitable in this case.
+ return ThreadPriority::BACKGROUND;
+}
+
+} // namespace internal
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/platform_thread_internal_posix.h b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.h
new file mode 100644
index 0000000000..d248fa9bfd
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/platform_thread_internal_posix.h
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+#define BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+
+#include "base/base_export.h"
+#include "base/optional.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace internal {
+
+struct ThreadPriorityToNiceValuePair {
+ ThreadPriority priority;
+ int nice_value;
+};
+// The elements must be listed in the order of increasing priority (lowest
+// priority first), that is, in the order of decreasing nice values (highest
+// nice value first).
+BASE_EXPORT extern
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4];
+
+// Returns the nice value matching |priority| based on the platform-specific
+// implementation of kThreadPriorityToNiceValueMap.
+int ThreadPriorityToNiceValue(ThreadPriority priority);
+
+// Returns the ThreadPrioirty matching |nice_value| based on the platform-
+// specific implementation of kThreadPriorityToNiceValueMap.
+BASE_EXPORT ThreadPriority NiceValueToThreadPriority(int nice_value);
+
+// If non-nullopt, this return value will be used as the platform-specific
+// result of CanIncreaseThreadPriority().
+Optional<bool> CanIncreaseCurrentThreadPriorityForPlatform(
+ ThreadPriority priority);
+
+// Allows platform specific tweaks to the generic POSIX solution for
+// SetCurrentThreadPriority(). Returns true if the platform-specific
+// implementation handled this |priority| change, false if the generic
+// implementation should instead proceed.
+bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority);
+
+// If non-null, this return value will be used as the platform-specific result
+// of CanIncreaseThreadPriority().
+Optional<ThreadPriority> GetCurrentThreadPriorityForPlatform();
+
+#if defined(OS_LINUX)
+// Current thread id is cached in thread local storage for performance reasons.
+// In some rare cases it's important to clear that cache explicitly (e.g. after
+// going through clone() syscall which does not call pthread_atfork()
+// handlers).
+BASE_EXPORT void ClearTidCache();
+#endif // defined(OS_LINUX)
+
+} // namespace internal
+
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
diff --git a/security/sandbox/chromium/base/threading/platform_thread_posix.cc b/security/sandbox/chromium/base/threading/platform_thread_posix.cc
new file mode 100644
index 0000000000..335848e329
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/platform_thread_posix.cc
@@ -0,0 +1,361 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include "base/debug/activity_tracker.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/threading/platform_thread_internal_posix.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "build/build_config.h"
+
+#if !defined(OS_MACOSX) && !defined(OS_FUCHSIA) && !defined(OS_NACL)
+#include "base/posix/can_lower_nice_to.h"
+#endif
+
+#if defined(OS_LINUX)
+#include <sys/syscall.h>
+#endif
+
+#if defined(OS_FUCHSIA)
+#include <zircon/process.h>
+#else
+#include <sys/resource.h>
+#endif
+
+namespace base {
+
+void InitThreading();
+void TerminateOnThread();
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
+
+namespace {
+
+struct ThreadParams {
+ ThreadParams()
+ : delegate(nullptr), joinable(false), priority(ThreadPriority::NORMAL) {}
+
+ PlatformThread::Delegate* delegate;
+ bool joinable;
+ ThreadPriority priority;
+};
+
+void* ThreadFunc(void* params) {
+ PlatformThread::Delegate* delegate = nullptr;
+
+ {
+ std::unique_ptr<ThreadParams> thread_params(
+ static_cast<ThreadParams*>(params));
+
+ delegate = thread_params->delegate;
+ if (!thread_params->joinable)
+ base::ThreadRestrictions::SetSingletonAllowed(false);
+
+#if !defined(OS_NACL)
+ // Threads on linux/android may inherit their priority from the thread
+ // where they were created. This explicitly sets the priority of all new
+ // threads.
+ PlatformThread::SetCurrentThreadPriority(thread_params->priority);
+#endif
+ }
+
+ ThreadIdNameManager::GetInstance()->RegisterThread(
+ PlatformThread::CurrentHandle().platform_handle(),
+ PlatformThread::CurrentId());
+
+ delegate->ThreadMain();
+
+ ThreadIdNameManager::GetInstance()->RemoveName(
+ PlatformThread::CurrentHandle().platform_handle(),
+ PlatformThread::CurrentId());
+
+ base::TerminateOnThread();
+ return nullptr;
+}
+
+bool CreateThread(size_t stack_size,
+ bool joinable,
+ PlatformThread::Delegate* delegate,
+ PlatformThreadHandle* thread_handle,
+ ThreadPriority priority) {
+ DCHECK(thread_handle);
+ base::InitThreading();
+
+ pthread_attr_t attributes;
+ pthread_attr_init(&attributes);
+
+ // Pthreads are joinable by default, so only specify the detached
+ // attribute if the thread should be non-joinable.
+ if (!joinable)
+ pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
+
+ // Get a better default if available.
+ if (stack_size == 0)
+ stack_size = base::GetDefaultThreadStackSize(attributes);
+
+ if (stack_size > 0)
+ pthread_attr_setstacksize(&attributes, stack_size);
+
+ std::unique_ptr<ThreadParams> params(new ThreadParams);
+ params->delegate = delegate;
+ params->joinable = joinable;
+ params->priority = priority;
+
+ pthread_t handle;
+ int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
+ bool success = !err;
+ if (success) {
+ // ThreadParams should be deleted on the created thread after used.
+ ignore_result(params.release());
+ } else {
+ // Value of |handle| is undefined if pthread_create fails.
+ handle = 0;
+ errno = err;
+ PLOG(ERROR) << "pthread_create";
+ }
+ *thread_handle = PlatformThreadHandle(handle);
+
+ pthread_attr_destroy(&attributes);
+
+ return success;
+}
+
+#if defined(OS_LINUX)
+
+// Store the thread ids in local storage since calling the SWI can
+// expensive and PlatformThread::CurrentId is used liberally. Clear
+// the stored value after a fork() because forking changes the thread
+// id. Forking without going through fork() (e.g. clone()) is not
+// supported, but there is no known usage. Using thread_local is
+// fine here (despite being banned) since it is going to be allowed
+// but is blocked on a clang bug for Mac (https://crbug.com/829078)
+// and we can't use ThreadLocalStorage because of re-entrancy due to
+// CHECK/DCHECKs.
+thread_local pid_t g_thread_id = -1;
+
+class InitAtFork {
+ public:
+ InitAtFork() { pthread_atfork(nullptr, nullptr, internal::ClearTidCache); }
+};
+
+#endif // defined(OS_LINUX)
+
+} // namespace
+
+#if defined(OS_LINUX)
+
+namespace internal {
+
+void ClearTidCache() {
+ g_thread_id = -1;
+}
+
+} // namespace internal
+
+#endif // defined(OS_LINUX)
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+ // Pthreads doesn't have the concept of a thread ID, so we have to reach down
+ // into the kernel.
+#if defined(OS_MACOSX)
+ return pthread_mach_thread_np(pthread_self());
+#elif defined(OS_LINUX)
+ static NoDestructor<InitAtFork> init_at_fork;
+ if (g_thread_id == -1) {
+ g_thread_id = syscall(__NR_gettid);
+ } else {
+ DCHECK_EQ(g_thread_id, syscall(__NR_gettid))
+ << "Thread id stored in TLS is different from thread id returned by "
+ "the system. It is likely that the process was forked without going "
+ "through fork().";
+ }
+ return g_thread_id;
+#elif defined(OS_ANDROID)
+ return gettid();
+#elif defined(OS_FUCHSIA)
+ return zx_thread_self();
+#elif defined(OS_SOLARIS) || defined(OS_QNX)
+ return pthread_self();
+#elif defined(OS_NACL) && defined(__GLIBC__)
+ return pthread_self();
+#elif defined(OS_NACL) && !defined(__GLIBC__)
+ // Pointers are 32-bits in NaCl.
+ return reinterpret_cast<int32_t>(pthread_self());
+#elif defined(OS_POSIX) && defined(OS_AIX)
+ return pthread_self();
+#elif defined(OS_POSIX) && !defined(OS_AIX)
+ return reinterpret_cast<int64_t>(pthread_self());
+#endif
+}
+
+// static
+PlatformThreadRef PlatformThread::CurrentRef() {
+ return PlatformThreadRef(pthread_self());
+}
+
+// static
+PlatformThreadHandle PlatformThread::CurrentHandle() {
+ return PlatformThreadHandle(pthread_self());
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+ sched_yield();
+}
+
+// static
+void PlatformThread::Sleep(TimeDelta duration) {
+ struct timespec sleep_time, remaining;
+
+ // Break the duration into seconds and nanoseconds.
+ // NOTE: TimeDelta's microseconds are int64s while timespec's
+ // nanoseconds are longs, so this unpacking must prevent overflow.
+ sleep_time.tv_sec = duration.InSeconds();
+ duration -= TimeDelta::FromSeconds(sleep_time.tv_sec);
+ sleep_time.tv_nsec = duration.InMicroseconds() * 1000; // nanoseconds
+
+ while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
+ sleep_time = remaining;
+}
+
+// static
+const char* PlatformThread::GetName() {
+ return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
+}
+
+// static
+bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle,
+ ThreadPriority priority) {
+ return CreateThread(stack_size, true /* joinable thread */, delegate,
+ thread_handle, priority);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+ return CreateNonJoinableWithPriority(stack_size, delegate,
+ ThreadPriority::NORMAL);
+}
+
+// static
+bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size,
+ Delegate* delegate,
+ ThreadPriority priority) {
+ PlatformThreadHandle unused;
+
+ bool result = CreateThread(stack_size, false /* non-joinable thread */,
+ delegate, &unused, priority);
+ return result;
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+ // Record the event that this thread is blocking upon (for hang diagnosis).
+ base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
+
+ // Joining another thread may block the current thread for a long time, since
+ // the thread referred to by |thread_handle| may still be running long-lived /
+ // blocking tasks.
+ base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
+ FROM_HERE, base::BlockingType::MAY_BLOCK);
+ CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), nullptr));
+}
+
+// static
+void PlatformThread::Detach(PlatformThreadHandle thread_handle) {
+ CHECK_EQ(0, pthread_detach(thread_handle.platform_handle()));
+}
+
+// Mac and Fuchsia have their own Set/GetCurrentThreadPriority()
+// implementations.
+#if !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
+
+// static
+bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
+#if defined(OS_NACL)
+ return false;
+#else
+ auto platform_specific_ability =
+ internal::CanIncreaseCurrentThreadPriorityForPlatform(priority);
+ if (platform_specific_ability)
+ return platform_specific_ability.value();
+
+ return internal::CanLowerNiceTo(
+ internal::ThreadPriorityToNiceValue(priority));
+#endif // defined(OS_NACL)
+}
+
+// static
+void PlatformThread::SetCurrentThreadPriorityImpl(ThreadPriority priority) {
+#if defined(OS_NACL)
+ NOTIMPLEMENTED();
+#else
+ if (internal::SetCurrentThreadPriorityForPlatform(priority))
+ return;
+
+ // setpriority(2) should change the whole thread group's (i.e. process)
+ // priority. However, as stated in the bugs section of
+ // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
+ // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
+ // attribute". Also, 0 is prefered to the current thread id since it is
+ // equivalent but makes sandboxing easier (https://crbug.com/399473).
+ const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
+ if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
+ DVPLOG(1) << "Failed to set nice value of thread ("
+ << PlatformThread::CurrentId() << ") to " << nice_setting;
+ }
+#endif // defined(OS_NACL)
+}
+
+// static
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
+#if defined(OS_NACL)
+ NOTIMPLEMENTED();
+ return ThreadPriority::NORMAL;
+#else
+ // Mirrors SetCurrentThreadPriority()'s implementation.
+ auto platform_specific_priority =
+ internal::GetCurrentThreadPriorityForPlatform();
+ if (platform_specific_priority)
+ return platform_specific_priority.value();
+
+ // Need to clear errno before calling getpriority():
+ // http://man7.org/linux/man-pages/man2/getpriority.2.html
+ errno = 0;
+ int nice_value = getpriority(PRIO_PROCESS, 0);
+ if (errno != 0) {
+ DVPLOG(1) << "Failed to get nice value of thread ("
+ << PlatformThread::CurrentId() << ")";
+ return ThreadPriority::NORMAL;
+ }
+
+ return internal::NiceValueToThreadPriority(nice_value);
+#endif // !defined(OS_NACL)
+}
+
+#endif // !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
+
+// static
+size_t PlatformThread::GetDefaultThreadStackSize() {
+ pthread_attr_t attributes;
+ pthread_attr_init(&attributes);
+ return base::GetDefaultThreadStackSize(attributes);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/platform_thread_win.cc b/security/sandbox/chromium/base/threading/platform_thread_win.cc
new file mode 100644
index 0000000000..0bcf6db247
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/platform_thread_win.cc
@@ -0,0 +1,463 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread_win.h"
+
+#include <stddef.h>
+
+#include "base/debug/activity_tracker.h"
+#include "base/debug/alias.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/profiler.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/process/memory.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time_override.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "build/build_config.h"
+
+#include <windows.h>
+
+namespace base {
+
+namespace {
+
+// The most common value returned by ::GetThreadPriority() after background
+// thread mode is enabled on Windows 7.
+constexpr int kWin7BackgroundThreadModePriority = 4;
+
+// Value sometimes returned by ::GetThreadPriority() after thread priority is
+// set to normal on Windows 7.
+constexpr int kWin7NormalPriority = 3;
+
+// These values are sometimes returned by ::GetThreadPriority().
+constexpr int kWinNormalPriority1 = 5;
+constexpr int kWinNormalPriority2 = 6;
+
+// The information on how to set the thread name comes from
+// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
+const DWORD kVCThreadNameException = 0x406D1388;
+
+typedef struct tagTHREADNAME_INFO {
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+
+// The SetThreadDescription API was brought in version 1607 of Windows 10.
+typedef HRESULT(WINAPI* SetThreadDescription)(HANDLE hThread,
+ PCWSTR lpThreadDescription);
+
+// This function has try handling, so it is separated out of its caller.
+void SetNameInternal(PlatformThreadId thread_id, const char* name) {
+ //This function is only used for debugging purposes, as you can find by its caller
+#ifndef __MINGW32__
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = thread_id;
+ info.dwFlags = 0;
+
+ __try {
+ RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
+ reinterpret_cast<DWORD_PTR*>(&info));
+ } __except(EXCEPTION_CONTINUE_EXECUTION) {
+ }
+#endif
+}
+
+struct ThreadParams {
+ PlatformThread::Delegate* delegate;
+ bool joinable;
+ ThreadPriority priority;
+};
+
+DWORD __stdcall ThreadFunc(void* params) {
+ ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+ PlatformThread::Delegate* delegate = thread_params->delegate;
+ if (!thread_params->joinable)
+ base::ThreadRestrictions::SetSingletonAllowed(false);
+
+ if (thread_params->priority != ThreadPriority::NORMAL)
+ PlatformThread::SetCurrentThreadPriority(thread_params->priority);
+
+ // Retrieve a copy of the thread handle to use as the key in the
+ // thread name mapping.
+ PlatformThreadHandle::Handle platform_handle;
+ BOOL did_dup = DuplicateHandle(GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ &platform_handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+
+ win::ScopedHandle scoped_platform_handle;
+
+ if (did_dup) {
+ scoped_platform_handle.Set(platform_handle);
+ ThreadIdNameManager::GetInstance()->RegisterThread(
+ scoped_platform_handle.Get(),
+ PlatformThread::CurrentId());
+ }
+
+ delete thread_params;
+ delegate->ThreadMain();
+
+ if (did_dup) {
+ ThreadIdNameManager::GetInstance()->RemoveName(
+ scoped_platform_handle.Get(),
+ PlatformThread::CurrentId());
+ }
+
+ return 0;
+}
+
+// CreateThreadInternal() matches PlatformThread::CreateWithPriority(), except
+// that |out_thread_handle| may be nullptr, in which case a non-joinable thread
+// is created.
+bool CreateThreadInternal(size_t stack_size,
+ PlatformThread::Delegate* delegate,
+ PlatformThreadHandle* out_thread_handle,
+ ThreadPriority priority) {
+ unsigned int flags = 0;
+ if (stack_size > 0) {
+ flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+#if defined(ARCH_CPU_32_BITS)
+ } else {
+ // The process stack size is increased to give spaces to |RendererMain| in
+ // |chrome/BUILD.gn|, but keep the default stack size of other threads to
+ // 1MB for the address space pressure.
+ flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+ stack_size = 1024 * 1024;
+#endif
+ }
+
+ ThreadParams* params = new ThreadParams;
+ params->delegate = delegate;
+ params->joinable = out_thread_handle != nullptr;
+ params->priority = priority;
+
+ // Using CreateThread here vs _beginthreadex makes thread creation a bit
+ // faster and doesn't require the loader lock to be available. Our code will
+ // have to work running on CreateThread() threads anyway, since we run code on
+ // the Windows thread pool, etc. For some background on the difference:
+ // http://www.microsoft.com/msj/1099/win32/win321099.aspx
+ void* thread_handle =
+ ::CreateThread(nullptr, stack_size, ThreadFunc, params, flags, nullptr);
+
+ if (!thread_handle) {
+ DWORD last_error = ::GetLastError();
+
+ switch (last_error) {
+ case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_OUTOFMEMORY:
+ case ERROR_COMMITMENT_LIMIT:
+ TerminateBecauseOutOfMemory(stack_size);
+ break;
+
+ default:
+ static auto* last_error_crash_key = debug::AllocateCrashKeyString(
+ "create_thread_last_error", debug::CrashKeySize::Size32);
+ debug::SetCrashKeyString(last_error_crash_key,
+ base::NumberToString(last_error));
+ break;
+ }
+
+ delete params;
+ return false;
+ }
+
+ if (out_thread_handle)
+ *out_thread_handle = PlatformThreadHandle(thread_handle);
+ else
+ CloseHandle(thread_handle);
+ return true;
+}
+
+} // namespace
+
+namespace internal {
+
+void AssertMemoryPriority(HANDLE thread, int memory_priority) {
+#if DCHECK_IS_ON()
+ static const auto get_thread_information_fn =
+ reinterpret_cast<decltype(&::GetThreadInformation)>(::GetProcAddress(
+ ::GetModuleHandle(L"Kernel32.dll"), "GetThreadInformation"));
+
+ if (!get_thread_information_fn) {
+ DCHECK_EQ(win::GetVersion(), win::Version::WIN7);
+ return;
+ }
+
+ MEMORY_PRIORITY_INFORMATION memory_priority_information = {};
+ DCHECK(get_thread_information_fn(thread, ::ThreadMemoryPriority,
+ &memory_priority_information,
+ sizeof(memory_priority_information)));
+
+ DCHECK_EQ(memory_priority,
+ static_cast<int>(memory_priority_information.MemoryPriority));
+#endif
+}
+
+} // namespace internal
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+ return ::GetCurrentThreadId();
+}
+
+// static
+PlatformThreadRef PlatformThread::CurrentRef() {
+ return PlatformThreadRef(::GetCurrentThreadId());
+}
+
+// static
+PlatformThreadHandle PlatformThread::CurrentHandle() {
+ return PlatformThreadHandle(::GetCurrentThread());
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+ ::Sleep(0);
+}
+
+// static
+void PlatformThread::Sleep(TimeDelta duration) {
+ // When measured with a high resolution clock, Sleep() sometimes returns much
+ // too early. We may need to call it repeatedly to get the desired duration.
+ // PlatformThread::Sleep doesn't support mock-time, so this always uses
+ // real-time.
+ const TimeTicks end = subtle::TimeTicksNowIgnoringOverride() + duration;
+ for (TimeTicks now = subtle::TimeTicksNowIgnoringOverride(); now < end;
+ now = subtle::TimeTicksNowIgnoringOverride()) {
+ ::Sleep(static_cast<DWORD>((end - now).InMillisecondsRoundedUp()));
+ }
+}
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+ ThreadIdNameManager::GetInstance()->SetName(name);
+
+ // The SetThreadDescription API works even if no debugger is attached.
+ static auto set_thread_description_func =
+ reinterpret_cast<SetThreadDescription>(::GetProcAddress(
+ ::GetModuleHandle(L"Kernel32.dll"), "SetThreadDescription"));
+ if (set_thread_description_func) {
+ set_thread_description_func(::GetCurrentThread(),
+ base::UTF8ToWide(name).c_str());
+ }
+
+ // The debugger needs to be around to catch the name in the exception. If
+ // there isn't a debugger, we are just needlessly throwing an exception.
+ if (!::IsDebuggerPresent())
+ return;
+
+ SetNameInternal(CurrentId(), name.c_str());
+}
+
+// static
+const char* PlatformThread::GetName() {
+ return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
+}
+
+// static
+bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle,
+ ThreadPriority priority) {
+ DCHECK(thread_handle);
+ return CreateThreadInternal(stack_size, delegate, thread_handle, priority);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+ return CreateNonJoinableWithPriority(stack_size, delegate,
+ ThreadPriority::NORMAL);
+}
+
+// static
+bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size,
+ Delegate* delegate,
+ ThreadPriority priority) {
+ return CreateThreadInternal(stack_size, delegate, nullptr /* non-joinable */,
+ priority);
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+ DCHECK(thread_handle.platform_handle());
+
+ DWORD thread_id = 0;
+ thread_id = ::GetThreadId(thread_handle.platform_handle());
+ DWORD last_error = 0;
+ if (!thread_id)
+ last_error = ::GetLastError();
+
+ // Record information about the exiting thread in case joining hangs.
+ base::debug::Alias(&thread_id);
+ base::debug::Alias(&last_error);
+
+ // Record the event that this thread is blocking upon (for hang diagnosis).
+ base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
+
+ base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
+ FROM_HERE, base::BlockingType::MAY_BLOCK);
+
+ // Wait for the thread to exit. It should already have terminated but make
+ // sure this assumption is valid.
+ CHECK_EQ(WAIT_OBJECT_0,
+ WaitForSingleObject(thread_handle.platform_handle(), INFINITE));
+ CloseHandle(thread_handle.platform_handle());
+}
+
+// static
+void PlatformThread::Detach(PlatformThreadHandle thread_handle) {
+ CloseHandle(thread_handle.platform_handle());
+}
+
+// static
+bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
+ return true;
+}
+
+// static
+void PlatformThread::SetCurrentThreadPriorityImpl(ThreadPriority priority) {
+ PlatformThreadHandle::Handle thread_handle =
+ PlatformThread::CurrentHandle().platform_handle();
+
+ if (priority != ThreadPriority::BACKGROUND) {
+ // Exit background mode if the new priority is not BACKGROUND. This is a
+ // no-op if not in background mode.
+ ::SetThreadPriority(thread_handle, THREAD_MODE_BACKGROUND_END);
+ internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_NORMAL);
+ }
+
+ int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
+ switch (priority) {
+ case ThreadPriority::BACKGROUND:
+ // Using THREAD_MODE_BACKGROUND_BEGIN instead of THREAD_PRIORITY_LOWEST
+ // improves input latency and navigation time. See
+ // https://docs.google.com/document/d/16XrOwuwTwKWdgPbcKKajTmNqtB4Am8TgS9GjbzBYLc0
+ //
+ // MSDN recommends THREAD_MODE_BACKGROUND_BEGIN for threads that perform
+ // background work, as it reduces disk and memory priority in addition to
+ // CPU priority.
+ desired_priority = THREAD_MODE_BACKGROUND_BEGIN;
+ break;
+ case ThreadPriority::NORMAL:
+ desired_priority = THREAD_PRIORITY_NORMAL;
+ break;
+ case ThreadPriority::DISPLAY:
+ desired_priority = THREAD_PRIORITY_ABOVE_NORMAL;
+ break;
+ case ThreadPriority::REALTIME_AUDIO:
+ desired_priority = THREAD_PRIORITY_TIME_CRITICAL;
+ break;
+ default:
+ NOTREACHED() << "Unknown priority.";
+ break;
+ }
+ DCHECK_NE(desired_priority, THREAD_PRIORITY_ERROR_RETURN);
+
+#if DCHECK_IS_ON()
+ const BOOL success =
+#endif
+ ::SetThreadPriority(thread_handle, desired_priority);
+ DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
+ << desired_priority;
+
+ if (priority == ThreadPriority::BACKGROUND) {
+ // In a background process, THREAD_MODE_BACKGROUND_BEGIN lowers the memory
+ // and I/O priorities but not the CPU priority (kernel bug?). Use
+ // THREAD_PRIORITY_LOWEST to also lower the CPU priority.
+ // https://crbug.com/901483
+ if (GetCurrentThreadPriority() != ThreadPriority::BACKGROUND) {
+ ::SetThreadPriority(thread_handle, THREAD_PRIORITY_LOWEST);
+ // Make sure that using THREAD_PRIORITY_LOWEST didn't affect the memory
+ // priority set by THREAD_MODE_BACKGROUND_BEGIN. There is no practical
+ // way to verify the I/O priority.
+ internal::AssertMemoryPriority(thread_handle, MEMORY_PRIORITY_VERY_LOW);
+ }
+ }
+
+ DCHECK_EQ(GetCurrentThreadPriority(), priority);
+}
+
+// static
+ThreadPriority PlatformThread::GetCurrentThreadPriority() {
+ static_assert(
+ THREAD_PRIORITY_IDLE < 0,
+ "THREAD_PRIORITY_IDLE is >= 0 and will incorrectly cause errors.");
+ static_assert(
+ THREAD_PRIORITY_LOWEST < 0,
+ "THREAD_PRIORITY_LOWEST is >= 0 and will incorrectly cause errors.");
+ static_assert(THREAD_PRIORITY_BELOW_NORMAL < 0,
+ "THREAD_PRIORITY_BELOW_NORMAL is >= 0 and will incorrectly "
+ "cause errors.");
+ static_assert(
+ THREAD_PRIORITY_NORMAL == 0,
+ "The logic below assumes that THREAD_PRIORITY_NORMAL is zero. If it is "
+ "not, ThreadPriority::BACKGROUND may be incorrectly detected.");
+ static_assert(THREAD_PRIORITY_ABOVE_NORMAL >= 0,
+ "THREAD_PRIORITY_ABOVE_NORMAL is < 0 and will incorrectly be "
+ "translated to ThreadPriority::BACKGROUND.");
+ static_assert(THREAD_PRIORITY_HIGHEST >= 0,
+ "THREAD_PRIORITY_HIGHEST is < 0 and will incorrectly be "
+ "translated to ThreadPriority::BACKGROUND.");
+ static_assert(THREAD_PRIORITY_TIME_CRITICAL >= 0,
+ "THREAD_PRIORITY_TIME_CRITICAL is < 0 and will incorrectly be "
+ "translated to ThreadPriority::BACKGROUND.");
+ static_assert(THREAD_PRIORITY_ERROR_RETURN >= 0,
+ "THREAD_PRIORITY_ERROR_RETURN is < 0 and will incorrectly be "
+ "translated to ThreadPriority::BACKGROUND.");
+
+ const int priority =
+ ::GetThreadPriority(PlatformThread::CurrentHandle().platform_handle());
+
+ // Negative values represent a background priority. We have observed -3, -4,
+ // -6 when THREAD_MODE_BACKGROUND_* is used. THREAD_PRIORITY_IDLE,
+ // THREAD_PRIORITY_LOWEST and THREAD_PRIORITY_BELOW_NORMAL are other possible
+ // negative values.
+ if (priority < THREAD_PRIORITY_NORMAL)
+ return ThreadPriority::BACKGROUND;
+
+ switch (priority) {
+ case kWin7BackgroundThreadModePriority:
+ DCHECK_EQ(win::GetVersion(), win::Version::WIN7);
+ return ThreadPriority::BACKGROUND;
+ case kWin7NormalPriority:
+ DCHECK_EQ(win::GetVersion(), win::Version::WIN7);
+ FALLTHROUGH;
+ case THREAD_PRIORITY_NORMAL:
+ return ThreadPriority::NORMAL;
+ case kWinNormalPriority1:
+ FALLTHROUGH;
+ case kWinNormalPriority2:
+ return ThreadPriority::NORMAL;
+ case THREAD_PRIORITY_ABOVE_NORMAL:
+ case THREAD_PRIORITY_HIGHEST:
+ return ThreadPriority::DISPLAY;
+ case THREAD_PRIORITY_TIME_CRITICAL:
+ return ThreadPriority::REALTIME_AUDIO;
+ case THREAD_PRIORITY_ERROR_RETURN:
+ DPCHECK(false) << "::GetThreadPriority error";
+ }
+
+ NOTREACHED() << "::GetThreadPriority returned " << priority << ".";
+ return ThreadPriority::NORMAL;
+}
+
+// static
+size_t PlatformThread::GetDefaultThreadStackSize() {
+ return 0;
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/platform_thread_win.h b/security/sandbox/chromium/base/threading/platform_thread_win.h
new file mode 100644
index 0000000000..3e833178e3
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/platform_thread_win.h
@@ -0,0 +1,23 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_WIN_H_
+#define BASE_THREADING_PLATFORM_THREAD_WIN_H_
+
+#include "base/threading/platform_thread.h"
+
+#include "base/base_export.h"
+
+namespace base {
+namespace internal {
+
+// Assert that the memory priority of |thread| is |memory_priority|. No-op on
+// Windows 7 because ::GetThreadInformation() is not available. Exposed for unit
+// tests.
+BASE_EXPORT void AssertMemoryPriority(HANDLE thread, int memory_priority);
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_WIN_H_
diff --git a/security/sandbox/chromium/base/threading/thread_checker_impl.h b/security/sandbox/chromium/base/threading/thread_checker_impl.h
new file mode 100644
index 0000000000..b325db6ae8
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_checker_impl.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_CHECKER_IMPL_H_
+#define BASE_THREADING_THREAD_CHECKER_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/sequence_token.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// Real implementation of ThreadChecker, for use in debug mode, or for temporary
+// use in release mode (e.g. to CHECK on a threading issue seen only in the
+// wild).
+//
+// Note: You should almost always use the ThreadChecker class to get the right
+// version for your build configuration.
+// Note: This is only a check, not a "lock". It is marked "LOCKABLE" only in
+// order to support thread_annotations.h.
+class LOCKABLE BASE_EXPORT ThreadCheckerImpl {
+ public:
+ ThreadCheckerImpl();
+ ~ThreadCheckerImpl();
+
+ // Allow move construct/assign. This must be called on |other|'s associated
+ // thread and assignment can only be made into a ThreadCheckerImpl which is
+ // detached or already associated with the current thread. This isn't
+ // thread-safe (|this| and |other| shouldn't be in use while this move is
+ // performed). If the assignment was legal, the resulting ThreadCheckerImpl
+ // will be bound to the current thread and |other| will be detached.
+ ThreadCheckerImpl(ThreadCheckerImpl&& other);
+ ThreadCheckerImpl& operator=(ThreadCheckerImpl&& other);
+
+ bool CalledOnValidThread() const WARN_UNUSED_RESULT;
+
+ // Changes the thread that is checked for in CalledOnValidThread. This may
+ // be useful when an object may be created on one thread and then used
+ // exclusively on another thread.
+ void DetachFromThread();
+
+ private:
+ void EnsureAssignedLockRequired() const EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ // Members are mutable so that CalledOnValidThread() can set them.
+
+ // Synchronizes access to all members.
+ mutable base::Lock lock_;
+
+ // Thread on which CalledOnValidThread() may return true.
+ mutable PlatformThreadRef thread_id_ GUARDED_BY(lock_);
+
+ // TaskToken for which CalledOnValidThread() always returns true. This allows
+ // CalledOnValidThread() to return true when called multiple times from the
+ // same task, even if it's not running in a single-threaded context itself
+ // (allowing usage of ThreadChecker objects on the stack in the scope of one-
+ // off tasks). Note: CalledOnValidThread() may return true even if the current
+ // TaskToken is not equal to this.
+ mutable TaskToken task_token_ GUARDED_BY(lock_);
+
+ // SequenceToken for which CalledOnValidThread() may return true. Used to
+ // ensure that CalledOnValidThread() doesn't return true for ThreadPool
+ // tasks that happen to run on the same thread but weren't posted to the same
+ // SingleThreadTaskRunner.
+ mutable SequenceToken sequence_token_ GUARDED_BY(lock_);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_CHECKER_IMPL_H_
diff --git a/security/sandbox/chromium/base/threading/thread_collision_warner.cc b/security/sandbox/chromium/base/threading/thread_collision_warner.cc
new file mode 100644
index 0000000000..547e11ca66
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_collision_warner.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_collision_warner.h"
+
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+void DCheckAsserter::warn() {
+ NOTREACHED() << "Thread Collision";
+}
+
+static subtle::Atomic32 CurrentThread() {
+ const PlatformThreadId current_thread_id = PlatformThread::CurrentId();
+ // We need to get the thread id into an atomic data type. This might be a
+ // truncating conversion, but any loss-of-information just increases the
+ // chance of a fault negative, not a false positive.
+ const subtle::Atomic32 atomic_thread_id =
+ static_cast<subtle::Atomic32>(current_thread_id);
+
+ return atomic_thread_id;
+}
+
+void ThreadCollisionWarner::EnterSelf() {
+ // If the active thread is 0 then I'll write the current thread ID
+ // if two or more threads arrive here only one will succeed to
+ // write on valid_thread_id_ the current thread ID.
+ subtle::Atomic32 current_thread_id = CurrentThread();
+
+ int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+ 0,
+ current_thread_id);
+ if (previous_value != 0 && previous_value != current_thread_id) {
+ // gotcha! a thread is trying to use the same class and that is
+ // not current thread.
+ asserter_->warn();
+ }
+
+ subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Enter() {
+ subtle::Atomic32 current_thread_id = CurrentThread();
+
+ if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+ 0,
+ current_thread_id) != 0) {
+ // gotcha! another thread is trying to use the same class.
+ asserter_->warn();
+ }
+
+ subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Leave() {
+ if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) {
+ subtle::NoBarrier_Store(&valid_thread_id_, 0);
+ }
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/thread_collision_warner.h b/security/sandbox/chromium/base/threading/thread_collision_warner.h
new file mode 100644
index 0000000000..7f7443b21d
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_collision_warner.h
@@ -0,0 +1,252 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_
+#define BASE_THREADING_THREAD_COLLISION_WARNER_H_
+
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+
+// A helper class alongside macros to be used to verify assumptions about thread
+// safety of a class.
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+// are synchronized somehow.
+//
+// In this case the macro DFAKE_SCOPED_LOCK has to be
+// used, it checks that if a thread is inside the push/pop then
+// noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+// public:
+// ...
+// void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
+// int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+// are synchronized somehow, it calls a method to "protect" from
+// a "protected" method
+//
+// In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
+// has to be used, it checks that if a thread is inside the push/pop
+// then noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+// public:
+// void push(int) {
+// DFAKE_SCOPED_LOCK(push_pop_);
+// ...
+// }
+// int pop() {
+// DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+// bar();
+// ...
+// }
+// void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation not usable even if clients are synchronized,
+// so only one thread in the class life cycle can use the two members
+// push/pop.
+//
+// In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
+// specified
+// critical section the first time a thread enters push or pop, from
+// that time on only that thread is allowed to execute push or pop.
+//
+// class NonThreadSafeQueue {
+// public:
+// ...
+// void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+// int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Class that has to be contructed/destroyed on same thread, it has
+// a "shareable" method (with external synchronization) and a not
+// shareable method (even with external synchronization).
+//
+// In this case 3 Critical sections have to be defined
+//
+// class ExoticClass {
+// public:
+// ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+// ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//
+// void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
+// void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(ctor_dtor_);
+// DFAKE_MUTEX(shareable_section_);
+// };
+
+
+#if !defined(NDEBUG)
+
+#define DFAKE_UNIQUE_VARIABLE_CONCAT(a, b) a##b
+// CONCAT1 provides extra level of indirection so that __LINE__ macro expands.
+#define DFAKE_UNIQUE_VARIABLE_CONCAT1(a, b) DFAKE_UNIQUE_VARIABLE_CONCAT(a, b)
+#define DFAKE_UNIQUE_VARIABLE_NAME(a) DFAKE_UNIQUE_VARIABLE_CONCAT1(a, __LINE__)
+
+// Defines a class member that acts like a mutex. It is used only as a
+// verification tool.
+#define DFAKE_MUTEX(obj) \
+ mutable base::ThreadCollisionWarner obj
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope.
+#define DFAKE_SCOPED_LOCK(obj) \
+ base::ThreadCollisionWarner::ScopedCheck DFAKE_UNIQUE_VARIABLE_NAME( \
+ s_check_)(&obj)
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
+ base::ThreadCollisionWarner::ScopedRecursiveCheck \
+ DFAKE_UNIQUE_VARIABLE_NAME(sr_check)(&obj)
+// Asserts the code is always executed in the same thread.
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
+ base::ThreadCollisionWarner::Check DFAKE_UNIQUE_VARIABLE_NAME(check_)(&obj)
+
+#else
+
+#define DFAKE_MUTEX(obj) typedef void InternalFakeMutexType##obj
+#define DFAKE_SCOPED_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0)
+
+#endif
+
+namespace base {
+
+// The class ThreadCollisionWarner uses an Asserter to notify the collision
+// AsserterBase is the interfaces and DCheckAsserter is the default asserter
+// used. During the unit tests is used another class that doesn't "DCHECK"
+// in case of collision (check thread_collision_warner_unittests.cc)
+struct BASE_EXPORT AsserterBase {
+ virtual ~AsserterBase() = default;
+ virtual void warn() = 0;
+};
+
+struct BASE_EXPORT DCheckAsserter : public AsserterBase {
+ ~DCheckAsserter() override = default;
+ void warn() override;
+};
+
+class BASE_EXPORT ThreadCollisionWarner {
+ public:
+ // The parameter asserter is there only for test purpose
+ explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
+ : valid_thread_id_(0),
+ counter_(0),
+ asserter_(asserter) {}
+
+ ~ThreadCollisionWarner() {
+ delete asserter_;
+ }
+
+ // This class is meant to be used through the macro
+ // DFAKE_SCOPED_LOCK_THREAD_LOCKED
+ // it doesn't leave the critical section, as opposed to ScopedCheck,
+ // because the critical section being pinned is allowed to be used only
+ // from one thread
+ class BASE_EXPORT Check {
+ public:
+ explicit Check(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->EnterSelf();
+ }
+
+ ~Check() = default;
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(Check);
+ };
+
+ // This class is meant to be used through the macro
+ // DFAKE_SCOPED_LOCK
+ class BASE_EXPORT ScopedCheck {
+ public:
+ explicit ScopedCheck(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->Enter();
+ }
+
+ ~ScopedCheck() {
+ warner_->Leave();
+ }
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
+ };
+
+ // This class is meant to be used through the macro
+ // DFAKE_SCOPED_RECURSIVE_LOCK
+ class BASE_EXPORT ScopedRecursiveCheck {
+ public:
+ explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->EnterSelf();
+ }
+
+ ~ScopedRecursiveCheck() {
+ warner_->Leave();
+ }
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
+ };
+
+ private:
+ // This method stores the current thread identifier and does a DCHECK
+ // if a another thread has already done it, it is safe if same thread
+ // calls this multiple time (recursion allowed).
+ void EnterSelf();
+
+ // Same as EnterSelf but recursion is not allowed.
+ void Enter();
+
+ // Removes the thread_id stored in order to allow other threads to
+ // call EnterSelf or Enter.
+ void Leave();
+
+ // This stores the thread id that is inside the critical section, if the
+ // value is 0 then no thread is inside.
+ volatile subtle::Atomic32 valid_thread_id_;
+
+ // Counter to trace how many time a critical section was "pinned"
+ // (when allowed) in order to unpin it when counter_ reaches 0.
+ volatile subtle::Atomic32 counter_;
+
+ // Here only for class unit tests purpose, during the test I need to not
+ // DCHECK but notify the collision with something else.
+ AsserterBase* asserter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_COLLISION_WARNER_H_
diff --git a/security/sandbox/chromium/base/threading/thread_id_name_manager.cc b/security/sandbox/chromium/base/threading/thread_id_name_manager.cc
new file mode 100644
index 0000000000..ba2f9b41cb
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_id_name_manager.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_id_name_manager.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/no_destructor.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_local.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+namespace base {
+namespace {
+
+static const char kDefaultName[] = "";
+static std::string* g_default_name;
+
+ThreadLocalStorage::Slot& GetThreadNameTLS() {
+ static base::NoDestructor<base::ThreadLocalStorage::Slot> thread_name_tls;
+ return *thread_name_tls;
+}
+}
+
+ThreadIdNameManager::Observer::~Observer() = default;
+
+ThreadIdNameManager::ThreadIdNameManager()
+ : main_process_name_(nullptr), main_process_id_(kInvalidThreadId) {
+ g_default_name = new std::string(kDefaultName);
+
+ AutoLock locked(lock_);
+ name_to_interned_name_[kDefaultName] = g_default_name;
+}
+
+ThreadIdNameManager::~ThreadIdNameManager() = default;
+
+ThreadIdNameManager* ThreadIdNameManager::GetInstance() {
+ return Singleton<ThreadIdNameManager,
+ LeakySingletonTraits<ThreadIdNameManager> >::get();
+}
+
+const char* ThreadIdNameManager::GetDefaultInternedString() {
+ return g_default_name->c_str();
+}
+
+void ThreadIdNameManager::RegisterThread(PlatformThreadHandle::Handle handle,
+ PlatformThreadId id) {
+ AutoLock locked(lock_);
+ thread_id_to_handle_[id] = handle;
+ thread_handle_to_interned_name_[handle] =
+ name_to_interned_name_[kDefaultName];
+}
+
+void ThreadIdNameManager::AddObserver(Observer* obs) {
+ AutoLock locked(lock_);
+ DCHECK(!base::Contains(observers_, obs));
+ observers_.push_back(obs);
+}
+
+void ThreadIdNameManager::RemoveObserver(Observer* obs) {
+ AutoLock locked(lock_);
+ DCHECK(base::Contains(observers_, obs));
+ base::Erase(observers_, obs);
+}
+
+void ThreadIdNameManager::SetName(const std::string& name) {
+ PlatformThreadId id = PlatformThread::CurrentId();
+ std::string* leaked_str = nullptr;
+ {
+ AutoLock locked(lock_);
+ auto iter = name_to_interned_name_.find(name);
+ if (iter != name_to_interned_name_.end()) {
+ leaked_str = iter->second;
+ } else {
+ leaked_str = new std::string(name);
+ name_to_interned_name_[name] = leaked_str;
+ }
+
+ auto id_to_handle_iter = thread_id_to_handle_.find(id);
+
+ GetThreadNameTLS().Set(const_cast<char*>(leaked_str->c_str()));
+ for (Observer* obs : observers_)
+ obs->OnThreadNameChanged(leaked_str->c_str());
+
+ // The main thread of a process will not be created as a Thread object which
+ // means there is no PlatformThreadHandler registered.
+ if (id_to_handle_iter == thread_id_to_handle_.end()) {
+ main_process_name_ = leaked_str;
+ main_process_id_ = id;
+ return;
+ }
+ thread_handle_to_interned_name_[id_to_handle_iter->second] = leaked_str;
+ }
+
+ // Add the leaked thread name to heap profiler context tracker. The name added
+ // is valid for the lifetime of the process. AllocationContextTracker cannot
+ // call GetName(which holds a lock) during the first allocation because it can
+ // cause a deadlock when the first allocation happens in the
+ // ThreadIdNameManager itself when holding the lock.
+ trace_event::AllocationContextTracker::SetCurrentThreadName(
+ leaked_str->c_str());
+}
+
+const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
+ AutoLock locked(lock_);
+
+ if (id == main_process_id_)
+ return main_process_name_->c_str();
+
+ auto id_to_handle_iter = thread_id_to_handle_.find(id);
+ if (id_to_handle_iter == thread_id_to_handle_.end())
+ return name_to_interned_name_[kDefaultName]->c_str();
+
+ auto handle_to_name_iter =
+ thread_handle_to_interned_name_.find(id_to_handle_iter->second);
+ return handle_to_name_iter->second->c_str();
+}
+
+const char* ThreadIdNameManager::GetNameForCurrentThread() {
+ const char* name = reinterpret_cast<const char*>(GetThreadNameTLS().Get());
+ return name ? name : kDefaultName;
+}
+
+void ThreadIdNameManager::RemoveName(PlatformThreadHandle::Handle handle,
+ PlatformThreadId id) {
+ AutoLock locked(lock_);
+ auto handle_to_name_iter = thread_handle_to_interned_name_.find(handle);
+
+ DCHECK(handle_to_name_iter != thread_handle_to_interned_name_.end());
+ thread_handle_to_interned_name_.erase(handle_to_name_iter);
+
+ auto id_to_handle_iter = thread_id_to_handle_.find(id);
+ DCHECK((id_to_handle_iter!= thread_id_to_handle_.end()));
+ // The given |id| may have been re-used by the system. Make sure the
+ // mapping points to the provided |handle| before removal.
+ if (id_to_handle_iter->second != handle)
+ return;
+
+ thread_id_to_handle_.erase(id_to_handle_iter);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/thread_id_name_manager.h b/security/sandbox/chromium/base/threading/thread_id_name_manager.h
new file mode 100644
index 0000000000..e413da5d03
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_id_name_manager.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
+#define BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+template <typename T>
+struct DefaultSingletonTraits;
+
+class BASE_EXPORT ThreadIdNameManager {
+ public:
+ static ThreadIdNameManager* GetInstance();
+
+ static const char* GetDefaultInternedString();
+
+ class BASE_EXPORT Observer {
+ public:
+ virtual ~Observer();
+
+ // Called on the thread whose name is changing, immediately after the name
+ // is set. |name| is a pointer to a C string that is guaranteed to remain
+ // valid for the duration of the process.
+ //
+ // NOTE: Will be called while ThreadIdNameManager's lock is held, so don't
+ // call back into it.
+ virtual void OnThreadNameChanged(const char* name) = 0;
+ };
+
+ // Register the mapping between a thread |id| and |handle|.
+ void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id);
+
+ void AddObserver(Observer*);
+ void RemoveObserver(Observer*);
+
+ // Set the name for the current thread.
+ void SetName(const std::string& name);
+
+ // Get the name for the given id.
+ const char* GetName(PlatformThreadId id);
+
+ // Unlike |GetName|, this method using TLS and avoids touching |lock_|.
+ const char* GetNameForCurrentThread();
+
+ // Remove the name for the given id.
+ void RemoveName(PlatformThreadHandle::Handle handle, PlatformThreadId id);
+
+ private:
+ friend struct DefaultSingletonTraits<ThreadIdNameManager>;
+
+ typedef std::map<PlatformThreadId, PlatformThreadHandle::Handle>
+ ThreadIdToHandleMap;
+ typedef std::map<PlatformThreadHandle::Handle, std::string*>
+ ThreadHandleToInternedNameMap;
+ typedef std::map<std::string, std::string*> NameToInternedNameMap;
+
+ ThreadIdNameManager();
+ ~ThreadIdNameManager();
+
+ // lock_ protects the name_to_interned_name_, thread_id_to_handle_ and
+ // thread_handle_to_interned_name_ maps.
+ Lock lock_;
+
+ NameToInternedNameMap name_to_interned_name_;
+ ThreadIdToHandleMap thread_id_to_handle_;
+ ThreadHandleToInternedNameMap thread_handle_to_interned_name_;
+
+ // Treat the main process specially as there is no PlatformThreadHandle.
+ std::string* main_process_name_;
+ PlatformThreadId main_process_id_;
+
+ // There's no point using a base::ObserverList behind a lock, so we just use
+ // an std::vector instead.
+ std::vector<Observer*> observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadIdNameManager);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
diff --git a/security/sandbox/chromium/base/threading/thread_local.h b/security/sandbox/chromium/base/threading/thread_local.h
new file mode 100644
index 0000000000..162b10bf0f
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_local.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// WARNING: Thread local storage is a bit tricky to get right. Please make sure
+// that this is really the proper solution for what you're trying to achieve.
+// Don't prematurely optimize, most likely you can just use a Lock.
+//
+// These classes implement a wrapper around ThreadLocalStorage::Slot. On
+// construction, they will allocate a TLS slot, and free the TLS slot on
+// destruction. No memory management (creation or destruction) is handled. This
+// means for uses of ThreadLocalPointer, you must correctly manage the memory
+// yourself, these classes will not destroy the pointer for you. There are no
+// at-thread-exit actions taken by these classes.
+//
+// ThreadLocalPointer<Type> wraps a Type*. It performs no creation or
+// destruction, so memory management must be handled elsewhere. The first call
+// to Get() on a thread will return NULL. You can update the pointer with a call
+// to Set().
+//
+// ThreadLocalBoolean wraps a bool. It will default to false if it has never
+// been set otherwise with Set().
+//
+// Thread Safety: An instance of ThreadLocalStorage is completely thread safe
+// once it has been created. If you want to dynamically create an instance, you
+// must of course properly deal with safety and race conditions.
+//
+// In Android, the system TLS is limited.
+//
+// Example usage:
+// // My class is logically attached to a single thread. We cache a pointer
+// // on the thread it was created on, so we can implement current().
+// MyClass::MyClass() {
+// DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() == NULL);
+// Singleton<ThreadLocalPointer<MyClass> >::get()->Set(this);
+// }
+//
+// MyClass::~MyClass() {
+// DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() != NULL);
+// Singleton<ThreadLocalPointer<MyClass> >::get()->Set(NULL);
+// }
+//
+// // Return the current MyClass associated with the calling thread, can be
+// // NULL if there isn't a MyClass associated.
+// MyClass* MyClass::current() {
+// return Singleton<ThreadLocalPointer<MyClass> >::get()->Get();
+// }
+
+#ifndef BASE_THREADING_THREAD_LOCAL_H_
+#define BASE_THREADING_THREAD_LOCAL_H_
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/threading/thread_local_internal.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+
+template <typename T>
+class ThreadLocalPointer {
+ public:
+ ThreadLocalPointer() = default;
+ ~ThreadLocalPointer() = default;
+
+ T* Get() const { return static_cast<T*>(slot_.Get()); }
+
+ void Set(T* ptr) {
+ slot_.Set(const_cast<void*>(static_cast<const void*>(ptr)));
+ }
+
+ private:
+ ThreadLocalStorage::Slot slot_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer);
+};
+
+// A ThreadLocalOwnedPointer<T> is like a ThreadLocalPointer<T> except that
+// pointers handed to it are owned and automatically deleted during their
+// associated thread's exit phase (or when replaced if Set() is invoked multiple
+// times on the same thread).
+// The ThreadLocalOwnedPointer instance itself can only be destroyed when no
+// threads, other than the one it is destroyed on, have remaining state set in
+// it. Typically this means that ThreadLocalOwnedPointer instances are held in
+// static storage or at the very least only recycled in the single-threaded
+// phase between tests in the same process.
+#if DCHECK_IS_ON()
+template <typename T>
+using ThreadLocalOwnedPointer = internal::CheckedThreadLocalOwnedPointer<T>;
+#else // DCHECK_IS_ON()
+template <typename T>
+class ThreadLocalOwnedPointer {
+ public:
+ ThreadLocalOwnedPointer() = default;
+
+ ~ThreadLocalOwnedPointer() {
+ // Assume that this thread is the only one with potential state left. This
+ // is verified in ~CheckedThreadLocalOwnedPointer().
+ Set(nullptr);
+ }
+
+ T* Get() const { return static_cast<T*>(slot_.Get()); }
+
+ void Set(std::unique_ptr<T> ptr) {
+ delete Get();
+ slot_.Set(const_cast<void*>(static_cast<const void*>(ptr.release())));
+ }
+
+ private:
+ static void DeleteTlsPtr(void* ptr) { delete static_cast<T*>(ptr); }
+
+ ThreadLocalStorage::Slot slot_{&DeleteTlsPtr};
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLocalOwnedPointer);
+};
+#endif // DCHECK_IS_ON()
+
+class ThreadLocalBoolean {
+ public:
+ ThreadLocalBoolean() = default;
+ ~ThreadLocalBoolean() = default;
+
+ bool Get() const { return tlp_.Get() != nullptr; }
+
+ void Set(bool val) { tlp_.Set(val ? this : nullptr); }
+
+ private:
+ ThreadLocalPointer<void> tlp_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_LOCAL_H_
diff --git a/security/sandbox/chromium/base/threading/thread_local_internal.h b/security/sandbox/chromium/base/threading/thread_local_internal.h
new file mode 100644
index 0000000000..bd2bea0636
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_local_internal.h
@@ -0,0 +1,80 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
+#define BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
+
+#if DCHECK_IS_ON()
+
+#include <atomic>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+namespace internal {
+
+// A version of ThreadLocalOwnedPointer which verifies that it's only destroyed
+// when no threads, other than the one it is destroyed on, have remaining state
+// set in it. A ThreadLocalOwnedPointer instance being destroyed too early would
+// result in leaks per unregistering the TLS slot (and thus the DeleteTlsPtr
+// hook).
+template <typename T>
+class CheckedThreadLocalOwnedPointer {
+ public:
+ CheckedThreadLocalOwnedPointer() = default;
+
+ ~CheckedThreadLocalOwnedPointer() {
+ Set(nullptr);
+
+ DCHECK_EQ(num_assigned_threads_.load(std::memory_order_relaxed), 0)
+ << "Memory leak: Must join all threads or release all associated "
+ "thread-local slots before ~ThreadLocalOwnedPointer";
+ }
+
+ T* Get() const {
+ PtrTracker* const ptr_tracker = static_cast<PtrTracker*>(slot_.Get());
+ return ptr_tracker ? ptr_tracker->ptr_.get() : nullptr;
+ }
+
+ void Set(std::unique_ptr<T> ptr) {
+ delete static_cast<PtrTracker*>(slot_.Get());
+ if (ptr)
+ slot_.Set(new PtrTracker(this, std::move(ptr)));
+ else
+ slot_.Set(nullptr);
+ }
+
+ private:
+ struct PtrTracker {
+ public:
+ PtrTracker(CheckedThreadLocalOwnedPointer<T>* outer, std::unique_ptr<T> ptr)
+ : outer_(outer), ptr_(std::move(ptr)) {
+ outer_->num_assigned_threads_.fetch_add(1, std::memory_order_relaxed);
+ }
+
+ ~PtrTracker() {
+ outer_->num_assigned_threads_.fetch_sub(1, std::memory_order_relaxed);
+ }
+
+ CheckedThreadLocalOwnedPointer<T>* const outer_;
+ const std::unique_ptr<T> ptr_;
+ };
+
+ static void DeleteTlsPtr(void* ptr) { delete static_cast<PtrTracker*>(ptr); }
+
+ ThreadLocalStorage::Slot slot_{&DeleteTlsPtr};
+
+ std::atomic_int num_assigned_threads_{0};
+
+ DISALLOW_COPY_AND_ASSIGN(CheckedThreadLocalOwnedPointer);
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // DCHECK_IS_ON()
+
+#endif // BASE_THREADING_THREAD_LOCAL_INTERNAL_H_
diff --git a/security/sandbox/chromium/base/threading/thread_local_storage.cc b/security/sandbox/chromium/base/threading/thread_local_storage.cc
new file mode 100644
index 0000000000..204f34c272
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_local_storage.cc
@@ -0,0 +1,461 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include "base/atomicops.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+using base::internal::PlatformThreadLocalStorage;
+
+// Chrome Thread Local Storage (TLS)
+//
+// This TLS system allows Chrome to use a single OS level TLS slot process-wide,
+// and allows us to control the slot limits instead of being at the mercy of the
+// platform. To do this, Chrome TLS replicates an array commonly found in the OS
+// thread metadata.
+//
+// Overview:
+//
+// OS TLS Slots Per-Thread Per-Process Global
+// ...
+// [] Chrome TLS Array Chrome TLS Metadata
+// [] ----------> [][][][][ ][][][][] [][][][][ ][][][][]
+// [] | |
+// ... V V
+// Metadata Version Slot Information
+// Your Data!
+//
+// Using a single OS TLS slot, Chrome TLS allocates an array on demand for the
+// lifetime of each thread that requests Chrome TLS data. Each per-thread TLS
+// array matches the length of the per-process global metadata array.
+//
+// A per-process global TLS metadata array tracks information about each item in
+// the per-thread array:
+// * Status: Tracks if the slot is allocated or free to assign.
+// * Destructor: An optional destructor to call on thread destruction for that
+// specific slot.
+// * Version: Tracks the current version of the TLS slot. Each TLS slot
+// allocation is associated with a unique version number.
+//
+// Most OS TLS APIs guarantee that a newly allocated TLS slot is
+// initialized to 0 for all threads. The Chrome TLS system provides
+// this guarantee by tracking the version for each TLS slot here
+// on each per-thread Chrome TLS array entry. Threads that access
+// a slot with a mismatched version will receive 0 as their value.
+// The metadata version is incremented when the client frees a
+// slot. The per-thread metadata version is updated when a client
+// writes to the slot. This scheme allows for constant time
+// invalidation and avoids the need to iterate through each Chrome
+// TLS array to mark the slot as zero.
+//
+// Just like an OS TLS API, clients of the Chrome TLS are responsible for
+// managing any necessary lifetime of the data in their slots. The only
+// convenience provided is automatic destruction when a thread ends. If a client
+// frees a slot, that client is responsible for destroying the data in the slot.
+
+namespace {
+// In order to make TLS destructors work, we need to keep around a function
+// pointer to the destructor for each slot. We keep this array of pointers in a
+// global (static) array.
+// We use the single OS-level TLS slot (giving us one pointer per thread) to
+// hold a pointer to a per-thread array (table) of slots that we allocate to
+// Chromium consumers.
+
+// g_native_tls_key is the one native TLS that we use. It stores our table.
+base::subtle::Atomic32 g_native_tls_key =
+ PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES;
+
+// The OS TLS slot has the following states. The TLS slot's lower 2 bits contain
+// the state, the upper bits the TlsVectorEntry*.
+// * kUninitialized: Any call to Slot::Get()/Set() will create the base
+// per-thread TLS state. kUninitialized must be null.
+// * kInUse: value has been created and is in use.
+// * kDestroying: Set when the thread is exiting prior to deleting any of the
+// values stored in the TlsVectorEntry*. This state is necessary so that
+// sequence/task checks won't be done while in the process of deleting the
+// tls entries (see comments in SequenceCheckerImpl for more details).
+// * kDestroyed: All of the values in the vector have been deallocated and
+// the TlsVectorEntry has been deleted.
+//
+// Final States:
+// * Windows: kDestroyed. Windows does not iterate through the OS TLS to clean
+// up the values.
+// * POSIX: kUninitialized. POSIX iterates through TLS until all slots contain
+// nullptr.
+//
+// More details on this design:
+// We need some type of thread-local state to indicate that the TLS system has
+// been destroyed. To do so, we leverage the multi-pass nature of destruction
+// of pthread_key.
+//
+// a) After destruction of TLS system, we set the pthread_key to a sentinel
+// kDestroyed.
+// b) All calls to Slot::Get() DCHECK that the state is not kDestroyed, and
+// any system which might potentially invoke Slot::Get() after destruction
+// of TLS must check ThreadLocalStorage::ThreadIsBeingDestroyed().
+// c) After a full pass of the pthread_keys, on the next invocation of
+// ConstructTlsVector(), we'll then set the key to nullptr.
+// d) At this stage, the TLS system is back in its uninitialized state.
+// e) If in the second pass of destruction of pthread_keys something were to
+// re-initialize TLS [this should never happen! Since the only code which
+// uses Chrome TLS is Chrome controlled, we should really be striving for
+// single-pass destruction], then TLS will be re-initialized and then go
+// through the 2-pass destruction system again. Everything should just
+// work (TM).
+
+// The state of the tls-entry.
+enum class TlsVectorState {
+ kUninitialized = 0,
+
+ // In the process of destroying the entries in the vector.
+ kDestroying,
+
+ // All of the entries and the vector has been destroyed.
+ kDestroyed,
+
+ // The vector has been initialized and is in use.
+ kInUse,
+
+ kMaxValue = kInUse
+};
+
+// Bit-mask used to store TlsVectorState.
+constexpr uintptr_t kVectorStateBitMask = 3;
+static_assert(static_cast<int>(TlsVectorState::kMaxValue) <=
+ kVectorStateBitMask,
+ "number of states must fit in header");
+static_assert(static_cast<int>(TlsVectorState::kUninitialized) == 0,
+ "kUninitialized must be null");
+
+// The maximum number of slots in our thread local storage stack.
+constexpr int kThreadLocalStorageSize = 256;
+
+enum TlsStatus {
+ FREE,
+ IN_USE,
+};
+
+struct TlsMetadata {
+ TlsStatus status;
+ base::ThreadLocalStorage::TLSDestructorFunc destructor;
+ // Incremented every time a slot is reused. Used to detect reuse of slots.
+ uint32_t version;
+};
+
+struct TlsVectorEntry {
+ void* data;
+ uint32_t version;
+};
+
+// This lock isn't needed until after we've constructed the per-thread TLS
+// vector, so it's safe to use.
+base::Lock* GetTLSMetadataLock() {
+ static auto* lock = new base::Lock();
+ return lock;
+}
+TlsMetadata g_tls_metadata[kThreadLocalStorageSize];
+size_t g_last_assigned_slot = 0;
+
+// The maximum number of times to try to clear slots by calling destructors.
+// Use pthread naming convention for clarity.
+constexpr int kMaxDestructorIterations = kThreadLocalStorageSize;
+
+// Sets the value and state of the vector.
+void SetTlsVectorValue(PlatformThreadLocalStorage::TLSKey key,
+ TlsVectorEntry* tls_data,
+ TlsVectorState state) {
+ DCHECK(tls_data || (state == TlsVectorState::kUninitialized) ||
+ (state == TlsVectorState::kDestroyed));
+ PlatformThreadLocalStorage::SetTLSValue(
+ key, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(tls_data) |
+ static_cast<uintptr_t>(state)));
+}
+
+// Returns the tls vector and current state from the raw tls value.
+TlsVectorState GetTlsVectorStateAndValue(void* tls_value,
+ TlsVectorEntry** entry = nullptr) {
+ if (entry) {
+ *entry = reinterpret_cast<TlsVectorEntry*>(
+ reinterpret_cast<uintptr_t>(tls_value) & ~kVectorStateBitMask);
+ }
+ return static_cast<TlsVectorState>(reinterpret_cast<uintptr_t>(tls_value) &
+ kVectorStateBitMask);
+}
+
+// Returns the tls vector and state using the tls key.
+TlsVectorState GetTlsVectorStateAndValue(PlatformThreadLocalStorage::TLSKey key,
+ TlsVectorEntry** entry = nullptr) {
+ return GetTlsVectorStateAndValue(PlatformThreadLocalStorage::GetTLSValue(key),
+ entry);
+}
+
+// This function is called to initialize our entire Chromium TLS system.
+// It may be called very early, and we need to complete most all of the setup
+// (initialization) before calling *any* memory allocator functions, which may
+// recursively depend on this initialization.
+// As a result, we use Atomics, and avoid anything (like a singleton) that might
+// require memory allocations.
+TlsVectorEntry* ConstructTlsVector() {
+ PlatformThreadLocalStorage::TLSKey key =
+ base::subtle::NoBarrier_Load(&g_native_tls_key);
+ if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) {
+ CHECK(PlatformThreadLocalStorage::AllocTLS(&key));
+
+ // The TLS_KEY_OUT_OF_INDEXES is used to find out whether the key is set or
+ // not in NoBarrier_CompareAndSwap, but Posix doesn't have invalid key, we
+ // define an almost impossible value be it.
+ // If we really get TLS_KEY_OUT_OF_INDEXES as value of key, just alloc
+ // another TLS slot.
+ if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) {
+ PlatformThreadLocalStorage::TLSKey tmp = key;
+ CHECK(PlatformThreadLocalStorage::AllocTLS(&key) &&
+ key != PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES);
+ PlatformThreadLocalStorage::FreeTLS(tmp);
+ }
+ // Atomically test-and-set the tls_key. If the key is
+ // TLS_KEY_OUT_OF_INDEXES, go ahead and set it. Otherwise, do nothing, as
+ // another thread already did our dirty work.
+ if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES !=
+ static_cast<PlatformThreadLocalStorage::TLSKey>(
+ base::subtle::NoBarrier_CompareAndSwap(
+ &g_native_tls_key,
+ PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key))) {
+ // We've been shortcut. Another thread replaced g_native_tls_key first so
+ // we need to destroy our index and use the one the other thread got
+ // first.
+ PlatformThreadLocalStorage::FreeTLS(key);
+ key = base::subtle::NoBarrier_Load(&g_native_tls_key);
+ }
+ }
+ CHECK_EQ(GetTlsVectorStateAndValue(key), TlsVectorState::kUninitialized);
+
+ // Some allocators, such as TCMalloc, make use of thread local storage. As a
+ // result, any attempt to call new (or malloc) will lazily cause such a system
+ // to initialize, which will include registering for a TLS key. If we are not
+ // careful here, then that request to create a key will call new back, and
+ // we'll have an infinite loop. We avoid that as follows: Use a stack
+ // allocated vector, so that we don't have dependence on our allocator until
+ // our service is in place. (i.e., don't even call new until after we're
+ // setup)
+ TlsVectorEntry stack_allocated_tls_data[kThreadLocalStorageSize];
+ memset(stack_allocated_tls_data, 0, sizeof(stack_allocated_tls_data));
+ // Ensure that any rentrant calls change the temp version.
+ SetTlsVectorValue(key, stack_allocated_tls_data, TlsVectorState::kInUse);
+
+ // Allocate an array to store our data.
+ TlsVectorEntry* tls_data = new TlsVectorEntry[kThreadLocalStorageSize];
+ memcpy(tls_data, stack_allocated_tls_data, sizeof(stack_allocated_tls_data));
+ SetTlsVectorValue(key, tls_data, TlsVectorState::kInUse);
+ return tls_data;
+}
+
+void OnThreadExitInternal(TlsVectorEntry* tls_data) {
+ DCHECK(tls_data);
+ // Some allocators, such as TCMalloc, use TLS. As a result, when a thread
+ // terminates, one of the destructor calls we make may be to shut down an
+ // allocator. We have to be careful that after we've shutdown all of the known
+ // destructors (perchance including an allocator), that we don't call the
+ // allocator and cause it to resurrect itself (with no possibly destructor
+ // call to follow). We handle this problem as follows: Switch to using a stack
+ // allocated vector, so that we don't have dependence on our allocator after
+ // we have called all g_tls_metadata destructors. (i.e., don't even call
+ // delete[] after we're done with destructors.)
+ TlsVectorEntry stack_allocated_tls_data[kThreadLocalStorageSize];
+ memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data));
+ // Ensure that any re-entrant calls change the temp version.
+ PlatformThreadLocalStorage::TLSKey key =
+ base::subtle::NoBarrier_Load(&g_native_tls_key);
+ SetTlsVectorValue(key, stack_allocated_tls_data, TlsVectorState::kDestroying);
+ delete[] tls_data; // Our last dependence on an allocator.
+
+ // Snapshot the TLS Metadata so we don't have to lock on every access.
+ TlsMetadata tls_metadata[kThreadLocalStorageSize];
+ {
+ base::AutoLock auto_lock(*GetTLSMetadataLock());
+ memcpy(tls_metadata, g_tls_metadata, sizeof(g_tls_metadata));
+ }
+
+ int remaining_attempts = kMaxDestructorIterations;
+ bool need_to_scan_destructors = true;
+ while (need_to_scan_destructors) {
+ need_to_scan_destructors = false;
+ // Try to destroy the first-created-slot (which is slot 1) in our last
+ // destructor call. That user was able to function, and define a slot with
+ // no other services running, so perhaps it is a basic service (like an
+ // allocator) and should also be destroyed last. If we get the order wrong,
+ // then we'll iterate several more times, so it is really not that critical
+ // (but it might help).
+ for (int slot = 0; slot < kThreadLocalStorageSize; ++slot) {
+ void* tls_value = stack_allocated_tls_data[slot].data;
+ if (!tls_value || tls_metadata[slot].status == TlsStatus::FREE ||
+ stack_allocated_tls_data[slot].version != tls_metadata[slot].version)
+ continue;
+
+ base::ThreadLocalStorage::TLSDestructorFunc destructor =
+ tls_metadata[slot].destructor;
+ if (!destructor)
+ continue;
+ stack_allocated_tls_data[slot].data = nullptr; // pre-clear the slot.
+ destructor(tls_value);
+ // Any destructor might have called a different service, which then set a
+ // different slot to a non-null value. Hence we need to check the whole
+ // vector again. This is a pthread standard.
+ need_to_scan_destructors = true;
+ }
+ if (--remaining_attempts <= 0) {
+ NOTREACHED(); // Destructors might not have been called.
+ break;
+ }
+ }
+
+ // Remove our stack allocated vector.
+ SetTlsVectorValue(key, nullptr, TlsVectorState::kDestroyed);
+}
+
+} // namespace
+
+namespace base {
+
+namespace internal {
+
+#if defined(OS_WIN)
+void PlatformThreadLocalStorage::OnThreadExit() {
+ PlatformThreadLocalStorage::TLSKey key =
+ base::subtle::NoBarrier_Load(&g_native_tls_key);
+ if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
+ return;
+ TlsVectorEntry* tls_vector = nullptr;
+ const TlsVectorState state = GetTlsVectorStateAndValue(key, &tls_vector);
+
+ // On Windows, thread destruction callbacks are only invoked once per module,
+ // so there should be no way that this could be invoked twice.
+ DCHECK_NE(state, TlsVectorState::kDestroyed);
+
+ // Maybe we have never initialized TLS for this thread.
+ if (state == TlsVectorState::kUninitialized)
+ return;
+ OnThreadExitInternal(tls_vector);
+}
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+void PlatformThreadLocalStorage::OnThreadExit(void* value) {
+ // On posix this function may be called twice. The first pass calls dtors and
+ // sets state to kDestroyed. The second pass sets kDestroyed to
+ // kUninitialized.
+ TlsVectorEntry* tls_vector = nullptr;
+ const TlsVectorState state = GetTlsVectorStateAndValue(value, &tls_vector);
+ if (state == TlsVectorState::kDestroyed) {
+ PlatformThreadLocalStorage::TLSKey key =
+ base::subtle::NoBarrier_Load(&g_native_tls_key);
+ SetTlsVectorValue(key, nullptr, TlsVectorState::kUninitialized);
+ return;
+ }
+
+ OnThreadExitInternal(tls_vector);
+}
+#endif // defined(OS_WIN)
+
+} // namespace internal
+
+// static
+bool ThreadLocalStorage::HasBeenDestroyed() {
+ PlatformThreadLocalStorage::TLSKey key =
+ base::subtle::NoBarrier_Load(&g_native_tls_key);
+ if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
+ return false;
+ const TlsVectorState state = GetTlsVectorStateAndValue(key);
+ return state == TlsVectorState::kDestroying ||
+ state == TlsVectorState::kDestroyed;
+}
+
+void ThreadLocalStorage::Slot::Initialize(TLSDestructorFunc destructor) {
+ PlatformThreadLocalStorage::TLSKey key =
+ base::subtle::NoBarrier_Load(&g_native_tls_key);
+ if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES ||
+ GetTlsVectorStateAndValue(key) == TlsVectorState::kUninitialized) {
+ ConstructTlsVector();
+ }
+
+ // Grab a new slot.
+ {
+ base::AutoLock auto_lock(*GetTLSMetadataLock());
+ for (int i = 0; i < kThreadLocalStorageSize; ++i) {
+ // Tracking the last assigned slot is an attempt to find the next
+ // available slot within one iteration. Under normal usage, slots remain
+ // in use for the lifetime of the process (otherwise before we reclaimed
+ // slots, we would have run out of slots). This makes it highly likely the
+ // next slot is going to be a free slot.
+ size_t slot_candidate =
+ (g_last_assigned_slot + 1 + i) % kThreadLocalStorageSize;
+ if (g_tls_metadata[slot_candidate].status == TlsStatus::FREE) {
+ g_tls_metadata[slot_candidate].status = TlsStatus::IN_USE;
+ g_tls_metadata[slot_candidate].destructor = destructor;
+ g_last_assigned_slot = slot_candidate;
+ DCHECK_EQ(kInvalidSlotValue, slot_);
+ slot_ = slot_candidate;
+ version_ = g_tls_metadata[slot_candidate].version;
+ break;
+ }
+ }
+ }
+ CHECK_NE(slot_, kInvalidSlotValue);
+ CHECK_LT(slot_, kThreadLocalStorageSize);
+}
+
+void ThreadLocalStorage::Slot::Free() {
+ DCHECK_NE(slot_, kInvalidSlotValue);
+ DCHECK_LT(slot_, kThreadLocalStorageSize);
+ {
+ base::AutoLock auto_lock(*GetTLSMetadataLock());
+ g_tls_metadata[slot_].status = TlsStatus::FREE;
+ g_tls_metadata[slot_].destructor = nullptr;
+ ++(g_tls_metadata[slot_].version);
+ }
+ slot_ = kInvalidSlotValue;
+}
+
+void* ThreadLocalStorage::Slot::Get() const {
+ TlsVectorEntry* tls_data = nullptr;
+ const TlsVectorState state = GetTlsVectorStateAndValue(
+ base::subtle::NoBarrier_Load(&g_native_tls_key), &tls_data);
+ DCHECK_NE(state, TlsVectorState::kDestroyed);
+ if (!tls_data)
+ return nullptr;
+ DCHECK_NE(slot_, kInvalidSlotValue);
+ DCHECK_LT(slot_, kThreadLocalStorageSize);
+ // Version mismatches means this slot was previously freed.
+ if (tls_data[slot_].version != version_)
+ return nullptr;
+ return tls_data[slot_].data;
+}
+
+void ThreadLocalStorage::Slot::Set(void* value) {
+ TlsVectorEntry* tls_data = nullptr;
+ const TlsVectorState state = GetTlsVectorStateAndValue(
+ base::subtle::NoBarrier_Load(&g_native_tls_key), &tls_data);
+ DCHECK_NE(state, TlsVectorState::kDestroyed);
+ if (!tls_data) {
+ if (!value)
+ return;
+ tls_data = ConstructTlsVector();
+ }
+ DCHECK_NE(slot_, kInvalidSlotValue);
+ DCHECK_LT(slot_, kThreadLocalStorageSize);
+ tls_data[slot_].data = value;
+ tls_data[slot_].version = version_;
+}
+
+ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
+ Initialize(destructor);
+}
+
+ThreadLocalStorage::Slot::~Slot() {
+ Free();
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/thread_local_storage.h b/security/sandbox/chromium/base/threading/thread_local_storage.h
new file mode 100644
index 0000000000..73b845ef56
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_local_storage.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+
+#include <stdint.h>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_types.h"
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <pthread.h>
+#endif
+
+namespace ui {
+class TLSDestructionCheckerForX11;
+}
+
+namespace base {
+
+class SamplingHeapProfiler;
+
+namespace debug {
+class GlobalActivityTracker;
+} // namespace debug
+
+namespace trace_event {
+class MallocDumpProvider;
+} // namespace trace_event
+
+namespace internal {
+
+class ThreadLocalStorageTestInternal;
+
+// WARNING: You should *NOT* use this class directly.
+// PlatformThreadLocalStorage is a low-level abstraction of the OS's TLS
+// interface. Instead, you should use one of the following:
+// * ThreadLocalBoolean (from thread_local.h) for booleans.
+// * ThreadLocalPointer (from thread_local.h) for pointers.
+// * ThreadLocalStorage::StaticSlot/Slot for more direct control of the slot.
+class BASE_EXPORT PlatformThreadLocalStorage {
+ public:
+
+#if defined(OS_WIN)
+ typedef unsigned long TLSKey;
+ enum : unsigned { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ typedef pthread_key_t TLSKey;
+ // The following is a "reserved key" which is used in our generic Chromium
+ // ThreadLocalStorage implementation. We expect that an OS will not return
+ // such a key, but if it is returned (i.e., the OS tries to allocate it) we
+ // will just request another key.
+ enum { TLS_KEY_OUT_OF_INDEXES = 0x7FFFFFFF };
+#endif
+
+ // The following methods need to be supported on each OS platform, so that
+ // the Chromium ThreadLocalStore functionality can be constructed.
+ // Chromium will use these methods to acquire a single OS slot, and then use
+ // that to support a much larger number of Chromium slots (independent of the
+ // OS restrictions).
+ // The following returns true if it successfully is able to return an OS
+ // key in |key|.
+ static bool AllocTLS(TLSKey* key);
+ // Note: FreeTLS() doesn't have to be called, it is fine with this leak, OS
+ // might not reuse released slot, you might just reset the TLS value with
+ // SetTLSValue().
+ static void FreeTLS(TLSKey key);
+ static void SetTLSValue(TLSKey key, void* value);
+ static void* GetTLSValue(TLSKey key) {
+#if defined(OS_WIN)
+ return TlsGetValue(key);
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ return pthread_getspecific(key);
+#endif
+ }
+
+ // Each platform (OS implementation) is required to call this method on each
+ // terminating thread when the thread is about to terminate. This method
+ // will then call all registered destructors for slots in Chromium
+ // ThreadLocalStorage, until there are no slot values remaining as having
+ // been set on this thread.
+ // Destructors may end up being called multiple times on a terminating
+ // thread, as other destructors may re-set slots that were previously
+ // destroyed.
+#if defined(OS_WIN)
+ // Since Windows which doesn't support TLS destructor, the implementation
+ // should use GetTLSValue() to retrieve the value of TLS slot.
+ static void OnThreadExit();
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // |Value| is the data stored in TLS slot, The implementation can't use
+ // GetTLSValue() to retrieve the value of slot as it has already been reset
+ // in Posix.
+ static void OnThreadExit(void* value);
+#endif
+};
+
+} // namespace internal
+
+// Wrapper for thread local storage. This class doesn't do much except provide
+// an API for portability.
+class BASE_EXPORT ThreadLocalStorage {
+ public:
+ // Prototype for the TLS destructor function, which can be optionally used to
+ // cleanup thread local storage on thread exit. 'value' is the data that is
+ // stored in thread local storage.
+ typedef void (*TLSDestructorFunc)(void* value);
+
+ // A key representing one value stored in TLS. Use as a class member or a
+ // local variable. If you need a static storage duration variable, use the
+ // following pattern with a NoDestructor<Slot>:
+ // void MyDestructorFunc(void* value);
+ // ThreadLocalStorage::Slot& ImportantContentTLS() {
+ // static NoDestructor<ThreadLocalStorage::Slot> important_content_tls(
+ // &MyDestructorFunc);
+ // return *important_content_tls;
+ // }
+ class BASE_EXPORT Slot final {
+ public:
+ // |destructor| is a pointer to a function to perform per-thread cleanup of
+ // this object. If set to nullptr, no cleanup is done for this TLS slot.
+ explicit Slot(TLSDestructorFunc destructor = nullptr);
+ // If a destructor was set for this slot, removes the destructor so that
+ // remaining threads exiting will not free data.
+ ~Slot();
+
+ // Get the thread-local value stored in slot 'slot'.
+ // Values are guaranteed to initially be zero.
+ void* Get() const;
+
+ // Set the thread-local value stored in slot 'slot' to
+ // value 'value'.
+ void Set(void* value);
+
+ private:
+ void Initialize(TLSDestructorFunc destructor);
+ void Free();
+
+ static constexpr int kInvalidSlotValue = -1;
+ int slot_ = kInvalidSlotValue;
+ uint32_t version_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(Slot);
+ };
+
+ private:
+ // In most cases, most callers should not need access to HasBeenDestroyed().
+ // If you are working in code that runs during thread destruction, contact the
+ // base OWNERs for advice and then make a friend request.
+ //
+ // Returns |true| if Chrome's implementation of TLS is being or has been
+ // destroyed during thread destruction. Attempting to call Slot::Get() during
+ // destruction is disallowed and will hit a DCHECK. Any code that relies on
+ // TLS during thread destruction must first check this method before calling
+ // Slot::Get().
+ friend class SequenceCheckerImpl;
+ friend class SamplingHeapProfiler;
+ friend class ThreadCheckerImpl;
+ friend class internal::ThreadLocalStorageTestInternal;
+ friend class trace_event::MallocDumpProvider;
+ friend class debug::GlobalActivityTracker;
+ friend class ui::TLSDestructionCheckerForX11;
+ static bool HasBeenDestroyed();
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_LOCAL_STORAGE_H_
diff --git a/security/sandbox/chromium/base/threading/thread_local_storage_posix.cc b/security/sandbox/chromium/base/threading/thread_local_storage_posix.cc
new file mode 100644
index 0000000000..89edeee1d2
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_local_storage_posix.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+bool PlatformThreadLocalStorage::AllocTLS(TLSKey* key) {
+ return !pthread_key_create(key,
+ base::internal::PlatformThreadLocalStorage::OnThreadExit);
+}
+
+void PlatformThreadLocalStorage::FreeTLS(TLSKey key) {
+ int ret = pthread_key_delete(key);
+ DCHECK_EQ(ret, 0);
+}
+
+void PlatformThreadLocalStorage::SetTLSValue(TLSKey key, void* value) {
+ int ret = pthread_setspecific(key, value);
+ DCHECK_EQ(ret, 0);
+}
+
+} // namespace internal
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/threading/thread_local_storage_win.cc b/security/sandbox/chromium/base/threading/thread_local_storage_win.cc
new file mode 100644
index 0000000000..a9aec31da5
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_local_storage_win.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_local_storage.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+bool PlatformThreadLocalStorage::AllocTLS(TLSKey* key) {
+ TLSKey value = TlsAlloc();
+ if (value != TLS_OUT_OF_INDEXES) {
+ *key = value;
+ return true;
+ }
+ return false;
+}
+
+void PlatformThreadLocalStorage::FreeTLS(TLSKey key) {
+ BOOL ret = TlsFree(key);
+ DCHECK(ret);
+}
+
+void PlatformThreadLocalStorage::SetTLSValue(TLSKey key, void* value) {
+ BOOL ret = TlsSetValue(key, value);
+ DCHECK(ret);
+}
+
+} // namespace internal
+
+} // namespace base
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives. So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from http://www.codeproject.com/threads/tls.asp
+// and it works for VC++ 7.0 and later.
+
+// Force a reference to _tls_used to make the linker create the TLS directory
+// if it's not already there. (e.g. if __declspec(thread) is not used).
+// Force a reference to p_thread_callback_base to prevent whole program
+// optimization from discarding the variable.
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:p_thread_callback_base")
+
+#else // _WIN64
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_p_thread_callback_base")
+
+#endif // _WIN64
+
+// Static callback function to call with each thread termination.
+void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved) {
+ // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
+ // and on W2K and W2K3. So don't assume it is sent.
+ if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason)
+ base::internal::PlatformThreadLocalStorage::OnThreadExit();
+}
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// By implicitly loaded, I mean that it is directly referenced by the main EXE
+// or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
+// implicitly loaded.
+//
+// See VC\crt\src\tlssup.c for reference.
+
+// extern "C" suppresses C++ name mangling so we know the symbol name for the
+// linker /INCLUDE:symbol pragma above.
+extern "C" {
+// The linker must not discard p_thread_callback_base. (We force a reference
+// to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If
+// this variable is discarded, the OnThreadExit function will never be called.
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback_base;
+const PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+
+#else // _WIN64
+
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma data_seg()
+
+#endif // _WIN64
+} // extern "C"
diff --git a/security/sandbox/chromium/base/threading/thread_restrictions.cc b/security/sandbox/chromium/base/threading/thread_restrictions.cc
new file mode 100644
index 0000000000..75c37eab4f
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_restrictions.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_restrictions.h"
+
+#if DCHECK_IS_ON()
+
+#include "base/debug/stack_trace.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_local.h"
+#include "build/build_config.h"
+
+namespace base {
+
+std::ostream& operator<<(std::ostream&out, const ThreadLocalBoolean& tl) {
+ out << "currently set to " << (tl.Get() ? "true" : "false");
+ return out;
+}
+
+namespace {
+
+#if defined(OS_NACL) || defined(OS_ANDROID)
+// NaCL doesn't support stack sampling and Android is slow at stack
+// sampling and this causes timeouts (crbug.com/959139).
+using ThreadLocalBooleanWithStacks = ThreadLocalBoolean;
+#else
+class ThreadLocalBooleanWithStacks {
+ public:
+ ThreadLocalBooleanWithStacks() = default;
+
+ bool Get() const { return bool_.Get(); }
+
+ void Set(bool val) {
+ stack_.Set(std::make_unique<debug::StackTrace>());
+ bool_.Set(val);
+ }
+
+ friend std::ostream& operator<<(std::ostream& out,
+ const ThreadLocalBooleanWithStacks& tl) {
+ out << tl.bool_ << " by ";
+
+ if (!tl.stack_.Get())
+ return out << "default value\n";
+ out << "\n";
+ tl.stack_.Get()->OutputToStream(&out);
+ return out;
+ }
+
+ private:
+ ThreadLocalBoolean bool_;
+ ThreadLocalOwnedPointer<debug::StackTrace> stack_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLocalBooleanWithStacks);
+};
+#endif // defined(OS_NACL)
+
+LazyInstance<ThreadLocalBooleanWithStacks>::Leaky g_blocking_disallowed =
+ LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBooleanWithStacks>::Leaky g_singleton_disallowed =
+ LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBooleanWithStacks>::Leaky
+ g_base_sync_primitives_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBooleanWithStacks>::Leaky
+ g_cpu_intensive_work_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+namespace internal {
+
+void AssertBlockingAllowed() {
+ DCHECK(!g_blocking_disallowed.Get().Get())
+ << "Function marked as blocking was called from a scope that disallows "
+ "blocking! If this task is running inside the ThreadPool, it needs "
+ "to have MayBlock() in its TaskTraits. Otherwise, consider making "
+ "this blocking work asynchronous or, as a last resort, you may use "
+ "ScopedAllowBlocking (see its documentation for best practices).\n"
+ << "g_blocking_disallowed " << g_blocking_disallowed.Get();
+}
+
+} // namespace internal
+
+void DisallowBlocking() {
+ g_blocking_disallowed.Get().Set(true);
+}
+
+ScopedDisallowBlocking::ScopedDisallowBlocking()
+ : was_disallowed_(g_blocking_disallowed.Get().Get()) {
+ g_blocking_disallowed.Get().Set(true);
+}
+
+ScopedDisallowBlocking::~ScopedDisallowBlocking() {
+ DCHECK(g_blocking_disallowed.Get().Get());
+ g_blocking_disallowed.Get().Set(was_disallowed_);
+}
+
+ScopedAllowBlocking::ScopedAllowBlocking()
+ : was_disallowed_(g_blocking_disallowed.Get().Get()) {
+ g_blocking_disallowed.Get().Set(false);
+}
+
+ScopedAllowBlocking::~ScopedAllowBlocking() {
+ DCHECK(!g_blocking_disallowed.Get().Get());
+ g_blocking_disallowed.Get().Set(was_disallowed_);
+}
+
+void DisallowBaseSyncPrimitives() {
+ g_base_sync_primitives_disallowed.Get().Set(true);
+}
+
+ScopedAllowBaseSyncPrimitives::ScopedAllowBaseSyncPrimitives()
+ : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
+ DCHECK(!g_blocking_disallowed.Get().Get())
+ << "To allow //base sync primitives in a scope where blocking is "
+ "disallowed use ScopedAllowBaseSyncPrimitivesOutsideBlockingScope.\n"
+ << "g_blocking_disallowed " << g_blocking_disallowed.Get();
+ g_base_sync_primitives_disallowed.Get().Set(false);
+}
+
+ScopedAllowBaseSyncPrimitives::~ScopedAllowBaseSyncPrimitives() {
+ DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
+ g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
+}
+
+ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
+ ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()
+ : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
+ g_base_sync_primitives_disallowed.Get().Set(false);
+}
+
+ScopedAllowBaseSyncPrimitivesOutsideBlockingScope::
+ ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope() {
+ DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
+ g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
+}
+
+ScopedAllowBaseSyncPrimitivesForTesting::
+ ScopedAllowBaseSyncPrimitivesForTesting()
+ : was_disallowed_(g_base_sync_primitives_disallowed.Get().Get()) {
+ g_base_sync_primitives_disallowed.Get().Set(false);
+}
+
+ScopedAllowBaseSyncPrimitivesForTesting::
+ ~ScopedAllowBaseSyncPrimitivesForTesting() {
+ DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
+ g_base_sync_primitives_disallowed.Get().Set(was_disallowed_);
+}
+
+ScopedAllowUnresponsiveTasksForTesting::ScopedAllowUnresponsiveTasksForTesting()
+ : was_disallowed_base_sync_(g_base_sync_primitives_disallowed.Get().Get()),
+ was_disallowed_blocking_(g_blocking_disallowed.Get().Get()),
+ was_disallowed_cpu_(g_cpu_intensive_work_disallowed.Get().Get()) {
+ g_base_sync_primitives_disallowed.Get().Set(false);
+ g_blocking_disallowed.Get().Set(false);
+ g_cpu_intensive_work_disallowed.Get().Set(false);
+}
+
+ScopedAllowUnresponsiveTasksForTesting::
+ ~ScopedAllowUnresponsiveTasksForTesting() {
+ DCHECK(!g_base_sync_primitives_disallowed.Get().Get());
+ DCHECK(!g_blocking_disallowed.Get().Get());
+ DCHECK(!g_cpu_intensive_work_disallowed.Get().Get());
+ g_base_sync_primitives_disallowed.Get().Set(was_disallowed_base_sync_);
+ g_blocking_disallowed.Get().Set(was_disallowed_blocking_);
+ g_cpu_intensive_work_disallowed.Get().Set(was_disallowed_cpu_);
+}
+
+namespace internal {
+
+void AssertBaseSyncPrimitivesAllowed() {
+ DCHECK(!g_base_sync_primitives_disallowed.Get().Get())
+ << "Waiting on a //base sync primitive is not allowed on this thread to "
+ "prevent jank and deadlock. If waiting on a //base sync primitive is "
+ "unavoidable, do it within the scope of a "
+ "ScopedAllowBaseSyncPrimitives. If in a test, "
+ "use ScopedAllowBaseSyncPrimitivesForTesting.\n"
+ << "g_base_sync_primitives_disallowed "
+ << g_base_sync_primitives_disallowed.Get()
+ << "It can be useful to know that g_blocking_disallowed is "
+ << g_blocking_disallowed.Get();
+}
+
+void ResetThreadRestrictionsForTesting() {
+ g_blocking_disallowed.Get().Set(false);
+ g_singleton_disallowed.Get().Set(false);
+ g_base_sync_primitives_disallowed.Get().Set(false);
+ g_cpu_intensive_work_disallowed.Get().Set(false);
+}
+
+} // namespace internal
+
+void AssertLongCPUWorkAllowed() {
+ DCHECK(!g_cpu_intensive_work_disallowed.Get().Get())
+ << "Function marked as CPU intensive was called from a scope that "
+ "disallows this kind of work! Consider making this work "
+ "asynchronous.\n"
+ << "g_cpu_intensive_work_disallowed "
+ << g_cpu_intensive_work_disallowed.Get();
+}
+
+void DisallowUnresponsiveTasks() {
+ DisallowBlocking();
+ DisallowBaseSyncPrimitives();
+ g_cpu_intensive_work_disallowed.Get().Set(true);
+}
+
+ThreadRestrictions::ScopedAllowIO::ScopedAllowIO()
+ : was_allowed_(SetIOAllowed(true)) {}
+
+ThreadRestrictions::ScopedAllowIO::~ScopedAllowIO() {
+ SetIOAllowed(was_allowed_);
+}
+
+// static
+bool ThreadRestrictions::SetIOAllowed(bool allowed) {
+ bool previous_disallowed = g_blocking_disallowed.Get().Get();
+ g_blocking_disallowed.Get().Set(!allowed);
+ return !previous_disallowed;
+}
+
+// static
+bool ThreadRestrictions::SetSingletonAllowed(bool allowed) {
+ bool previous_disallowed = g_singleton_disallowed.Get().Get();
+ g_singleton_disallowed.Get().Set(!allowed);
+ return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertSingletonAllowed() {
+ DCHECK(!g_singleton_disallowed.Get().Get())
+ << "LazyInstance/Singleton is not allowed to be used on this thread. "
+ "Most likely it's because this thread is not joinable (or the current "
+ "task is running with TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN "
+ "semantics), so AtExitManager may have deleted the object on "
+ "shutdown, leading to a potential shutdown crash. If you need to use "
+ "the object from this context, it'll have to be updated to use Leaky "
+ "traits.\n"
+ << "g_singleton_disallowed " << g_singleton_disallowed.Get();
+}
+
+// static
+void ThreadRestrictions::DisallowWaiting() {
+ DisallowBaseSyncPrimitives();
+}
+
+bool ThreadRestrictions::SetWaitAllowed(bool allowed) {
+ bool previous_disallowed = g_base_sync_primitives_disallowed.Get().Get();
+ g_base_sync_primitives_disallowed.Get().Set(!allowed);
+ return !previous_disallowed;
+}
+
+} // namespace base
+
+#endif // DCHECK_IS_ON()
diff --git a/security/sandbox/chromium/base/threading/thread_restrictions.h b/security/sandbox/chromium/base/threading/thread_restrictions.h
new file mode 100644
index 0000000000..55047c5b40
--- /dev/null
+++ b/security/sandbox/chromium/base/threading/thread_restrictions.h
@@ -0,0 +1,680 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_RESTRICTIONS_H_
+#define BASE_THREADING_THREAD_RESTRICTIONS_H_
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
+//
+// Overview:
+// This file exposes functions to ban and allow certain slow operations
+// on a per-thread basis. To annotate *usage* of such slow operations, refer to
+// scoped_blocking_call.h instead.
+//
+// Specific allowances that can be controlled in this file are:
+// - Blocking call: Refers to any call that causes the calling thread to wait
+// off-CPU. It includes but is not limited to calls that wait on synchronous
+// file I/O operations: read or write a file from disk, interact with a pipe
+// or a socket, rename or delete a file, enumerate files in a directory, etc.
+// Acquiring a low contention lock is not considered a blocking call.
+//
+// - Waiting on a //base sync primitive: Refers to calling one of these methods:
+// - base::WaitableEvent::*Wait*
+// - base::ConditionVariable::*Wait*
+// - base::Process::WaitForExit*
+//
+// - Long CPU work: Refers to any code that takes more than 100 ms to
+// run when there is no CPU contention and no hard page faults and therefore,
+// is not suitable to run on a thread required to keep the browser responsive
+// (where jank could be visible to the user).
+//
+// The following disallowance functions are offered:
+// - DisallowBlocking(): Disallows blocking calls on the current thread.
+// - DisallowBaseSyncPrimitives(): Disallows waiting on a //base sync primitive
+// on the current thread.
+// - DisallowUnresponsiveTasks() Disallows blocking calls, waiting on a //base
+// sync primitive, and long cpu work on the current thread.
+//
+// In addition, scoped-allowance mechanisms are offered to make an exception
+// within a scope for a behavior that is normally disallowed.
+// - ScopedAllowBlocking(ForTesting): Allows blocking calls.
+// - ScopedAllowBaseSyncPrimitives(ForTesting)(OutsideBlockingScope): Allow
+// waiting on a //base sync primitive. The OutsideBlockingScope suffix allows
+// uses in a scope where blocking is also disallowed.
+//
+// Avoid using allowances outside of unit tests. In unit tests, use allowances
+// with the suffix "ForTesting".
+//
+// Prefer making blocking calls from tasks posted to base::ThreadPoolInstance
+// with base::MayBlock().
+//
+// Instead of waiting on a WaitableEvent or a ConditionVariable, prefer putting
+// the work that should happen after the wait in a continuation callback and
+// post it from where the WaitableEvent or ConditionVariable would have been
+// signaled. If something needs to be scheduled after many tasks have executed,
+// use base::BarrierClosure.
+//
+// On Windows, join processes asynchronously using base::win::ObjectWatcher.
+//
+// Where unavoidable, put ScopedAllow* instances in the narrowest scope possible
+// in the caller making the blocking call but no further down. For example: if a
+// Cleanup() method needs to do a blocking call, document Cleanup() as blocking
+// and add a ScopedAllowBlocking instance in callers that can't avoid making
+// this call from a context where blocking is banned, as such:
+//
+// void Client::MyMethod() {
+// (...)
+// {
+// // Blocking is okay here because XYZ.
+// ScopedAllowBlocking allow_blocking;
+// my_foo_->Cleanup();
+// }
+// (...)
+// }
+//
+// // This method can block.
+// void Foo::Cleanup() {
+// // Do NOT add the ScopedAllowBlocking in Cleanup() directly as that hides
+// // its blocking nature from unknowing callers and defeats the purpose of
+// // these checks.
+// FlushStateToDisk();
+// }
+//
+// Note: In rare situations where the blocking call is an implementation detail
+// (i.e. the impl makes a call that invokes AssertBlockingAllowed() but it
+// somehow knows that in practice this will not block), it might be okay to hide
+// the ScopedAllowBlocking instance in the impl with a comment explaining why
+// that's okay.
+
+class BrowserProcessImpl;
+class HistogramSynchronizer;
+class KeyStorageLinux;
+class NativeBackendKWallet;
+class NativeDesktopMediaList;
+class StartupTimeBomb;
+
+namespace android_webview {
+class AwFormDatabaseService;
+class CookieManager;
+class ScopedAllowInitGLBindings;
+class VizCompositorThreadRunnerWebView;
+}
+namespace audio {
+class OutputDevice;
+}
+namespace blink {
+class RTCVideoDecoderAdapter;
+class RTCVideoEncoder;
+class SourceStream;
+class VideoFrameResourceProvider;
+class WorkerThread;
+namespace scheduler {
+class WorkerThread;
+}
+}
+namespace cc {
+class CompletionEvent;
+class TileTaskManagerImpl;
+}
+namespace chromeos {
+class BlockingMethodCaller;
+namespace system {
+class StatisticsProviderImpl;
+}
+}
+namespace chrome_browser_net {
+class Predictor;
+}
+namespace chrome_cleaner {
+class SystemReportComponent;
+}
+namespace content {
+class BrowserGpuChannelHostFactory;
+class BrowserMainLoop;
+class BrowserProcessSubThread;
+class BrowserShutdownProfileDumper;
+class BrowserTestBase;
+class CategorizedWorkerPool;
+class DesktopCaptureDevice;
+class InProcessUtilityThread;
+class NestedMessagePumpAndroid;
+class RenderProcessHostImpl;
+class RenderWidgetHostViewMac;
+class RTCVideoDecoder;
+class SandboxHostLinux;
+class ScopedAllowWaitForDebugURL;
+class ServiceWorkerContextClient;
+class SoftwareOutputDeviceMus;
+class SynchronousCompositor;
+class SynchronousCompositorHost;
+class SynchronousCompositorSyncCallBridge;
+class TextInputClientMac;
+class WebContentsViewMac;
+} // namespace content
+namespace cronet {
+class CronetPrefsManager;
+class CronetURLRequestContext;
+} // namespace cronet
+namespace dbus {
+class Bus;
+}
+namespace disk_cache {
+class BackendImpl;
+class InFlightIO;
+}
+namespace functions {
+class ExecScriptScopedAllowBaseSyncPrimitives;
+}
+namespace history_report {
+class HistoryReportJniBridge;
+}
+namespace gpu {
+class GpuChannelHost;
+}
+namespace leveldb_env {
+class DBTracker;
+}
+namespace media {
+class AudioInputDevice;
+class AudioOutputDevice;
+class BlockingUrlProtocol;
+class PaintCanvasVideoRenderer;
+}
+namespace memory_instrumentation {
+class OSMetrics;
+}
+namespace midi {
+class TaskService; // https://crbug.com/796830
+}
+namespace module_installer {
+class ScopedAllowModulePakLoad;
+}
+namespace mojo {
+class CoreLibraryInitializer;
+class SyncCallRestrictions;
+namespace core {
+class ScopedIPCSupport;
+}
+}
+namespace printing {
+class PrintJobWorker;
+class PrinterQuery;
+}
+namespace rlz_lib {
+class FinancialPing;
+}
+namespace syncer {
+class GetLocalChangesRequest;
+class HttpBridge;
+class ModelSafeWorker;
+}
+namespace ui {
+class CommandBufferClientImpl;
+class CommandBufferLocal;
+class GpuState;
+class MaterialDesignController;
+}
+namespace weblayer {
+class WebLayerPathProvider;
+}
+namespace net {
+class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
+class MultiThreadedProxyResolverScopedAllowJoinOnIO;
+class NetworkChangeNotifierMac;
+class NetworkConfigWatcherMacThread;
+namespace internal {
+class AddressTrackerLinux;
+}
+}
+
+namespace proxy_resolver {
+class ScopedAllowThreadJoinForProxyResolverV8Tracing;
+}
+
+namespace remoting {
+class AutoThread;
+namespace protocol {
+class ScopedAllowThreadJoinForWebRtcTransport;
+}
+}
+
+namespace resource_coordinator {
+class TabManagerDelegate;
+}
+
+namespace service_manager {
+class ServiceProcessLauncher;
+}
+
+namespace shell_integration_linux {
+class LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
+}
+
+namespace ui {
+class WindowResizeHelperMac;
+}
+
+namespace viz {
+class HostGpuMemoryBufferManager;
+}
+
+namespace vr {
+class VrShell;
+}
+
+namespace web {
+class WebMainLoop;
+class WebSubThread;
+}
+
+namespace weblayer {
+class ProfileImpl;
+}
+
+namespace webrtc {
+class DesktopConfigurationMonitor;
+}
+
+namespace base {
+
+namespace sequence_manager {
+namespace internal {
+class TaskQueueImpl;
+}
+} // namespace sequence_manager
+
+namespace android {
+class JavaHandlerThread;
+}
+
+namespace internal {
+class JobTaskSource;
+class TaskTracker;
+}
+
+class AdjustOOMScoreHelper;
+class FileDescriptorWatcher;
+class GetAppOutputScopedAllowBaseSyncPrimitives;
+class ScopedAllowThreadRecallForStackSamplingProfiler;
+class SimpleThread;
+class StackSamplingProfiler;
+class Thread;
+
+#if DCHECK_IS_ON()
+#define INLINE_IF_DCHECK_IS_OFF BASE_EXPORT
+#define EMPTY_BODY_IF_DCHECK_IS_OFF
+#else
+#define INLINE_IF_DCHECK_IS_OFF inline
+
+// The static_assert() eats follow-on semicolons. `= default` would work
+// too, but it makes clang realize that all the Scoped classes are no-ops in
+// non-dcheck builds and it starts emitting many -Wunused-variable warnings.
+#define EMPTY_BODY_IF_DCHECK_IS_OFF \
+ {} \
+ static_assert(true, "")
+#endif
+
+namespace internal {
+
+// Asserts that blocking calls are allowed in the current scope. This is an
+// internal call, external code should use ScopedBlockingCall instead, which
+// serves as a precise annotation of the scope that may/will block.
+INLINE_IF_DCHECK_IS_OFF void AssertBlockingAllowed()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+} // namespace internal
+
+// Disallows blocking on the current thread.
+INLINE_IF_DCHECK_IS_OFF void DisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+// Disallows blocking calls within its scope.
+class BASE_EXPORT ScopedDisallowBlocking {
+ public:
+ ScopedDisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+ ~ScopedDisallowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+ private:
+#if DCHECK_IS_ON()
+ const bool was_disallowed_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDisallowBlocking);
+};
+
+class BASE_EXPORT ScopedAllowBlocking {
+ private:
+ FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest, ScopedAllowBlocking);
+ friend class ScopedAllowBlockingForTesting;
+
+ // This can only be instantiated by friends. Use ScopedAllowBlockingForTesting
+ // in unit tests to avoid the friend requirement.
+ friend class AdjustOOMScoreHelper;
+ friend class android_webview::ScopedAllowInitGLBindings;
+ friend class content::BrowserProcessSubThread;
+ friend class content::RenderWidgetHostViewMac; // http://crbug.com/121917
+ friend class content::WebContentsViewMac;
+ friend class cronet::CronetPrefsManager;
+ friend class cronet::CronetURLRequestContext;
+ friend class memory_instrumentation::OSMetrics;
+ friend class module_installer::ScopedAllowModulePakLoad;
+ friend class mojo::CoreLibraryInitializer;
+ friend class printing::PrintJobWorker;
+ friend class resource_coordinator::TabManagerDelegate; // crbug.com/778703
+ friend class ui::MaterialDesignController;
+ friend class web::WebSubThread;
+ friend class StackSamplingProfiler;
+ friend class weblayer::ProfileImpl;
+ friend class content::RenderProcessHostImpl;
+ friend class weblayer::WebLayerPathProvider;
+
+ ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+ ~ScopedAllowBlocking() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+#if DCHECK_IS_ON()
+ const bool was_disallowed_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowBlocking);
+};
+
+class ScopedAllowBlockingForTesting {
+ public:
+ ScopedAllowBlockingForTesting() {}
+ ~ScopedAllowBlockingForTesting() {}
+
+ private:
+#if DCHECK_IS_ON()
+ ScopedAllowBlocking scoped_allow_blocking_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowBlockingForTesting);
+};
+
+INLINE_IF_DCHECK_IS_OFF void DisallowBaseSyncPrimitives()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+class BASE_EXPORT ScopedAllowBaseSyncPrimitives {
+ private:
+ // This can only be instantiated by friends. Use
+ // ScopedAllowBaseSyncPrimitivesForTesting in unit tests to avoid the friend
+ // requirement.
+ FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
+ ScopedAllowBaseSyncPrimitives);
+ FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
+ ScopedAllowBaseSyncPrimitivesResetsState);
+ FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
+ ScopedAllowBaseSyncPrimitivesWithBlockingDisallowed);
+
+ // Allowed usage:
+ friend class SimpleThread;
+ friend class base::GetAppOutputScopedAllowBaseSyncPrimitives;
+ friend class blink::SourceStream;
+ friend class blink::WorkerThread;
+ friend class blink::scheduler::WorkerThread;
+ friend class chrome_cleaner::SystemReportComponent;
+ friend class content::BrowserMainLoop;
+ friend class content::BrowserProcessSubThread;
+ friend class content::ServiceWorkerContextClient;
+ friend class functions::ExecScriptScopedAllowBaseSyncPrimitives;
+ friend class history_report::HistoryReportJniBridge;
+ friend class internal::TaskTracker;
+ friend class leveldb_env::DBTracker;
+ friend class media::BlockingUrlProtocol;
+ friend class mojo::core::ScopedIPCSupport;
+ friend class net::MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
+ friend class rlz_lib::FinancialPing;
+ friend class shell_integration_linux::
+ LaunchXdgUtilityScopedAllowBaseSyncPrimitives;
+ friend class syncer::HttpBridge;
+ friend class syncer::GetLocalChangesRequest;
+ friend class syncer::ModelSafeWorker;
+ friend class webrtc::DesktopConfigurationMonitor;
+
+ // Usage that should be fixed:
+ friend class ::NativeBackendKWallet; // http://crbug.com/125331
+ friend class ::chromeos::system::
+ StatisticsProviderImpl; // http://crbug.com/125385
+ friend class content::TextInputClientMac; // http://crbug.com/121917
+ friend class blink::VideoFrameResourceProvider; // http://crbug.com/878070
+
+ ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
+ ~ScopedAllowBaseSyncPrimitives() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+#if DCHECK_IS_ON()
+ const bool was_disallowed_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitives);
+};
+
+class BASE_EXPORT ScopedAllowBaseSyncPrimitivesOutsideBlockingScope {
+ private:
+ // This can only be instantiated by friends. Use
+ // ScopedAllowBaseSyncPrimitivesForTesting in unit tests to avoid the friend
+ // requirement.
+ FRIEND_TEST_ALL_PREFIXES(ThreadRestrictionsTest,
+ ScopedAllowBaseSyncPrimitivesOutsideBlockingScope);
+ FRIEND_TEST_ALL_PREFIXES(
+ ThreadRestrictionsTest,
+ ScopedAllowBaseSyncPrimitivesOutsideBlockingScopeResetsState);
+
+ // Allowed usage:
+ friend class ::BrowserProcessImpl; // http://crbug.com/125207
+ friend class ::KeyStorageLinux;
+ friend class ::NativeDesktopMediaList;
+ friend class ::StartupTimeBomb;
+ friend class android::JavaHandlerThread;
+ friend class android_webview::
+ AwFormDatabaseService; // http://crbug.com/904431
+ friend class android_webview::CookieManager;
+ friend class android_webview::VizCompositorThreadRunnerWebView;
+ friend class audio::OutputDevice;
+ friend class base::sequence_manager::internal::TaskQueueImpl;
+ friend class base::FileDescriptorWatcher;
+ friend class base::internal::JobTaskSource;
+ friend class base::ScopedAllowThreadRecallForStackSamplingProfiler;
+ friend class base::StackSamplingProfiler;
+ friend class blink::RTCVideoDecoderAdapter;
+ friend class blink::RTCVideoEncoder;
+ friend class cc::TileTaskManagerImpl;
+ friend class content::CategorizedWorkerPool;
+ friend class content::DesktopCaptureDevice;
+ friend class content::InProcessUtilityThread;
+ friend class content::RTCVideoDecoder;
+ friend class content::SandboxHostLinux;
+ friend class content::ScopedAllowWaitForDebugURL;
+ friend class content::SynchronousCompositor;
+ friend class content::SynchronousCompositorHost;
+ friend class content::SynchronousCompositorSyncCallBridge;
+ friend class media::AudioInputDevice;
+ friend class media::AudioOutputDevice;
+ friend class media::PaintCanvasVideoRenderer;
+ friend class mojo::SyncCallRestrictions;
+ friend class net::NetworkConfigWatcherMacThread;
+ friend class viz::HostGpuMemoryBufferManager;
+ friend class vr::VrShell;
+
+ // Usage that should be fixed:
+ friend class ::chromeos::BlockingMethodCaller; // http://crbug.com/125360
+ friend class base::Thread; // http://crbug.com/918039
+ friend class cc::CompletionEvent; // http://crbug.com/902653
+ friend class content::
+ BrowserGpuChannelHostFactory; // http://crbug.com/125248
+ friend class dbus::Bus; // http://crbug.com/125222
+ friend class disk_cache::BackendImpl; // http://crbug.com/74623
+ friend class disk_cache::InFlightIO; // http://crbug.com/74623
+ friend class gpu::GpuChannelHost; // http://crbug.com/125264
+ friend class remoting::protocol::
+ ScopedAllowThreadJoinForWebRtcTransport; // http://crbug.com/660081
+ friend class midi::TaskService; // https://crbug.com/796830
+ friend class net::internal::AddressTrackerLinux; // http://crbug.com/125097
+ friend class net::
+ MultiThreadedProxyResolverScopedAllowJoinOnIO; // http://crbug.com/69710
+ friend class net::NetworkChangeNotifierMac; // http://crbug.com/125097
+ friend class printing::PrinterQuery; // http://crbug.com/66082
+ friend class proxy_resolver::
+ ScopedAllowThreadJoinForProxyResolverV8Tracing; // http://crbug.com/69710
+ friend class remoting::AutoThread; // https://crbug.com/944316
+ // Not used in production yet, https://crbug.com/844078.
+ friend class service_manager::ServiceProcessLauncher;
+ friend class ui::WindowResizeHelperMac; // http://crbug.com/902829
+
+ ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+ ~ScopedAllowBaseSyncPrimitivesOutsideBlockingScope()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+#if DCHECK_IS_ON()
+ const bool was_disallowed_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitivesOutsideBlockingScope);
+};
+
+class BASE_EXPORT ScopedAllowBaseSyncPrimitivesForTesting {
+ public:
+ ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
+ ~ScopedAllowBaseSyncPrimitivesForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+ private:
+#if DCHECK_IS_ON()
+ const bool was_disallowed_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowBaseSyncPrimitivesForTesting);
+};
+
+// Counterpart to base::DisallowUnresponsiveTasks() for tests to allow them to
+// block their thread after it was banned.
+class BASE_EXPORT ScopedAllowUnresponsiveTasksForTesting {
+ public:
+ ScopedAllowUnresponsiveTasksForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
+ ~ScopedAllowUnresponsiveTasksForTesting() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+ private:
+#if DCHECK_IS_ON()
+ const bool was_disallowed_base_sync_;
+ const bool was_disallowed_blocking_;
+ const bool was_disallowed_cpu_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowUnresponsiveTasksForTesting);
+};
+
+namespace internal {
+
+// Asserts that waiting on a //base sync primitive is allowed in the current
+// scope.
+INLINE_IF_DCHECK_IS_OFF void AssertBaseSyncPrimitivesAllowed()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+// Resets all thread restrictions on the current thread.
+INLINE_IF_DCHECK_IS_OFF void ResetThreadRestrictionsForTesting()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+} // namespace internal
+
+// Asserts that running long CPU work is allowed in the current scope.
+INLINE_IF_DCHECK_IS_OFF void AssertLongCPUWorkAllowed()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+INLINE_IF_DCHECK_IS_OFF void DisallowUnresponsiveTasks()
+ EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+class BASE_EXPORT ThreadRestrictions {
+ public:
+ // Constructing a ScopedAllowIO temporarily allows IO for the current
+ // thread. Doing this is almost certainly always incorrect.
+ //
+ // DEPRECATED. Use ScopedAllowBlocking(ForTesting).
+ class BASE_EXPORT ScopedAllowIO {
+ public:
+ ScopedAllowIO() EMPTY_BODY_IF_DCHECK_IS_OFF;
+ ~ScopedAllowIO() EMPTY_BODY_IF_DCHECK_IS_OFF;
+
+ private:
+#if DCHECK_IS_ON()
+ const bool was_allowed_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
+ };
+
+#if DCHECK_IS_ON()
+ // Set whether the current thread to make IO calls.
+ // Threads start out in the *allowed* state.
+ // Returns the previous value.
+ //
+ // DEPRECATED. Use ScopedAllowBlocking(ForTesting) or ScopedDisallowBlocking.
+ static bool SetIOAllowed(bool allowed);
+
+ // Set whether the current thread can use singletons. Returns the previous
+ // value.
+ static bool SetSingletonAllowed(bool allowed);
+
+ // Check whether the current thread is allowed to use singletons (Singleton /
+ // LazyInstance). DCHECKs if not.
+ static void AssertSingletonAllowed();
+
+ // Disable waiting on the current thread. Threads start out in the *allowed*
+ // state. Returns the previous value.
+ //
+ // DEPRECATED. Use DisallowBaseSyncPrimitives.
+ static void DisallowWaiting();
+#else
+ // Inline the empty definitions of these functions so that they can be
+ // compiled out.
+ static bool SetIOAllowed(bool allowed) { return true; }
+ static bool SetSingletonAllowed(bool allowed) { return true; }
+ static void AssertSingletonAllowed() {}
+ static void DisallowWaiting() {}
+#endif
+
+ private:
+ // DO NOT ADD ANY OTHER FRIEND STATEMENTS.
+ // BEGIN ALLOWED USAGE.
+ friend class content::BrowserMainLoop;
+ friend class content::BrowserShutdownProfileDumper;
+ friend class content::BrowserTestBase;
+ friend class content::ScopedAllowWaitForDebugURL;
+ friend class ::HistogramSynchronizer;
+ friend class internal::TaskTracker;
+ friend class web::WebMainLoop;
+ friend class MessagePumpDefault;
+ friend class PlatformThread;
+ friend class ui::CommandBufferClientImpl;
+ friend class ui::CommandBufferLocal;
+ friend class ui::GpuState;
+
+ // END ALLOWED USAGE.
+ // BEGIN USAGE THAT NEEDS TO BE FIXED.
+ friend class chrome_browser_net::Predictor; // http://crbug.com/78451
+#if !defined(OFFICIAL_BUILD)
+ friend class content::SoftwareOutputDeviceMus; // Interim non-production code
+#endif
+// END USAGE THAT NEEDS TO BE FIXED.
+
+#if DCHECK_IS_ON()
+ // DEPRECATED. Use ScopedAllowBaseSyncPrimitives.
+ static bool SetWaitAllowed(bool allowed);
+#else
+ static bool SetWaitAllowed(bool allowed) { return true; }
+#endif
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions);
+};
+
+#undef INLINE_IF_DCHECK_IS_OFF
+#undef EMPTY_BODY_IF_DCHECK_IS_OFF
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_RESTRICTIONS_H_
diff --git a/security/sandbox/chromium/base/time/time.cc b/security/sandbox/chromium/base/time/time.cc
new file mode 100644
index 0000000000..1293cdcaad
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time.cc
@@ -0,0 +1,433 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+
+#include <cmath>
+#include <ios>
+#include <limits>
+#include <ostream>
+#include <sstream>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/nspr/prtime.h"
+#include "base/time/time_override.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace internal {
+
+TimeNowFunction g_time_now_function = &subtle::TimeNowIgnoringOverride;
+
+TimeNowFunction g_time_now_from_system_time_function =
+ &subtle::TimeNowFromSystemTimeIgnoringOverride;
+
+TimeTicksNowFunction g_time_ticks_now_function =
+ &subtle::TimeTicksNowIgnoringOverride;
+
+ThreadTicksNowFunction g_thread_ticks_now_function =
+ &subtle::ThreadTicksNowIgnoringOverride;
+
+} // namespace internal
+
+// TimeDelta ------------------------------------------------------------------
+
+int TimeDelta::InDays() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int>::max();
+ }
+ return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
+}
+
+int TimeDelta::InDaysFloored() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int>::max();
+ }
+ int result = delta_ / Time::kMicrosecondsPerDay;
+ int64_t remainder = delta_ - (result * Time::kMicrosecondsPerDay);
+ if (remainder < 0) {
+ --result; // Use floor(), not trunc() rounding behavior.
+ }
+ return result;
+}
+
+int TimeDelta::InHours() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int>::max();
+ }
+ return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
+}
+
+int TimeDelta::InMinutes() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int>::max();
+ }
+ return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
+}
+
+double TimeDelta::InSecondsF() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<double>::infinity();
+ }
+ return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
+}
+
+int64_t TimeDelta::InSeconds() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int64_t>::max();
+ }
+ return delta_ / Time::kMicrosecondsPerSecond;
+}
+
+double TimeDelta::InMillisecondsF() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<double>::infinity();
+ }
+ return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
+}
+
+int64_t TimeDelta::InMilliseconds() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int64_t>::max();
+ }
+ return delta_ / Time::kMicrosecondsPerMillisecond;
+}
+
+int64_t TimeDelta::InMillisecondsRoundedUp() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int64_t>::max();
+ }
+ int64_t result = delta_ / Time::kMicrosecondsPerMillisecond;
+ int64_t remainder = delta_ - (result * Time::kMicrosecondsPerMillisecond);
+ if (remainder > 0) {
+ ++result; // Use ceil(), not trunc() rounding behavior.
+ }
+ return result;
+}
+
+double TimeDelta::InMicrosecondsF() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<double>::infinity();
+ }
+ return static_cast<double>(delta_);
+}
+
+int64_t TimeDelta::InNanoseconds() const {
+ if (is_max()) {
+ // Preserve max to prevent overflow.
+ return std::numeric_limits<int64_t>::max();
+ }
+ return delta_ * Time::kNanosecondsPerMicrosecond;
+}
+
+std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
+ return os << time_delta.InSecondsF() << " s";
+}
+
+// Time -----------------------------------------------------------------------
+
+// static
+Time Time::Now() {
+ return internal::g_time_now_function();
+}
+
+// static
+Time Time::NowFromSystemTime() {
+ // Just use g_time_now_function because it returns the system time.
+ return internal::g_time_now_from_system_time_function();
+}
+
+// static
+Time Time::FromDeltaSinceWindowsEpoch(TimeDelta delta) {
+ return Time(delta.InMicroseconds());
+}
+
+TimeDelta Time::ToDeltaSinceWindowsEpoch() const {
+ return TimeDelta::FromMicroseconds(us_);
+}
+
+// static
+Time Time::FromTimeT(time_t tt) {
+ if (tt == 0)
+ return Time(); // Preserve 0 so we can tell it doesn't exist.
+ if (tt == std::numeric_limits<time_t>::max())
+ return Max();
+ return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSeconds(tt);
+}
+
+time_t Time::ToTimeT() const {
+ if (is_null())
+ return 0; // Preserve 0 so we can tell it doesn't exist.
+ if (is_max()) {
+ // Preserve max without offset to prevent overflow.
+ return std::numeric_limits<time_t>::max();
+ }
+ if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) {
+ DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
+ "value " << us_ << " to time_t.";
+ return std::numeric_limits<time_t>::max();
+ }
+ return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
+}
+
+// static
+Time Time::FromDoubleT(double dt) {
+ if (dt == 0 || std::isnan(dt))
+ return Time(); // Preserve 0 so we can tell it doesn't exist.
+ return Time(kTimeTToMicrosecondsOffset) + TimeDelta::FromSecondsD(dt);
+}
+
+double Time::ToDoubleT() const {
+ if (is_null())
+ return 0; // Preserve 0 so we can tell it doesn't exist.
+ if (is_max()) {
+ // Preserve max without offset to prevent overflow.
+ return std::numeric_limits<double>::infinity();
+ }
+ return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+ static_cast<double>(kMicrosecondsPerSecond));
+}
+
+#if defined(OS_POSIX)
+// static
+Time Time::FromTimeSpec(const timespec& ts) {
+ return FromDoubleT(ts.tv_sec +
+ static_cast<double>(ts.tv_nsec) /
+ base::Time::kNanosecondsPerSecond);
+}
+#endif
+
+// static
+Time Time::FromJsTime(double ms_since_epoch) {
+ // The epoch is a valid time, so this constructor doesn't interpret
+ // 0 as the null time.
+ return Time(kTimeTToMicrosecondsOffset) +
+ TimeDelta::FromMillisecondsD(ms_since_epoch);
+}
+
+double Time::ToJsTime() const {
+ if (is_null()) {
+ // Preserve 0 so the invalid result doesn't depend on the platform.
+ return 0;
+ }
+ return ToJsTimeIgnoringNull();
+}
+
+double Time::ToJsTimeIgnoringNull() const {
+ if (is_max()) {
+ // Preserve max without offset to prevent overflow.
+ return std::numeric_limits<double>::infinity();
+ }
+ return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+ kMicrosecondsPerMillisecond);
+}
+
+Time Time::FromJavaTime(int64_t ms_since_epoch) {
+ return base::Time::UnixEpoch() +
+ base::TimeDelta::FromMilliseconds(ms_since_epoch);
+}
+
+int64_t Time::ToJavaTime() const {
+ if (is_null()) {
+ // Preserve 0 so the invalid result doesn't depend on the platform.
+ return 0;
+ }
+ if (is_max()) {
+ // Preserve max without offset to prevent overflow.
+ return std::numeric_limits<int64_t>::max();
+ }
+ return ((us_ - kTimeTToMicrosecondsOffset) /
+ kMicrosecondsPerMillisecond);
+}
+
+// static
+Time Time::UnixEpoch() {
+ Time time;
+ time.us_ = kTimeTToMicrosecondsOffset;
+ return time;
+}
+
+Time Time::Midnight(bool is_local) const {
+ Exploded exploded;
+ Explode(is_local, &exploded);
+ exploded.hour = 0;
+ exploded.minute = 0;
+ exploded.second = 0;
+ exploded.millisecond = 0;
+ Time out_time;
+ if (FromExploded(is_local, exploded, &out_time)) {
+ return out_time;
+ } else if (is_local) {
+ // Hitting this branch means 00:00:00am of the current day
+ // does not exist (due to Daylight Saving Time in some countries
+ // where clocks are shifted at midnight). In this case, midnight
+ // should be defined as 01:00:00am.
+ exploded.hour = 1;
+ if (FromExploded(is_local, exploded, &out_time))
+ return out_time;
+ }
+ // This function must not fail.
+ NOTREACHED();
+ return Time();
+}
+
+#if !defined(MOZ_SANDBOX)
+// static
+bool Time::FromStringInternal(const char* time_string,
+ bool is_local,
+ Time* parsed_time) {
+ DCHECK((time_string != nullptr) && (parsed_time != nullptr));
+
+ if (time_string[0] == '\0')
+ return false;
+
+ PRTime result_time = 0;
+ PRStatus result = PR_ParseTimeString(time_string,
+ is_local ? PR_FALSE : PR_TRUE,
+ &result_time);
+ if (PR_SUCCESS != result)
+ return false;
+
+ result_time += kTimeTToMicrosecondsOffset;
+ *parsed_time = Time(result_time);
+ return true;
+}
+#endif
+
+// static
+bool Time::ExplodedMostlyEquals(const Exploded& lhs, const Exploded& rhs) {
+ return lhs.year == rhs.year && lhs.month == rhs.month &&
+ lhs.day_of_month == rhs.day_of_month && lhs.hour == rhs.hour &&
+ lhs.minute == rhs.minute && lhs.second == rhs.second &&
+ lhs.millisecond == rhs.millisecond;
+}
+
+// static
+bool Time::FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,
+ Time* time) {
+ // Adjust the provided time from milliseconds since the Unix epoch (1970) to
+ // microseconds since the Windows epoch (1601), avoiding overflows.
+ base::CheckedNumeric<int64_t> checked_microseconds_win_epoch =
+ unix_milliseconds;
+ checked_microseconds_win_epoch *= kMicrosecondsPerMillisecond;
+ checked_microseconds_win_epoch += kTimeTToMicrosecondsOffset;
+ if (!checked_microseconds_win_epoch.IsValid()) {
+ *time = base::Time(0);
+ return false;
+ }
+
+ *time = Time(checked_microseconds_win_epoch.ValueOrDie());
+ return true;
+}
+
+int64_t Time::ToRoundedDownMillisecondsSinceUnixEpoch() const {
+ // Adjust from Windows epoch (1601) to Unix epoch (1970).
+ int64_t microseconds = us_ - kTimeTToMicrosecondsOffset;
+
+ // Round the microseconds towards -infinity.
+ if (microseconds >= 0) {
+ // In this case, rounding towards -infinity means rounding towards 0.
+ return microseconds / kMicrosecondsPerMillisecond;
+ } else {
+ return (microseconds - kMicrosecondsPerMillisecond + 1) /
+ kMicrosecondsPerMillisecond;
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, Time time) {
+ Time::Exploded exploded;
+ time.UTCExplode(&exploded);
+ // Use StringPrintf because iostreams formatting is painful.
+ return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC",
+ exploded.year,
+ exploded.month,
+ exploded.day_of_month,
+ exploded.hour,
+ exploded.minute,
+ exploded.second,
+ exploded.millisecond);
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+// static
+TimeTicks TimeTicks::Now() {
+ return internal::g_time_ticks_now_function();
+}
+
+// static
+TimeTicks TimeTicks::UnixEpoch() {
+ static const base::NoDestructor<base::TimeTicks> epoch([]() {
+ return subtle::TimeTicksNowIgnoringOverride() -
+ (subtle::TimeNowIgnoringOverride() - Time::UnixEpoch());
+ }());
+ return *epoch;
+}
+
+TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
+ TimeDelta tick_interval) const {
+ // |interval_offset| is the offset from |this| to the next multiple of
+ // |tick_interval| after |tick_phase|, possibly negative if in the past.
+ TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
+ // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
+ // Otherwise, if |tick_phase| was in the past, adjust forward to the next
+ // tick after |this|.
+ if (!interval_offset.is_zero() && tick_phase < *this)
+ interval_offset += tick_interval;
+ return *this + interval_offset;
+}
+
+std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
+ // This function formats a TimeTicks object as "bogo-microseconds".
+ // The origin and granularity of the count are platform-specific, and may very
+ // from run to run. Although bogo-microseconds usually roughly correspond to
+ // real microseconds, the only real guarantee is that the number never goes
+ // down during a single run.
+ const TimeDelta as_time_delta = time_ticks - TimeTicks();
+ return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
+}
+
+// ThreadTicks ----------------------------------------------------------------
+
+// static
+ThreadTicks ThreadTicks::Now() {
+ return internal::g_thread_ticks_now_function();
+}
+
+std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
+ const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
+ return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
+}
+
+// Time::Exploded -------------------------------------------------------------
+
+inline bool is_in_range(int value, int lo, int hi) {
+ return lo <= value && value <= hi;
+}
+
+bool Time::Exploded::HasValidValues() const {
+ return is_in_range(month, 1, 12) &&
+ is_in_range(day_of_week, 0, 6) &&
+ is_in_range(day_of_month, 1, 31) &&
+ is_in_range(hour, 0, 23) &&
+ is_in_range(minute, 0, 59) &&
+ is_in_range(second, 0, 60) &&
+ is_in_range(millisecond, 0, 999);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/time/time.h b/security/sandbox/chromium/base/time/time.h
new file mode 100644
index 0000000000..7214e000f0
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time.h
@@ -0,0 +1,1077 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Time represents an absolute point in coordinated universal time (UTC),
+// internally represented as microseconds (s/1,000,000) since the Windows epoch
+// (1601-01-01 00:00:00 UTC). System-dependent clock interface routines are
+// defined in time_PLATFORM.cc. Note that values for Time may skew and jump
+// around as the operating system makes adjustments to synchronize (e.g., with
+// NTP servers). Thus, client code that uses the Time class must account for
+// this.
+//
+// TimeDelta represents a duration of time, internally represented in
+// microseconds.
+//
+// TimeTicks and ThreadTicks represent an abstract time that is most of the time
+// incrementing, for use in measuring time durations. Internally, they are
+// represented in microseconds. They cannot be converted to a human-readable
+// time, but are guaranteed not to decrease (unlike the Time class). Note that
+// TimeTicks may "stand still" (e.g., if the computer is suspended), and
+// ThreadTicks will "stand still" whenever the thread has been de-scheduled by
+// the operating system.
+//
+// All time classes are copyable, assignable, and occupy 64-bits per instance.
+// As a result, prefer passing them by value:
+// void MyFunction(TimeDelta arg);
+// If circumstances require, you may also pass by const reference:
+// void MyFunction(const TimeDelta& arg); // Not preferred.
+//
+// Definitions of operator<< are provided to make these types work with
+// DCHECK_EQ() and other log macros. For human-readable formatting, see
+// "base/i18n/time_formatting.h".
+//
+// So many choices! Which time class should you use? Examples:
+//
+// Time: Interpreting the wall-clock time provided by a remote system.
+// Detecting whether cached resources have expired. Providing the
+// user with a display of the current date and time. Determining
+// the amount of time between events across re-boots of the
+// machine.
+//
+// TimeTicks: Tracking the amount of time a task runs. Executing delayed
+// tasks at the right time. Computing presentation timestamps.
+// Synchronizing audio and video using TimeTicks as a common
+// reference clock (lip-sync). Measuring network round-trip
+// latency.
+//
+// ThreadTicks: Benchmarking how long the current thread has been doing actual
+// work.
+
+#ifndef BASE_TIME_TIME_H_
+#define BASE_TIME_TIME_H_
+
+#include <stdint.h>
+#include <time.h>
+
+#include <iosfwd>
+#include <limits>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "build/build_config.h"
+
+#if defined(OS_FUCHSIA)
+#include <zircon/types.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+// Avoid Mac system header macro leak.
+#undef TYPE_BOOL
+#endif
+
+#if defined(OS_ANDROID)
+#include <jni.h>
+#endif
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#if defined(OS_WIN)
+#include "base/gtest_prod_util.h"
+#include "base/win/windows_types.h"
+#endif
+
+namespace ABI {
+namespace Windows {
+namespace Foundation {
+struct DateTime;
+} // namespace Foundation
+} // namespace Windows
+} // namespace ABI
+
+namespace base {
+
+class PlatformThreadHandle;
+class TimeDelta;
+
+// The functions in the time_internal namespace are meant to be used only by the
+// time classes and functions. Please use the math operators defined in the
+// time classes instead.
+namespace time_internal {
+
+// Add or subtract a TimeDelta from |value|. TimeDelta::Min()/Max() are treated
+// as infinity and will always saturate the return value (infinity math applies
+// if |value| also is at either limit of its spectrum). The int64_t argument and
+// return value are in terms of a microsecond timebase.
+BASE_EXPORT constexpr int64_t SaturatedAdd(int64_t value, TimeDelta delta);
+BASE_EXPORT constexpr int64_t SaturatedSub(int64_t value, TimeDelta delta);
+
+} // namespace time_internal
+
+// TimeDelta ------------------------------------------------------------------
+
+class BASE_EXPORT TimeDelta {
+ public:
+ constexpr TimeDelta() : delta_(0) {}
+
+ // Converts units of time to TimeDeltas.
+ // WARNING: Floating point arithmetic is such that FromXXXD(t.InXXXF()) may
+ // not precisely equal |t|. Hence, floating point values should not be used
+ // for storage.
+ static constexpr TimeDelta FromDays(int days);
+ static constexpr TimeDelta FromHours(int hours);
+ static constexpr TimeDelta FromMinutes(int minutes);
+ static constexpr TimeDelta FromSeconds(int64_t secs);
+ static constexpr TimeDelta FromMilliseconds(int64_t ms);
+ static constexpr TimeDelta FromMicroseconds(int64_t us);
+ static constexpr TimeDelta FromNanoseconds(int64_t ns);
+ static constexpr TimeDelta FromSecondsD(double secs);
+ static constexpr TimeDelta FromMillisecondsD(double ms);
+ static constexpr TimeDelta FromMicrosecondsD(double us);
+ static constexpr TimeDelta FromNanosecondsD(double ns);
+#if defined(OS_WIN)
+ static TimeDelta FromQPCValue(LONGLONG qpc_value);
+ // TODO(crbug.com/989694): Avoid base::TimeDelta factory functions
+ // based on absolute time
+ static TimeDelta FromFileTime(FILETIME ft);
+ static TimeDelta FromWinrtDateTime(ABI::Windows::Foundation::DateTime dt);
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ static TimeDelta FromTimeSpec(const timespec& ts);
+#endif
+#if defined(OS_FUCHSIA)
+ static TimeDelta FromZxDuration(zx_duration_t nanos);
+#endif
+
+ // Converts an integer value representing TimeDelta to a class. This is used
+ // when deserializing a |TimeDelta| structure, using a value known to be
+ // compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ //
+ // DEPRECATED - Do not use in new code. http://crbug.com/634507
+ static constexpr TimeDelta FromInternalValue(int64_t delta) {
+ return TimeDelta(delta);
+ }
+
+ // Returns the maximum time delta, which should be greater than any reasonable
+ // time delta we might compare it to. Adding or subtracting the maximum time
+ // delta to a time or another time delta has an undefined result.
+ static constexpr TimeDelta Max();
+
+ // Returns the minimum time delta, which should be less than than any
+ // reasonable time delta we might compare it to. Adding or subtracting the
+ // minimum time delta to a time or another time delta has an undefined result.
+ static constexpr TimeDelta Min();
+
+ // Returns the internal numeric value of the TimeDelta object. Please don't
+ // use this and do arithmetic on it, as it is more error prone than using the
+ // provided operators.
+ // For serializing, use FromInternalValue to reconstitute.
+ //
+ // DEPRECATED - Do not use in new code. http://crbug.com/634507
+ constexpr int64_t ToInternalValue() const { return delta_; }
+
+ // Returns the magnitude (absolute value) of this TimeDelta.
+ constexpr TimeDelta magnitude() const {
+ // Some toolchains provide an incomplete C++11 implementation and lack an
+ // int64_t overload for std::abs(). The following is a simple branchless
+ // implementation:
+ const int64_t mask = delta_ >> (sizeof(delta_) * 8 - 1);
+ return TimeDelta((delta_ + mask) ^ mask);
+ }
+
+ // Returns true if the time delta is zero.
+ constexpr bool is_zero() const { return delta_ == 0; }
+
+ // Returns true if the time delta is the maximum/minimum time delta.
+ constexpr bool is_max() const {
+ return delta_ == std::numeric_limits<int64_t>::max();
+ }
+ constexpr bool is_min() const {
+ return delta_ == std::numeric_limits<int64_t>::min();
+ }
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+ struct timespec ToTimeSpec() const;
+#endif
+#if defined(OS_FUCHSIA)
+ zx_duration_t ToZxDuration() const;
+#endif
+#if defined(OS_WIN)
+ ABI::Windows::Foundation::DateTime ToWinrtDateTime() const;
+#endif
+
+ // Returns the time delta in some unit. The InXYZF versions return a floating
+ // point value. The InXYZ versions return a truncated value (aka rounded
+ // towards zero, std::trunc() behavior). The InXYZFloored() versions round to
+ // lesser integers (std::floor() behavior). The XYZRoundedUp() versions round
+ // up to greater integers (std::ceil() behavior).
+ // WARNING: Floating point arithmetic is such that FromXXXD(t.InXXXF()) may
+ // not precisely equal |t|. Hence, floating point values should not be used
+ // for storage.
+ int InDays() const;
+ int InDaysFloored() const;
+ int InHours() const;
+ int InMinutes() const;
+ double InSecondsF() const;
+ int64_t InSeconds() const;
+ double InMillisecondsF() const;
+ int64_t InMilliseconds() const;
+ int64_t InMillisecondsRoundedUp() const;
+ constexpr int64_t InMicroseconds() const { return delta_; }
+ double InMicrosecondsF() const;
+ int64_t InNanoseconds() const;
+
+ // Computations with other deltas.
+ constexpr TimeDelta operator+(TimeDelta other) const {
+ return TimeDelta(time_internal::SaturatedAdd(delta_, other));
+ }
+ constexpr TimeDelta operator-(TimeDelta other) const {
+ return TimeDelta(time_internal::SaturatedSub(delta_, other));
+ }
+
+ constexpr TimeDelta& operator+=(TimeDelta other) {
+ return *this = (*this + other);
+ }
+ constexpr TimeDelta& operator-=(TimeDelta other) {
+ return *this = (*this - other);
+ }
+ constexpr TimeDelta operator-() const { return TimeDelta(-delta_); }
+
+ // Computations with numeric types.
+ template <typename T>
+ constexpr TimeDelta operator*(T a) const {
+ CheckedNumeric<int64_t> rv(delta_);
+ rv *= a;
+ if (rv.IsValid())
+ return TimeDelta(rv.ValueOrDie());
+ // Matched sign overflows. Mismatched sign underflows.
+ if ((delta_ < 0) ^ (a < 0))
+ return TimeDelta(std::numeric_limits<int64_t>::min());
+ return TimeDelta(std::numeric_limits<int64_t>::max());
+ }
+ template <typename T>
+ constexpr TimeDelta operator/(T a) const {
+ CheckedNumeric<int64_t> rv(delta_);
+ rv /= a;
+ if (rv.IsValid())
+ return TimeDelta(rv.ValueOrDie());
+ // Matched sign overflows. Mismatched sign underflows.
+ // Special case to catch divide by zero.
+ if ((delta_ < 0) ^ (a <= 0))
+ return TimeDelta(std::numeric_limits<int64_t>::min());
+ return TimeDelta(std::numeric_limits<int64_t>::max());
+ }
+ template <typename T>
+ constexpr TimeDelta& operator*=(T a) {
+ return *this = (*this * a);
+ }
+ template <typename T>
+ constexpr TimeDelta& operator/=(T a) {
+ return *this = (*this / a);
+ }
+
+ constexpr int64_t operator/(TimeDelta a) const { return delta_ / a.delta_; }
+
+ constexpr TimeDelta operator%(TimeDelta a) const {
+ return TimeDelta(delta_ % a.delta_);
+ }
+ TimeDelta& operator%=(TimeDelta other) { return *this = (*this % other); }
+
+ // Comparison operators.
+ constexpr bool operator==(TimeDelta other) const {
+ return delta_ == other.delta_;
+ }
+ constexpr bool operator!=(TimeDelta other) const {
+ return delta_ != other.delta_;
+ }
+ constexpr bool operator<(TimeDelta other) const {
+ return delta_ < other.delta_;
+ }
+ constexpr bool operator<=(TimeDelta other) const {
+ return delta_ <= other.delta_;
+ }
+ constexpr bool operator>(TimeDelta other) const {
+ return delta_ > other.delta_;
+ }
+ constexpr bool operator>=(TimeDelta other) const {
+ return delta_ >= other.delta_;
+ }
+
+ private:
+ friend constexpr int64_t time_internal::SaturatedAdd(int64_t value,
+ TimeDelta delta);
+ friend constexpr int64_t time_internal::SaturatedSub(int64_t value,
+ TimeDelta delta);
+
+ // Constructs a delta given the duration in microseconds. This is private
+ // to avoid confusion by callers with an integer constructor. Use
+ // FromSeconds, FromMilliseconds, etc. instead.
+ constexpr explicit TimeDelta(int64_t delta_us) : delta_(delta_us) {}
+
+ // Private method to build a delta from a double.
+ static constexpr TimeDelta FromDouble(double value);
+
+ // Private method to build a delta from the product of a user-provided value
+ // and a known-positive value.
+ static constexpr TimeDelta FromProduct(int64_t value, int64_t positive_value);
+
+ // Delta in microseconds.
+ int64_t delta_;
+};
+
+template <typename T>
+constexpr TimeDelta operator*(T a, TimeDelta td) {
+ return td * a;
+}
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeDelta time_delta);
+
+// Do not reference the time_internal::TimeBase template class directly. Please
+// use one of the time subclasses instead, and only reference the public
+// TimeBase members via those classes.
+namespace time_internal {
+
+constexpr int64_t SaturatedAdd(int64_t value, TimeDelta delta) {
+ // Treat Min/Max() as +/- infinity (additions involving two infinities are
+ // only valid if signs match).
+ if (delta.is_max()) {
+ CHECK_GT(value, std::numeric_limits<int64_t>::min());
+ return std::numeric_limits<int64_t>::max();
+ } else if (delta.is_min()) {
+ CHECK_LT(value, std::numeric_limits<int64_t>::max());
+ return std::numeric_limits<int64_t>::min();
+ }
+
+ return base::ClampAdd(value, delta.delta_);
+}
+
+constexpr int64_t SaturatedSub(int64_t value, TimeDelta delta) {
+ // Treat Min/Max() as +/- infinity (subtractions involving two infinities are
+ // only valid if signs are opposite).
+ if (delta.is_max()) {
+ CHECK_LT(value, std::numeric_limits<int64_t>::max());
+ return std::numeric_limits<int64_t>::min();
+ } else if (delta.is_min()) {
+ CHECK_GT(value, std::numeric_limits<int64_t>::min());
+ return std::numeric_limits<int64_t>::max();
+ }
+
+ return base::ClampSub(value, delta.delta_);
+}
+
+// TimeBase--------------------------------------------------------------------
+
+// Provides value storage and comparison/math operations common to all time
+// classes. Each subclass provides for strong type-checking to ensure
+// semantically meaningful comparison/math of time values from the same clock
+// source or timeline.
+template<class TimeClass>
+class TimeBase {
+ public:
+ static constexpr int64_t kHoursPerDay = 24;
+ static constexpr int64_t kSecondsPerMinute = 60;
+ static constexpr int64_t kSecondsPerHour = 60 * kSecondsPerMinute;
+ static constexpr int64_t kMillisecondsPerSecond = 1000;
+ static constexpr int64_t kMillisecondsPerDay =
+ kMillisecondsPerSecond * 60 * 60 * kHoursPerDay;
+ static constexpr int64_t kMicrosecondsPerMillisecond = 1000;
+ static constexpr int64_t kMicrosecondsPerSecond =
+ kMicrosecondsPerMillisecond * kMillisecondsPerSecond;
+ static constexpr int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+ static constexpr int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+ static constexpr int64_t kMicrosecondsPerDay =
+ kMicrosecondsPerHour * kHoursPerDay;
+ static constexpr int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+ static constexpr int64_t kNanosecondsPerMicrosecond = 1000;
+ static constexpr int64_t kNanosecondsPerSecond =
+ kNanosecondsPerMicrosecond * kMicrosecondsPerSecond;
+
+ // Returns true if this object has not been initialized.
+ //
+ // Warning: Be careful when writing code that performs math on time values,
+ // since it's possible to produce a valid "zero" result that should not be
+ // interpreted as a "null" value.
+ constexpr bool is_null() const { return us_ == 0; }
+
+ // Returns true if this object represents the maximum/minimum time.
+ constexpr bool is_max() const {
+ return us_ == std::numeric_limits<int64_t>::max();
+ }
+ constexpr bool is_min() const {
+ return us_ == std::numeric_limits<int64_t>::min();
+ }
+
+ // Returns the maximum/minimum times, which should be greater/less than than
+ // any reasonable time with which we might compare it.
+ static constexpr TimeClass Max() {
+ return TimeClass(std::numeric_limits<int64_t>::max());
+ }
+
+ static constexpr TimeClass Min() {
+ return TimeClass(std::numeric_limits<int64_t>::min());
+ }
+
+ // For serializing only. Use FromInternalValue() to reconstitute. Please don't
+ // use this and do arithmetic on it, as it is more error prone than using the
+ // provided operators.
+ //
+ // DEPRECATED - Do not use in new code. For serializing Time values, prefer
+ // Time::ToDeltaSinceWindowsEpoch().InMicroseconds(). http://crbug.com/634507
+ constexpr int64_t ToInternalValue() const { return us_; }
+
+ // The amount of time since the origin (or "zero") point. This is a syntactic
+ // convenience to aid in code readability, mainly for debugging/testing use
+ // cases.
+ //
+ // Warning: While the Time subclass has a fixed origin point, the origin for
+ // the other subclasses can vary each time the application is restarted.
+ constexpr TimeDelta since_origin() const {
+ return TimeDelta::FromMicroseconds(us_);
+ }
+
+ constexpr TimeClass& operator=(TimeClass other) {
+ us_ = other.us_;
+ return *(static_cast<TimeClass*>(this));
+ }
+
+ // Compute the difference between two times.
+ constexpr TimeDelta operator-(TimeClass other) const {
+ return TimeDelta::FromMicroseconds(us_ - other.us_);
+ }
+
+ // Return a new time modified by some delta.
+ constexpr TimeClass operator+(TimeDelta delta) const {
+ return TimeClass(time_internal::SaturatedAdd(us_, delta));
+ }
+ constexpr TimeClass operator-(TimeDelta delta) const {
+ return TimeClass(time_internal::SaturatedSub(us_, delta));
+ }
+
+ // Modify by some time delta.
+ constexpr TimeClass& operator+=(TimeDelta delta) {
+ return static_cast<TimeClass&>(*this = (*this + delta));
+ }
+ constexpr TimeClass& operator-=(TimeDelta delta) {
+ return static_cast<TimeClass&>(*this = (*this - delta));
+ }
+
+ // Comparison operators
+ constexpr bool operator==(TimeClass other) const { return us_ == other.us_; }
+ constexpr bool operator!=(TimeClass other) const { return us_ != other.us_; }
+ constexpr bool operator<(TimeClass other) const { return us_ < other.us_; }
+ constexpr bool operator<=(TimeClass other) const { return us_ <= other.us_; }
+ constexpr bool operator>(TimeClass other) const { return us_ > other.us_; }
+ constexpr bool operator>=(TimeClass other) const { return us_ >= other.us_; }
+
+ protected:
+ constexpr explicit TimeBase(int64_t us) : us_(us) {}
+
+ // Time value in a microsecond timebase.
+ int64_t us_;
+};
+
+} // namespace time_internal
+
+template <class TimeClass>
+inline constexpr TimeClass operator+(TimeDelta delta, TimeClass t) {
+ return t + delta;
+}
+
+// Time -----------------------------------------------------------------------
+
+// Represents a wall clock time in UTC. Values are not guaranteed to be
+// monotonically non-decreasing and are subject to large amounts of skew.
+// Time is stored internally as microseconds since the Windows epoch (1601).
+class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
+ public:
+ // Offset of UNIX epoch (1970-01-01 00:00:00 UTC) from Windows FILETIME epoch
+ // (1601-01-01 00:00:00 UTC), in microseconds. This value is derived from the
+ // following: ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the number
+ // of leap year days between 1601 and 1970: (1970-1601)/4 excluding 1700,
+ // 1800, and 1900.
+ static constexpr int64_t kTimeTToMicrosecondsOffset =
+ INT64_C(11644473600000000);
+
+#if defined(OS_WIN)
+ // To avoid overflow in QPC to Microseconds calculations, since we multiply
+ // by kMicrosecondsPerSecond, then the QPC value should not exceed
+ // (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
+ static constexpr int64_t kQPCOverflowThreshold = INT64_C(0x8637BD05AF7);
+#endif
+
+// kExplodedMinYear and kExplodedMaxYear define the platform-specific limits
+// for values passed to FromUTCExploded() and FromLocalExploded(). Those
+// functions will return false if passed values outside these limits. The limits
+// are inclusive, meaning that the API should support all dates within a given
+// limit year.
+#if defined(OS_WIN)
+ static constexpr int kExplodedMinYear = 1601;
+ static constexpr int kExplodedMaxYear = 30827;
+#elif defined(OS_IOS) && !__LP64__
+ static constexpr int kExplodedMinYear = std::numeric_limits<int>::min();
+ static constexpr int kExplodedMaxYear = std::numeric_limits<int>::max();
+#elif defined(OS_MACOSX)
+ static constexpr int kExplodedMinYear = 1902;
+ static constexpr int kExplodedMaxYear = std::numeric_limits<int>::max();
+#elif defined(OS_ANDROID)
+ // Though we use 64-bit time APIs on both 32 and 64 bit Android, some OS
+ // versions like KitKat (ARM but not x86 emulator) can't handle some early
+ // dates (e.g. before 1170). So we set min conservatively here.
+ static constexpr int kExplodedMinYear = 1902;
+ static constexpr int kExplodedMaxYear = std::numeric_limits<int>::max();
+#else
+ static constexpr int kExplodedMinYear =
+ (sizeof(time_t) == 4 ? 1902 : std::numeric_limits<int>::min());
+ static constexpr int kExplodedMaxYear =
+ (sizeof(time_t) == 4 ? 2037 : std::numeric_limits<int>::max());
+#endif
+
+ // Represents an exploded time that can be formatted nicely. This is kind of
+ // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few
+ // additions and changes to prevent errors.
+ struct BASE_EXPORT Exploded {
+ int year; // Four digit year "2007"
+ int month; // 1-based month (values 1 = January, etc.)
+ int day_of_week; // 0-based day of week (0 = Sunday, etc.)
+ int day_of_month; // 1-based day of month (1-31)
+ int hour; // Hour within the current day (0-23)
+ int minute; // Minute within the current hour (0-59)
+ int second; // Second within the current minute (0-59 plus leap
+ // seconds which may take it up to 60).
+ int millisecond; // Milliseconds within the current second (0-999)
+
+ // A cursory test for whether the data members are within their
+ // respective ranges. A 'true' return value does not guarantee the
+ // Exploded value can be successfully converted to a Time value.
+ bool HasValidValues() const;
+ };
+
+ // Contains the NULL time. Use Time::Now() to get the current time.
+ constexpr Time() : TimeBase(0) {}
+
+ // Returns the time for epoch in Unix-like system (Jan 1, 1970).
+ static Time UnixEpoch();
+
+ // Returns the current time. Watch out, the system might adjust its clock
+ // in which case time will actually go backwards. We don't guarantee that
+ // times are increasing, or that two calls to Now() won't be the same.
+ static Time Now();
+
+ // Returns the current time. Same as Now() except that this function always
+ // uses system time so that there are no discrepancies between the returned
+ // time and system time even on virtual environments including our test bot.
+ // For timing sensitive unittests, this function should be used.
+ static Time NowFromSystemTime();
+
+ // Converts to/from TimeDeltas relative to the Windows epoch (1601-01-01
+ // 00:00:00 UTC). Prefer these methods for opaque serialization and
+ // deserialization of time values, e.g.
+ //
+ // // Serialization:
+ // base::Time last_updated = ...;
+ // SaveToDatabase(last_updated.ToDeltaSinceWindowsEpoch().InMicroseconds());
+ //
+ // // Deserialization:
+ // base::Time last_updated = base::Time::FromDeltaSinceWindowsEpoch(
+ // base::TimeDelta::FromMicroseconds(LoadFromDatabase()));
+ static Time FromDeltaSinceWindowsEpoch(TimeDelta delta);
+ TimeDelta ToDeltaSinceWindowsEpoch() const;
+
+ // Converts to/from time_t in UTC and a Time class.
+ static Time FromTimeT(time_t tt);
+ time_t ToTimeT() const;
+
+ // Converts time to/from a double which is the number of seconds since epoch
+ // (Jan 1, 1970). Webkit uses this format to represent time.
+ // Because WebKit initializes double time value to 0 to indicate "not
+ // initialized", we map it to empty Time object that also means "not
+ // initialized".
+ static Time FromDoubleT(double dt);
+ double ToDoubleT() const;
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+ // Converts the timespec structure to time. MacOS X 10.8.3 (and tentatively,
+ // earlier versions) will have the |ts|'s tv_nsec component zeroed out,
+ // having a 1 second resolution, which agrees with
+ // https://developer.apple.com/legacy/library/#technotes/tn/tn1150.html#HFSPlusDates.
+ static Time FromTimeSpec(const timespec& ts);
+#endif
+
+ // Converts to/from the Javascript convention for times, a number of
+ // milliseconds since the epoch:
+ // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/getTime.
+ //
+ // Don't use ToJsTime() in new code, since it contains a subtle hack (only
+ // exactly 1601-01-01 00:00 UTC is represented as 1970-01-01 00:00 UTC), and
+ // that is not appropriate for general use. Try to use ToJsTimeIgnoringNull()
+ // unless you have a very good reason to use ToJsTime().
+ static Time FromJsTime(double ms_since_epoch);
+ double ToJsTime() const;
+ double ToJsTimeIgnoringNull() const;
+
+ // Converts to/from Java convention for times, a number of milliseconds since
+ // the epoch. Because the Java format has less resolution, converting to Java
+ // time is a lossy operation.
+ static Time FromJavaTime(int64_t ms_since_epoch);
+ int64_t ToJavaTime() const;
+
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
+ static Time FromTimeVal(struct timeval t);
+ struct timeval ToTimeVal() const;
+#endif
+
+#if defined(OS_FUCHSIA)
+ static Time FromZxTime(zx_time_t time);
+ zx_time_t ToZxTime() const;
+#endif
+
+#if defined(OS_MACOSX)
+ static Time FromCFAbsoluteTime(CFAbsoluteTime t);
+ CFAbsoluteTime ToCFAbsoluteTime() const;
+#endif
+
+#if defined(OS_WIN)
+ static Time FromFileTime(FILETIME ft);
+ FILETIME ToFileTime() const;
+
+ // The minimum time of a low resolution timer. This is basically a windows
+ // constant of ~15.6ms. While it does vary on some older OS versions, we'll
+ // treat it as static across all windows versions.
+ static const int kMinLowResolutionThresholdMs = 16;
+
+ // Enable or disable Windows high resolution timer.
+ static void EnableHighResolutionTimer(bool enable);
+
+ // Read the minimum timer interval from the feature list. This should be
+ // called once after the feature list is initialized. This is needed for
+ // an experiment - see https://crbug.com/927165
+ static void ReadMinTimerIntervalLowResMs();
+
+ // Activates or deactivates the high resolution timer based on the |activate|
+ // flag. If the HighResolutionTimer is not Enabled (see
+ // EnableHighResolutionTimer), this function will return false. Otherwise
+ // returns true. Each successful activate call must be paired with a
+ // subsequent deactivate call.
+ // All callers to activate the high resolution timer must eventually call
+ // this function to deactivate the high resolution timer.
+ static bool ActivateHighResolutionTimer(bool activate);
+
+ // Returns true if the high resolution timer is both enabled and activated.
+ // This is provided for testing only, and is not tracked in a thread-safe
+ // way.
+ static bool IsHighResolutionTimerInUse();
+
+ // The following two functions are used to report the fraction of elapsed time
+ // that the high resolution timer is activated.
+ // ResetHighResolutionTimerUsage() resets the cumulative usage and starts the
+ // measurement interval and GetHighResolutionTimerUsage() returns the
+ // percentage of time since the reset that the high resolution timer was
+ // activated.
+ // ResetHighResolutionTimerUsage() must be called at least once before calling
+ // GetHighResolutionTimerUsage(); otherwise the usage result would be
+ // undefined.
+ static void ResetHighResolutionTimerUsage();
+ static double GetHighResolutionTimerUsage();
+#endif // defined(OS_WIN)
+
+ // Converts an exploded structure representing either the local time or UTC
+ // into a Time class. Returns false on a failure when, for example, a day of
+ // month is set to 31 on a 28-30 day month. Returns Time(0) on overflow.
+ static bool FromUTCExploded(const Exploded& exploded,
+ Time* time) WARN_UNUSED_RESULT {
+ return FromExploded(false, exploded, time);
+ }
+ static bool FromLocalExploded(const Exploded& exploded,
+ Time* time) WARN_UNUSED_RESULT {
+ return FromExploded(true, exploded, time);
+ }
+
+ // Converts a string representation of time to a Time object.
+ // An example of a time string which is converted is as below:-
+ // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+ // in the input string, FromString assumes local time and FromUTCString
+ // assumes UTC. A timezone that cannot be parsed (e.g. "UTC" which is not
+ // specified in RFC822) is treated as if the timezone is not specified.
+ //
+ // WARNING: the underlying converter is very permissive. For example: it is
+ // not checked whether a given day of the week matches the date; Feb 29
+ // silently becomes Mar 1 in non-leap years; under certain conditions, whole
+ // English sentences may be parsed successfully and yield unexpected results.
+ //
+ // TODO(iyengar) Move the FromString/FromTimeT/ToTimeT/FromFileTime to
+ // a new time converter class.
+ static bool FromString(const char* time_string,
+ Time* parsed_time) WARN_UNUSED_RESULT {
+ return FromStringInternal(time_string, true, parsed_time);
+ }
+ static bool FromUTCString(const char* time_string,
+ Time* parsed_time) WARN_UNUSED_RESULT {
+ return FromStringInternal(time_string, false, parsed_time);
+ }
+
+ // Fills the given exploded structure with either the local time or UTC from
+ // this time structure (containing UTC).
+ void UTCExplode(Exploded* exploded) const {
+ return Explode(false, exploded);
+ }
+ void LocalExplode(Exploded* exploded) const {
+ return Explode(true, exploded);
+ }
+
+ // The following two functions round down the time to the nearest day in
+ // either UTC or local time. It will represent midnight on that day.
+ Time UTCMidnight() const { return Midnight(false); }
+ Time LocalMidnight() const { return Midnight(true); }
+
+ // Converts an integer value representing Time to a class. This may be used
+ // when deserializing a |Time| structure, using a value known to be
+ // compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ //
+ // DEPRECATED - Do not use in new code. For deserializing Time values, prefer
+ // Time::FromDeltaSinceWindowsEpoch(). http://crbug.com/634507
+ static constexpr Time FromInternalValue(int64_t us) { return Time(us); }
+
+ private:
+ friend class time_internal::TimeBase<Time>;
+
+ constexpr explicit Time(int64_t microseconds_since_win_epoch)
+ : TimeBase(microseconds_since_win_epoch) {}
+
+ // Explodes the given time to either local time |is_local = true| or UTC
+ // |is_local = false|.
+ void Explode(bool is_local, Exploded* exploded) const;
+
+ // Unexplodes a given time assuming the source is either local time
+ // |is_local = true| or UTC |is_local = false|. Function returns false on
+ // failure and sets |time| to Time(0). Otherwise returns true and sets |time|
+ // to non-exploded time.
+ static bool FromExploded(bool is_local,
+ const Exploded& exploded,
+ Time* time) WARN_UNUSED_RESULT;
+
+ // Rounds down the time to the nearest day in either local time
+ // |is_local = true| or UTC |is_local = false|.
+ Time Midnight(bool is_local) const;
+
+ // Converts a string representation of time to a Time object.
+ // An example of a time string which is converted is as below:-
+ // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+ // in the input string, local time |is_local = true| or
+ // UTC |is_local = false| is assumed. A timezone that cannot be parsed
+ // (e.g. "UTC" which is not specified in RFC822) is treated as if the
+ // timezone is not specified.
+ static bool FromStringInternal(const char* time_string,
+ bool is_local,
+ Time* parsed_time) WARN_UNUSED_RESULT;
+
+ // Comparison does not consider |day_of_week| when doing the operation.
+ static bool ExplodedMostlyEquals(const Exploded& lhs,
+ const Exploded& rhs) WARN_UNUSED_RESULT;
+
+ // Converts the provided time in milliseconds since the Unix epoch (1970) to a
+ // Time object, avoiding overflows.
+ static bool FromMillisecondsSinceUnixEpoch(int64_t unix_milliseconds,
+ Time* time) WARN_UNUSED_RESULT;
+
+ // Returns the milliseconds since the Unix epoch (1970), rounding the
+ // microseconds towards -infinity.
+ int64_t ToRoundedDownMillisecondsSinceUnixEpoch() const;
+};
+
+// static
+constexpr TimeDelta TimeDelta::FromDays(int days) {
+ return days == std::numeric_limits<int>::max()
+ ? Max()
+ : TimeDelta(days * Time::kMicrosecondsPerDay);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromHours(int hours) {
+ return hours == std::numeric_limits<int>::max()
+ ? Max()
+ : TimeDelta(hours * Time::kMicrosecondsPerHour);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMinutes(int minutes) {
+ return minutes == std::numeric_limits<int>::max()
+ ? Max()
+ : TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromSeconds(int64_t secs) {
+ return FromProduct(secs, Time::kMicrosecondsPerSecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMilliseconds(int64_t ms) {
+ return FromProduct(ms, Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMicroseconds(int64_t us) {
+ return TimeDelta(us);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromNanoseconds(int64_t ns) {
+ return TimeDelta(ns / Time::kNanosecondsPerMicrosecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromSecondsD(double secs) {
+ return FromDouble(secs * Time::kMicrosecondsPerSecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMillisecondsD(double ms) {
+ return FromDouble(ms * Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromMicrosecondsD(double us) {
+ return FromDouble(us);
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromNanosecondsD(double ns) {
+ return FromDouble(ns / Time::kNanosecondsPerMicrosecond);
+}
+
+// static
+constexpr TimeDelta TimeDelta::Max() {
+ return TimeDelta(std::numeric_limits<int64_t>::max());
+}
+
+// static
+constexpr TimeDelta TimeDelta::Min() {
+ return TimeDelta(std::numeric_limits<int64_t>::min());
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromDouble(double value) {
+ return TimeDelta(saturated_cast<int64_t>(value));
+}
+
+// static
+constexpr TimeDelta TimeDelta::FromProduct(int64_t value,
+ int64_t positive_value) {
+ DCHECK(positive_value > 0); // NOLINT, DCHECK_GT isn't constexpr.
+ return value > std::numeric_limits<int64_t>::max() / positive_value
+ ? Max()
+ : value < std::numeric_limits<int64_t>::min() / positive_value
+ ? Min()
+ : TimeDelta(value * positive_value);
+}
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time);
+
+// TimeTicks ------------------------------------------------------------------
+
+// Represents monotonically non-decreasing clock time.
+class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
+ public:
+ // The underlying clock used to generate new TimeTicks.
+ enum class Clock {
+ FUCHSIA_ZX_CLOCK_MONOTONIC,
+ LINUX_CLOCK_MONOTONIC,
+ IOS_CF_ABSOLUTE_TIME_MINUS_KERN_BOOTTIME,
+ MAC_MACH_ABSOLUTE_TIME,
+ WIN_QPC,
+ WIN_ROLLOVER_PROTECTED_TIME_GET_TIME
+ };
+
+ constexpr TimeTicks() : TimeBase(0) {}
+
+ // Platform-dependent tick count representing "right now." When
+ // IsHighResolution() returns false, the resolution of the clock could be
+ // as coarse as ~15.6ms. Otherwise, the resolution should be no worse than one
+ // microsecond.
+ static TimeTicks Now();
+
+ // Returns true if the high resolution clock is working on this system and
+ // Now() will return high resolution values. Note that, on systems where the
+ // high resolution clock works but is deemed inefficient, the low resolution
+ // clock will be used instead.
+ static bool IsHighResolution() WARN_UNUSED_RESULT;
+
+ // Returns true if TimeTicks is consistent across processes, meaning that
+ // timestamps taken on different processes can be safely compared with one
+ // another. (Note that, even on platforms where this returns true, time values
+ // from different threads that are within one tick of each other must be
+ // considered to have an ambiguous ordering.)
+ static bool IsConsistentAcrossProcesses() WARN_UNUSED_RESULT;
+
+#if defined(OS_FUCHSIA)
+ // Converts between TimeTicks and an ZX_CLOCK_MONOTONIC zx_time_t value.
+ static TimeTicks FromZxTime(zx_time_t nanos_since_boot);
+ zx_time_t ToZxTime() const;
+#endif
+
+#if defined(OS_WIN)
+ // Translates an absolute QPC timestamp into a TimeTicks value. The returned
+ // value has the same origin as Now(). Do NOT attempt to use this if
+ // IsHighResolution() returns false.
+ static TimeTicks FromQPCValue(LONGLONG qpc_value);
+#endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ static TimeTicks FromMachAbsoluteTime(uint64_t mach_absolute_time);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+ // Converts to TimeTicks the value obtained from SystemClock.uptimeMillis().
+ // Note: this convertion may be non-monotonic in relation to previously
+ // obtained TimeTicks::Now() values because of the truncation (to
+ // milliseconds) performed by uptimeMillis().
+ static TimeTicks FromUptimeMillis(int64_t uptime_millis_value);
+#endif
+
+ // Get an estimate of the TimeTick value at the time of the UnixEpoch. Because
+ // Time and TimeTicks respond differently to user-set time and NTP
+ // adjustments, this number is only an estimate. Nevertheless, this can be
+ // useful when you need to relate the value of TimeTicks to a real time and
+ // date. Note: Upon first invocation, this function takes a snapshot of the
+ // realtime clock to establish a reference point. This function will return
+ // the same value for the duration of the application, but will be different
+ // in future application runs.
+ static TimeTicks UnixEpoch();
+
+ // Returns |this| snapped to the next tick, given a |tick_phase| and
+ // repeating |tick_interval| in both directions. |this| may be before,
+ // after, or equal to the |tick_phase|.
+ TimeTicks SnappedToNextTick(TimeTicks tick_phase,
+ TimeDelta tick_interval) const;
+
+ // Returns an enum indicating the underlying clock being used to generate
+ // TimeTicks timestamps. This function should only be used for debugging and
+ // logging purposes.
+ static Clock GetClock();
+
+ // Converts an integer value representing TimeTicks to a class. This may be
+ // used when deserializing a |TimeTicks| structure, using a value known to be
+ // compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ //
+ // DEPRECATED - Do not use in new code. For deserializing TimeTicks values,
+ // prefer TimeTicks + TimeDelta(). http://crbug.com/634507
+ static constexpr TimeTicks FromInternalValue(int64_t us) {
+ return TimeTicks(us);
+ }
+
+ protected:
+#if defined(OS_WIN)
+ typedef DWORD (*TickFunctionType)(void);
+ static TickFunctionType SetMockTickFunction(TickFunctionType ticker);
+#endif
+
+ private:
+ friend class time_internal::TimeBase<TimeTicks>;
+
+ // Please use Now() to create a new object. This is for internal use
+ // and testing.
+ constexpr explicit TimeTicks(int64_t us) : TimeBase(us) {}
+};
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks);
+
+// ThreadTicks ----------------------------------------------------------------
+
+// Represents a clock, specific to a particular thread, than runs only while the
+// thread is running.
+class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
+ public:
+ constexpr ThreadTicks() : TimeBase(0) {}
+
+ // Returns true if ThreadTicks::Now() is supported on this system.
+ static bool IsSupported() WARN_UNUSED_RESULT {
+#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID) || \
+ defined(OS_FUCHSIA)
+ return true;
+#elif defined(OS_WIN)
+ return IsSupportedWin();
+#else
+ return false;
+#endif
+ }
+
+ // Waits until the initialization is completed. Needs to be guarded with a
+ // call to IsSupported().
+ static void WaitUntilInitialized() {
+#if defined(OS_WIN)
+ WaitUntilInitializedWin();
+#endif
+ }
+
+ // Returns thread-specific CPU-time on systems that support this feature.
+ // Needs to be guarded with a call to IsSupported(). Use this timer
+ // to (approximately) measure how much time the calling thread spent doing
+ // actual work vs. being de-scheduled. May return bogus results if the thread
+ // migrates to another CPU between two calls. Returns an empty ThreadTicks
+ // object until the initialization is completed. If a clock reading is
+ // absolutely needed, call WaitUntilInitialized() before this method.
+ static ThreadTicks Now();
+
+#if defined(OS_WIN)
+ // Similar to Now() above except this returns thread-specific CPU time for an
+ // arbitrary thread. All comments for Now() method above apply apply to this
+ // method as well.
+ static ThreadTicks GetForThread(const PlatformThreadHandle& thread_handle);
+#endif
+
+ // Converts an integer value representing ThreadTicks to a class. This may be
+ // used when deserializing a |ThreadTicks| structure, using a value known to
+ // be compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ //
+ // DEPRECATED - Do not use in new code. For deserializing ThreadTicks values,
+ // prefer ThreadTicks + TimeDelta(). http://crbug.com/634507
+ static constexpr ThreadTicks FromInternalValue(int64_t us) {
+ return ThreadTicks(us);
+ }
+
+ private:
+ friend class time_internal::TimeBase<ThreadTicks>;
+
+ // Please use Now() or GetForThread() to create a new object. This is for
+ // internal use and testing.
+ constexpr explicit ThreadTicks(int64_t us) : TimeBase(us) {}
+
+#if defined(OS_WIN)
+ FRIEND_TEST_ALL_PREFIXES(TimeTicks, TSCTicksPerSecond);
+
+#if defined(ARCH_CPU_ARM64)
+ // TSCTicksPerSecond is not supported on Windows on Arm systems because the
+ // cycle-counting methods use the actual CPU cycle count, and not a consistent
+ // incrementing counter.
+#else
+ // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't
+ // been measured yet. Needs to be guarded with a call to IsSupported().
+ // This method is declared here rather than in the anonymous namespace to
+ // allow testing.
+ static double TSCTicksPerSecond();
+#endif
+
+ static bool IsSupportedWin() WARN_UNUSED_RESULT;
+ static void WaitUntilInitializedWin();
+#endif
+};
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
+
+} // namespace base
+
+#endif // BASE_TIME_TIME_H_
diff --git a/security/sandbox/chromium/base/time/time_exploded_posix.cc b/security/sandbox/chromium/base/time/time_exploded_posix.cc
new file mode 100644
index 0000000000..ca8a7880bf
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time_exploded_posix.cc
@@ -0,0 +1,287 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <time.h>
+#if defined(OS_ANDROID) && !defined(__LP64__)
+#include <time64.h>
+#endif
+#include <unistd.h>
+
+#include <limits>
+
+#include "base/numerics/safe_math.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#elif defined(OS_NACL)
+#include "base/os_compat_nacl.h"
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_IOS)
+static_assert(sizeof(time_t) >= 8, "Y2038 problem!");
+#endif
+
+namespace {
+
+// This prevents a crash on traversing the environment global and looking up
+// the 'TZ' variable in libc. See: crbug.com/390567.
+base::Lock* GetSysTimeToTimeStructLock() {
+ static auto* lock = new base::Lock();
+ return lock;
+}
+
+// Define a system-specific SysTime that wraps either to a time_t or
+// a time64_t depending on the host system, and associated convertion.
+// See crbug.com/162007
+#if defined(OS_ANDROID) && !defined(__LP64__)
+typedef time64_t SysTime;
+
+SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
+ base::AutoLock locked(*GetSysTimeToTimeStructLock());
+ if (is_local)
+ return mktime64(timestruct);
+ else
+ return timegm64(timestruct);
+}
+
+void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
+ base::AutoLock locked(*GetSysTimeToTimeStructLock());
+ if (is_local)
+ localtime64_r(&t, timestruct);
+ else
+ gmtime64_r(&t, timestruct);
+}
+#elif defined(OS_AIX)
+// The function timegm is not available on AIX.
+time_t aix_timegm(struct tm* tm) {
+ time_t ret;
+ char* tz;
+
+ tz = getenv("TZ");
+ if (tz) {
+ tz = strdup(tz);
+ }
+ setenv("TZ", "GMT0", 1);
+ tzset();
+ ret = mktime(tm);
+ if (tz) {
+ setenv("TZ", tz, 1);
+ free(tz);
+ } else {
+ unsetenv("TZ");
+ }
+ tzset();
+ return ret;
+}
+
+typedef time_t SysTime;
+
+SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
+ base::AutoLock locked(*GetSysTimeToTimeStructLock());
+ if (is_local)
+ return mktime(timestruct);
+ else
+ return aix_timegm(timestruct);
+}
+
+void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
+ base::AutoLock locked(*GetSysTimeToTimeStructLock());
+ if (is_local)
+ localtime_r(&t, timestruct);
+ else
+ gmtime_r(&t, timestruct);
+}
+
+#else
+typedef time_t SysTime;
+
+SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
+ base::AutoLock locked(*GetSysTimeToTimeStructLock());
+ return is_local ? mktime(timestruct) : timegm(timestruct);
+}
+
+void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
+ base::AutoLock locked(*GetSysTimeToTimeStructLock());
+ if (is_local)
+ localtime_r(&t, timestruct);
+ else
+ gmtime_r(&t, timestruct);
+}
+#endif // defined(OS_ANDROID) && !defined(__LP64__)
+
+} // namespace
+
+namespace base {
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+ // The following values are all rounded towards -infinity.
+ int64_t milliseconds = ToRoundedDownMillisecondsSinceUnixEpoch();
+ SysTime seconds; // Seconds since epoch.
+ int millisecond; // Exploded millisecond value (0-999).
+
+ // If the microseconds were negative, the rounded down milliseconds will also
+ // be negative. For example, -1 us becomes -1 ms.
+ if (milliseconds >= 0) {
+ // Rounding towards -infinity <=> rounding towards 0, in this case.
+ seconds = milliseconds / kMillisecondsPerSecond;
+ millisecond = milliseconds % kMillisecondsPerSecond;
+ } else {
+ // Round these *down* (towards -infinity).
+ seconds =
+ (milliseconds - kMillisecondsPerSecond + 1) / kMillisecondsPerSecond;
+ // Make this nonnegative (and between 0 and 999 inclusive).
+ millisecond = milliseconds % kMillisecondsPerSecond;
+ if (millisecond < 0)
+ millisecond += kMillisecondsPerSecond;
+ }
+
+ struct tm timestruct;
+ SysTimeToTimeStruct(seconds, &timestruct, is_local);
+
+ exploded->year = timestruct.tm_year + 1900;
+ exploded->month = timestruct.tm_mon + 1;
+ exploded->day_of_week = timestruct.tm_wday;
+ exploded->day_of_month = timestruct.tm_mday;
+ exploded->hour = timestruct.tm_hour;
+ exploded->minute = timestruct.tm_min;
+ exploded->second = timestruct.tm_sec;
+ exploded->millisecond = millisecond;
+}
+
+// static
+bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
+ CheckedNumeric<int> month = exploded.month;
+ month--;
+ CheckedNumeric<int> year = exploded.year;
+ year -= 1900;
+ if (!month.IsValid() || !year.IsValid()) {
+ *time = Time(0);
+ return false;
+ }
+
+ struct tm timestruct;
+ timestruct.tm_sec = exploded.second;
+ timestruct.tm_min = exploded.minute;
+ timestruct.tm_hour = exploded.hour;
+ timestruct.tm_mday = exploded.day_of_month;
+ timestruct.tm_mon = month.ValueOrDie();
+ timestruct.tm_year = year.ValueOrDie();
+ timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this
+ timestruct.tm_yday = 0; // mktime/timegm ignore this
+ timestruct.tm_isdst = -1; // attempt to figure it out
+#if !defined(OS_NACL) && !defined(OS_SOLARIS) && !defined(OS_AIX)
+ timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore
+ timestruct.tm_zone = nullptr; // not a POSIX field, so mktime/timegm ignore
+#endif
+
+ SysTime seconds;
+
+ // Certain exploded dates do not really exist due to daylight saving times,
+ // and this causes mktime() to return implementation-defined values when
+ // tm_isdst is set to -1. On Android, the function will return -1, while the
+ // C libraries of other platforms typically return a liberally-chosen value.
+ // Handling this requires the special code below.
+
+ // SysTimeFromTimeStruct() modifies the input structure, save current value.
+ struct tm timestruct0 = timestruct;
+
+ seconds = SysTimeFromTimeStruct(&timestruct, is_local);
+ if (seconds == -1) {
+ // Get the time values with tm_isdst == 0 and 1, then select the closest one
+ // to UTC 00:00:00 that isn't -1.
+ timestruct = timestruct0;
+ timestruct.tm_isdst = 0;
+ int64_t seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+ timestruct = timestruct0;
+ timestruct.tm_isdst = 1;
+ int64_t seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+ // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
+ // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
+ if (seconds_isdst0 < 0)
+ seconds = seconds_isdst1;
+ else if (seconds_isdst1 < 0)
+ seconds = seconds_isdst0;
+ else
+ seconds = std::min(seconds_isdst0, seconds_isdst1);
+ }
+
+ // Handle overflow. Clamping the range to what mktime and timegm might
+ // return is the best that can be done here. It's not ideal, but it's better
+ // than failing here or ignoring the overflow case and treating each time
+ // overflow as one second prior to the epoch.
+ int64_t milliseconds = 0;
+ if (seconds == -1 && (exploded.year < 1969 || exploded.year > 1970)) {
+ // If exploded.year is 1969 or 1970, take -1 as correct, with the
+ // time indicating 1 second prior to the epoch. (1970 is allowed to handle
+ // time zone and DST offsets.) Otherwise, return the most future or past
+ // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
+ //
+ // The minimum and maximum representible times that mktime and timegm could
+ // return are used here instead of values outside that range to allow for
+ // proper round-tripping between exploded and counter-type time
+ // representations in the presence of possible truncation to time_t by
+ // division and use with other functions that accept time_t.
+ //
+ // When representing the most distant time in the future, add in an extra
+ // 999ms to avoid the time being less than any other possible value that
+ // this function can return.
+
+ // On Android, SysTime is int64_t, special care must be taken to avoid
+ // overflows.
+ const int64_t min_seconds = (sizeof(SysTime) < sizeof(int64_t))
+ ? std::numeric_limits<SysTime>::min()
+ : std::numeric_limits<int32_t>::min();
+ const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t))
+ ? std::numeric_limits<SysTime>::max()
+ : std::numeric_limits<int32_t>::max();
+ if (exploded.year < 1969) {
+ milliseconds = min_seconds * kMillisecondsPerSecond;
+ } else {
+ milliseconds = max_seconds * kMillisecondsPerSecond;
+ milliseconds += (kMillisecondsPerSecond - 1);
+ }
+ } else {
+ CheckedNumeric<int64_t> checked_millis = seconds;
+ checked_millis *= kMillisecondsPerSecond;
+ checked_millis += exploded.millisecond;
+ if (!checked_millis.IsValid()) {
+ *time = Time(0);
+ return false;
+ }
+ milliseconds = checked_millis.ValueOrDie();
+ }
+
+ Time converted_time;
+ if (!FromMillisecondsSinceUnixEpoch(milliseconds, &converted_time)) {
+ *time = base::Time(0);
+ return false;
+ }
+
+ // If |exploded.day_of_month| is set to 31 on a 28-30 day month, it will
+ // return the first day of the next month. Thus round-trip the time and
+ // compare the initial |exploded| with |utc_to_exploded| time.
+ Time::Exploded to_exploded;
+ if (!is_local)
+ converted_time.UTCExplode(&to_exploded);
+ else
+ converted_time.LocalExplode(&to_exploded);
+
+ if (ExplodedMostlyEquals(to_exploded, exploded)) {
+ *time = converted_time;
+ return true;
+ }
+
+ *time = Time(0);
+ return false;
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/time/time_now_posix.cc b/security/sandbox/chromium/base/time/time_now_posix.cc
new file mode 100644
index 0000000000..4ce93c0811
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time_now_posix.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time.h"
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <time.h>
+#if defined(OS_ANDROID) && !defined(__LP64__)
+#include <time64.h>
+#endif
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "base/time/time_override.h"
+#include "build/build_config.h"
+
+// Ensure the Fuchsia and Mac builds do not include this module. Instead,
+// non-POSIX implementation is used for sampling the system clocks.
+#if defined(OS_FUCHSIA) || defined(OS_MACOSX)
+#error "This implementation is for POSIX platforms other than Fuchsia or Mac."
+#endif
+
+namespace {
+
+int64_t ConvertTimespecToMicros(const struct timespec& ts) {
+ // On 32-bit systems, the calculation cannot overflow int64_t.
+ // 2**32 * 1000000 + 2**64 / 1000 < 2**63
+ if (sizeof(ts.tv_sec) <= 4 && sizeof(ts.tv_nsec) <= 8) {
+ int64_t result = ts.tv_sec;
+ result *= base::Time::kMicrosecondsPerSecond;
+ result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
+ return result;
+ }
+ base::CheckedNumeric<int64_t> result(ts.tv_sec);
+ result *= base::Time::kMicrosecondsPerSecond;
+ result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
+ return result.ValueOrDie();
+}
+
+// Helper function to get results from clock_gettime() and convert to a
+// microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
+// on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
+// _POSIX_MONOTONIC_CLOCK to -1.
+#if (defined(OS_POSIX) && defined(_POSIX_MONOTONIC_CLOCK) && \
+ _POSIX_MONOTONIC_CLOCK >= 0) || \
+ defined(OS_BSD) || defined(OS_ANDROID)
+int64_t ClockNow(clockid_t clk_id) {
+ struct timespec ts;
+ CHECK(clock_gettime(clk_id, &ts) == 0);
+ return ConvertTimespecToMicros(ts);
+}
+#else // _POSIX_MONOTONIC_CLOCK
+#error No usable tick clock function on this platform.
+#endif // _POSIX_MONOTONIC_CLOCK
+
+} // namespace
+
+namespace base {
+
+// Time -----------------------------------------------------------------------
+
+namespace subtle {
+Time TimeNowIgnoringOverride() {
+ struct timeval tv;
+ struct timezone tz = {0, 0}; // UTC
+ CHECK(gettimeofday(&tv, &tz) == 0);
+ // Combine seconds and microseconds in a 64-bit field containing microseconds
+ // since the epoch. That's enough for nearly 600 centuries. Adjust from
+ // Unix (1970) to Windows (1601) epoch.
+ return Time() + TimeDelta::FromMicroseconds(
+ (tv.tv_sec * Time::kMicrosecondsPerSecond + tv.tv_usec) +
+ Time::kTimeTToMicrosecondsOffset);
+}
+
+Time TimeNowFromSystemTimeIgnoringOverride() {
+ // Just use TimeNowIgnoringOverride() because it returns the system time.
+ return TimeNowIgnoringOverride();
+}
+} // namespace subtle
+
+// TimeTicks ------------------------------------------------------------------
+
+namespace subtle {
+TimeTicks TimeTicksNowIgnoringOverride() {
+ return TimeTicks() + TimeDelta::FromMicroseconds(ClockNow(CLOCK_MONOTONIC));
+}
+} // namespace subtle
+
+// static
+TimeTicks::Clock TimeTicks::GetClock() {
+ return Clock::LINUX_CLOCK_MONOTONIC;
+}
+
+// static
+bool TimeTicks::IsHighResolution() {
+ return true;
+}
+
+// static
+bool TimeTicks::IsConsistentAcrossProcesses() {
+ return true;
+}
+
+// ThreadTicks ----------------------------------------------------------------
+
+namespace subtle {
+ThreadTicks ThreadTicksNowIgnoringOverride() {
+#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
+ defined(OS_ANDROID)
+ return ThreadTicks() +
+ TimeDelta::FromMicroseconds(ClockNow(CLOCK_THREAD_CPUTIME_ID));
+#else
+ NOTREACHED();
+ return ThreadTicks();
+#endif
+}
+} // namespace subtle
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/time/time_override.h b/security/sandbox/chromium/base/time/time_override.h
new file mode 100644
index 0000000000..ad3180c62a
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time_override.h
@@ -0,0 +1,74 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIME_TIME_OVERRIDE_H_
+#define BASE_TIME_TIME_OVERRIDE_H_
+
+#include "base/base_export.h"
+#include "base/time/time.h"
+
+namespace base {
+
+using TimeNowFunction = decltype(&Time::Now);
+using TimeTicksNowFunction = decltype(&TimeTicks::Now);
+using ThreadTicksNowFunction = decltype(&ThreadTicks::Now);
+
+// Time overrides should be used with extreme caution. Discuss with //base/time
+// OWNERS before adding a new one.
+namespace subtle {
+
+// Override the return value of Time::Now and Time::NowFromSystemTime /
+// TimeTicks::Now / ThreadTicks::Now to emulate time, e.g. for tests or to
+// modify progression of time. Note that the override should be set while
+// single-threaded and before the first call to Now() to avoid threading issues
+// and inconsistencies in returned values. Nested overrides are not allowed.
+class BASE_EXPORT ScopedTimeClockOverrides {
+ public:
+ // Pass |nullptr| for any override if it shouldn't be overriden.
+ ScopedTimeClockOverrides(TimeNowFunction time_override,
+ TimeTicksNowFunction time_ticks_override,
+ ThreadTicksNowFunction thread_ticks_override);
+
+ // Restores the platform default Now() functions.
+ ~ScopedTimeClockOverrides();
+
+ static bool overrides_active() { return overrides_active_; }
+
+ private:
+ static bool overrides_active_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTimeClockOverrides);
+};
+
+// These methods return the platform default Time::Now / TimeTicks::Now /
+// ThreadTicks::Now values even while an override is in place. These methods
+// should only be used in places where emulated time should be disregarded. For
+// example, they can be used to implement test timeouts for tests that may
+// override time.
+BASE_EXPORT Time TimeNowIgnoringOverride();
+BASE_EXPORT Time TimeNowFromSystemTimeIgnoringOverride();
+BASE_EXPORT TimeTicks TimeTicksNowIgnoringOverride();
+BASE_EXPORT ThreadTicks ThreadTicksNowIgnoringOverride();
+
+} // namespace subtle
+
+namespace internal {
+
+// These function pointers are used by platform-independent implementations of
+// the Now() methods and ScopedTimeClockOverrides. They are set to point to the
+// respective NowIgnoringOverride functions by default, but can also be set by
+// platform-specific code to select a default implementation at runtime, thereby
+// avoiding the indirection via the NowIgnoringOverride functions. Note that the
+// pointers can be overridden and later reset to the NowIgnoringOverride
+// functions by ScopedTimeClockOverrides.
+extern TimeNowFunction g_time_now_function;
+extern TimeNowFunction g_time_now_from_system_time_function;
+extern TimeTicksNowFunction g_time_ticks_now_function;
+extern ThreadTicksNowFunction g_thread_ticks_now_function;
+
+} // namespace internal
+
+} // namespace base
+
+#endif // BASE_TIME_TIME_OVERRIDE_H_
diff --git a/security/sandbox/chromium/base/time/time_win.cc b/security/sandbox/chromium/base/time/time_win.cc
new file mode 100644
index 0000000000..c1976e64a6
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time_win.cc
@@ -0,0 +1,810 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+// Windows Timer Primer
+//
+// A good article: http://www.ddj.com/windows/184416651
+// A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258
+//
+// The default windows timer, GetSystemTimeAsFileTime is not very precise.
+// It is only good to ~15.5ms.
+//
+// QueryPerformanceCounter is the logical choice for a high-precision timer.
+// However, it is known to be buggy on some hardware. Specifically, it can
+// sometimes "jump". On laptops, QPC can also be very expensive to call.
+// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
+// on laptops. A unittest exists which will show the relative cost of various
+// timers on any system.
+//
+// The next logical choice is timeGetTime(). timeGetTime has a precision of
+// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
+// applications on the system. By default, precision is only 15.5ms.
+// Unfortunately, we don't want to call timeBeginPeriod because we don't
+// want to affect other applications. Further, on mobile platforms, use of
+// faster multimedia timers can hurt battery life. See the intel
+// article about this here:
+// http://softwarecommunity.intel.com/articles/eng/1086.htm
+//
+// To work around all this, we're going to generally use timeGetTime(). We
+// will only increase the system-wide timer if we're not running on battery
+// power.
+
+#include "base/time/time.h"
+
+#include <windows.foundation.h>
+#include <windows.h>
+#include <mmsystem.h>
+#include <stdint.h>
+
+#include "base/atomicops.h"
+#include "base/bit_cast.h"
+#include "base/cpu.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time_override.h"
+#include "base/time/time_win_features.h"
+
+namespace base {
+
+namespace {
+
+// From MSDN, FILETIME "Contains a 64-bit value representing the number of
+// 100-nanosecond intervals since January 1, 1601 (UTC)."
+int64_t FileTimeToMicroseconds(const FILETIME& ft) {
+ // Need to bit_cast to fix alignment, then divide by 10 to convert
+ // 100-nanoseconds to microseconds. This only works on little-endian
+ // machines.
+ return bit_cast<int64_t, FILETIME>(ft) / 10;
+}
+
+void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
+ DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
+ "representable in FILETIME";
+
+ // Multiply by 10 to convert microseconds to 100-nanoseconds. Bit_cast will
+ // handle alignment problems. This only works on little-endian machines.
+ *ft = bit_cast<FILETIME, int64_t>(us * 10);
+}
+
+int64_t CurrentWallclockMicroseconds() {
+ FILETIME ft;
+ ::GetSystemTimeAsFileTime(&ft);
+ return FileTimeToMicroseconds(ft);
+}
+
+// Time between resampling the un-granular clock for this API.
+constexpr TimeDelta kMaxTimeToAvoidDrift = TimeDelta::FromSeconds(60);
+
+int64_t g_initial_time = 0;
+TimeTicks g_initial_ticks;
+
+void InitializeClock() {
+ g_initial_ticks = subtle::TimeTicksNowIgnoringOverride();
+ g_initial_time = CurrentWallclockMicroseconds();
+}
+
+// Interval to use when on DC power.
+UINT g_battery_power_interval_ms = 4;
+// Track the last value passed to timeBeginPeriod so that we can cancel that
+// call by calling timeEndPeriod with the same value. A value of zero means that
+// the timer frequency is not currently raised.
+UINT g_last_interval_requested_ms = 0;
+// Track if MinTimerIntervalHighResMs() or MinTimerIntervalLowResMs() is active.
+// For most purposes this could also be named g_is_on_ac_power.
+bool g_high_res_timer_enabled = false;
+// How many times the high resolution timer has been called.
+uint32_t g_high_res_timer_count = 0;
+// Start time of the high resolution timer usage monitoring. This is needed
+// to calculate the usage as percentage of the total elapsed time.
+TimeTicks g_high_res_timer_usage_start;
+// The cumulative time the high resolution timer has been in use since
+// |g_high_res_timer_usage_start| moment.
+TimeDelta g_high_res_timer_usage;
+// Timestamp of the last activation change of the high resolution timer. This
+// is used to calculate the cumulative usage.
+TimeTicks g_high_res_timer_last_activation;
+// The lock to control access to the above set of variables.
+Lock* GetHighResLock() {
+ static auto* lock = new Lock();
+ return lock;
+}
+
+// The two values that ActivateHighResolutionTimer uses to set the systemwide
+// timer interrupt frequency on Windows. These control how precise timers are
+// but also have a big impact on battery life.
+
+// Used when a faster timer has been requested (g_high_res_timer_count > 0) and
+// the computer is running on AC power (plugged in) so that it's okay to go to
+// the highest frequency.
+UINT MinTimerIntervalHighResMs() {
+ return 1;
+}
+
+// Used when a faster timer has been requested (g_high_res_timer_count > 0) and
+// the computer is running on DC power (battery) so that we don't want to raise
+// the timer frequency as much.
+UINT MinTimerIntervalLowResMs() {
+ return g_battery_power_interval_ms;
+}
+
+// Calculate the desired timer interrupt interval. Note that zero means that the
+// system default should be used.
+UINT GetIntervalMs() {
+ if (!g_high_res_timer_count)
+ return 0; // Use the default, typically 15.625
+ if (g_high_res_timer_enabled)
+ return MinTimerIntervalHighResMs();
+ return MinTimerIntervalLowResMs();
+}
+
+// Compare the currently requested timer interrupt interval to the last interval
+// requested and update if necessary (by cancelling the old request and making a
+// new request). If there is no change then do nothing.
+void UpdateTimerIntervalLocked() {
+ UINT new_interval = GetIntervalMs();
+ if (new_interval == g_last_interval_requested_ms)
+ return;
+ if (g_last_interval_requested_ms) {
+ // Record how long the timer interrupt frequency was raised.
+ g_high_res_timer_usage += subtle::TimeTicksNowIgnoringOverride() -
+ g_high_res_timer_last_activation;
+ // Reset the timer interrupt back to the default.
+ timeEndPeriod(g_last_interval_requested_ms);
+ }
+ g_last_interval_requested_ms = new_interval;
+ if (g_last_interval_requested_ms) {
+ // Record when the timer interrupt was raised.
+ g_high_res_timer_last_activation = subtle::TimeTicksNowIgnoringOverride();
+ timeBeginPeriod(g_last_interval_requested_ms);
+ }
+}
+
+// Returns the current value of the performance counter.
+uint64_t QPCNowRaw() {
+ LARGE_INTEGER perf_counter_now = {};
+ // According to the MSDN documentation for QueryPerformanceCounter(), this
+ // will never fail on systems that run XP or later.
+ // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
+ ::QueryPerformanceCounter(&perf_counter_now);
+ return perf_counter_now.QuadPart;
+}
+
+bool SafeConvertToWord(int in, WORD* out) {
+ CheckedNumeric<WORD> result = in;
+ *out = result.ValueOrDefault(std::numeric_limits<WORD>::max());
+ return result.IsValid();
+}
+
+} // namespace
+
+// Time -----------------------------------------------------------------------
+
+namespace subtle {
+Time TimeNowIgnoringOverride() {
+ if (g_initial_time == 0)
+ InitializeClock();
+
+ // We implement time using the high-resolution timers so that we can get
+ // timeouts which are smaller than 10-15ms. If we just used
+ // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
+ //
+ // To make this work, we initialize the clock (g_initial_time) and the
+ // counter (initial_ctr). To compute the initial time, we can check
+ // the number of ticks that have elapsed, and compute the delta.
+ //
+ // To avoid any drift, we periodically resync the counters to the system
+ // clock.
+ while (true) {
+ TimeTicks ticks = TimeTicksNowIgnoringOverride();
+
+ // Calculate the time elapsed since we started our timer
+ TimeDelta elapsed = ticks - g_initial_ticks;
+
+ // Check if enough time has elapsed that we need to resync the clock.
+ if (elapsed > kMaxTimeToAvoidDrift) {
+ InitializeClock();
+ continue;
+ }
+
+ return Time() + elapsed + TimeDelta::FromMicroseconds(g_initial_time);
+ }
+}
+
+Time TimeNowFromSystemTimeIgnoringOverride() {
+ // Force resync.
+ InitializeClock();
+ return Time() + TimeDelta::FromMicroseconds(g_initial_time);
+}
+} // namespace subtle
+
+// static
+Time Time::FromFileTime(FILETIME ft) {
+ if (bit_cast<int64_t, FILETIME>(ft) == 0)
+ return Time();
+ if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
+ ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
+ return Max();
+ return Time(FileTimeToMicroseconds(ft));
+}
+
+FILETIME Time::ToFileTime() const {
+ if (is_null())
+ return bit_cast<FILETIME, int64_t>(0);
+ if (is_max()) {
+ FILETIME result;
+ result.dwHighDateTime = std::numeric_limits<DWORD>::max();
+ result.dwLowDateTime = std::numeric_limits<DWORD>::max();
+ return result;
+ }
+ FILETIME utc_ft;
+ MicrosecondsToFileTime(us_, &utc_ft);
+ return utc_ft;
+}
+
+void Time::ReadMinTimerIntervalLowResMs() {
+ AutoLock lock(*GetHighResLock());
+ // Read the setting for what interval to use on battery power.
+ g_battery_power_interval_ms =
+ base::FeatureList::IsEnabled(base::kSlowDCTimerInterruptsWin) ? 8 : 4;
+ UpdateTimerIntervalLocked();
+}
+
+// static
+// Enable raising of the system-global timer interrupt frequency to 1 kHz (when
+// enable is true, which happens when on AC power) or some lower frequency when
+// on battery power (when enable is false). If the g_high_res_timer_enabled
+// setting hasn't actually changed or if if there are no outstanding requests
+// (if g_high_res_timer_count is zero) then do nothing.
+// TL;DR - call this when going from AC to DC power or vice-versa.
+void Time::EnableHighResolutionTimer(bool enable) {
+ AutoLock lock(*GetHighResLock());
+ g_high_res_timer_enabled = enable;
+ UpdateTimerIntervalLocked();
+}
+
+// static
+// Request that the system-global Windows timer interrupt frequency be raised.
+// How high the frequency is raised depends on the system's power state and
+// possibly other options.
+// TL;DR - call this at the beginning and end of a time period where you want
+// higher frequency timer interrupts. Each call with activating=true must be
+// paired with a subsequent activating=false call.
+bool Time::ActivateHighResolutionTimer(bool activating) {
+ // We only do work on the transition from zero to one or one to zero so we
+ // can easily undo the effect (if necessary) when EnableHighResolutionTimer is
+ // called.
+ const uint32_t max = std::numeric_limits<uint32_t>::max();
+
+ AutoLock lock(*GetHighResLock());
+ if (activating) {
+ DCHECK_NE(g_high_res_timer_count, max);
+ ++g_high_res_timer_count;
+ } else {
+ DCHECK_NE(g_high_res_timer_count, 0u);
+ --g_high_res_timer_count;
+ }
+ UpdateTimerIntervalLocked();
+ return true;
+}
+
+// static
+// See if the timer interrupt interval has been set to the lowest value.
+bool Time::IsHighResolutionTimerInUse() {
+ AutoLock lock(*GetHighResLock());
+ return g_last_interval_requested_ms == MinTimerIntervalHighResMs();
+}
+
+// static
+void Time::ResetHighResolutionTimerUsage() {
+ AutoLock lock(*GetHighResLock());
+ g_high_res_timer_usage = TimeDelta();
+ g_high_res_timer_usage_start = subtle::TimeTicksNowIgnoringOverride();
+ if (g_high_res_timer_count > 0)
+ g_high_res_timer_last_activation = g_high_res_timer_usage_start;
+}
+
+// static
+double Time::GetHighResolutionTimerUsage() {
+ AutoLock lock(*GetHighResLock());
+ TimeTicks now = subtle::TimeTicksNowIgnoringOverride();
+ TimeDelta elapsed_time = now - g_high_res_timer_usage_start;
+ if (elapsed_time.is_zero()) {
+ // This is unexpected but possible if TimeTicks resolution is low and
+ // GetHighResolutionTimerUsage() is called promptly after
+ // ResetHighResolutionTimerUsage().
+ return 0.0;
+ }
+ TimeDelta used_time = g_high_res_timer_usage;
+ if (g_high_res_timer_count > 0) {
+ // If currently activated add the remainder of time since the last
+ // activation.
+ used_time += now - g_high_res_timer_last_activation;
+ }
+ return used_time.InMillisecondsF() / elapsed_time.InMillisecondsF() * 100;
+}
+
+// static
+bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
+ // Create the system struct representing our exploded time. It will either be
+ // in local time or UTC.If casting from int to WORD results in overflow,
+ // fail and return Time(0).
+ SYSTEMTIME st;
+ if (!SafeConvertToWord(exploded.year, &st.wYear) ||
+ !SafeConvertToWord(exploded.month, &st.wMonth) ||
+ !SafeConvertToWord(exploded.day_of_week, &st.wDayOfWeek) ||
+ !SafeConvertToWord(exploded.day_of_month, &st.wDay) ||
+ !SafeConvertToWord(exploded.hour, &st.wHour) ||
+ !SafeConvertToWord(exploded.minute, &st.wMinute) ||
+ !SafeConvertToWord(exploded.second, &st.wSecond) ||
+ !SafeConvertToWord(exploded.millisecond, &st.wMilliseconds)) {
+ *time = Time(0);
+ return false;
+ }
+
+ FILETIME ft;
+ bool success = true;
+ // Ensure that it's in UTC.
+ if (is_local) {
+ SYSTEMTIME utc_st;
+ success = TzSpecificLocalTimeToSystemTime(nullptr, &st, &utc_st) &&
+ SystemTimeToFileTime(&utc_st, &ft);
+ } else {
+ success = !!SystemTimeToFileTime(&st, &ft);
+ }
+
+ if (!success) {
+ *time = Time(0);
+ return false;
+ }
+
+ *time = Time(FileTimeToMicroseconds(ft));
+ return true;
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+ if (us_ < 0LL) {
+ // We are not able to convert it to FILETIME.
+ ZeroMemory(exploded, sizeof(*exploded));
+ return;
+ }
+
+ // FILETIME in UTC.
+ FILETIME utc_ft;
+ MicrosecondsToFileTime(us_, &utc_ft);
+
+ // FILETIME in local time if necessary.
+ bool success = true;
+ // FILETIME in SYSTEMTIME (exploded).
+ SYSTEMTIME st = {0};
+ if (is_local) {
+ SYSTEMTIME utc_st;
+ // We don't use FileTimeToLocalFileTime here, since it uses the current
+ // settings for the time zone and daylight saving time. Therefore, if it is
+ // daylight saving time, it will take daylight saving time into account,
+ // even if the time you are converting is in standard time.
+ success = FileTimeToSystemTime(&utc_ft, &utc_st) &&
+ SystemTimeToTzSpecificLocalTime(nullptr, &utc_st, &st);
+ } else {
+ success = !!FileTimeToSystemTime(&utc_ft, &st);
+ }
+
+ if (!success) {
+ NOTREACHED() << "Unable to convert time, don't know why";
+ ZeroMemory(exploded, sizeof(*exploded));
+ return;
+ }
+
+ exploded->year = st.wYear;
+ exploded->month = st.wMonth;
+ exploded->day_of_week = st.wDayOfWeek;
+ exploded->day_of_month = st.wDay;
+ exploded->hour = st.wHour;
+ exploded->minute = st.wMinute;
+ exploded->second = st.wSecond;
+ exploded->millisecond = st.wMilliseconds;
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+namespace {
+
+// We define a wrapper to adapt between the __stdcall and __cdecl call of the
+// mock function, and to avoid a static constructor. Assigning an import to a
+// function pointer directly would require setup code to fetch from the IAT.
+DWORD timeGetTimeWrapper() {
+ return timeGetTime();
+}
+
+DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
+
+// A structure holding the most significant bits of "last seen" and a
+// "rollover" counter.
+union LastTimeAndRolloversState {
+ // The state as a single 32-bit opaque value.
+ subtle::Atomic32 as_opaque_32;
+
+ // The state as usable values.
+ struct {
+ // The top 8-bits of the "last" time. This is enough to check for rollovers
+ // and the small bit-size means fewer CompareAndSwap operations to store
+ // changes in state, which in turn makes for fewer retries.
+ uint8_t last_8;
+ // A count of the number of detected rollovers. Using this as bits 47-32
+ // of the upper half of a 64-bit value results in a 48-bit tick counter.
+ // This extends the total rollover period from about 49 days to about 8800
+ // years while still allowing it to be stored with last_8 in a single
+ // 32-bit value.
+ uint16_t rollovers;
+ } as_values;
+};
+subtle::Atomic32 g_last_time_and_rollovers = 0;
+static_assert(
+ sizeof(LastTimeAndRolloversState) <= sizeof(g_last_time_and_rollovers),
+ "LastTimeAndRolloversState does not fit in a single atomic word");
+
+// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
+// because it returns the number of milliseconds since Windows has started,
+// which will roll over the 32-bit value every ~49 days. We try to track
+// rollover ourselves, which works if TimeTicks::Now() is called at least every
+// 48.8 days (not 49 days because only changes in the top 8 bits get noticed).
+TimeTicks RolloverProtectedNow() {
+ LastTimeAndRolloversState state;
+ DWORD now; // DWORD is always unsigned 32 bits.
+
+ while (true) {
+ // Fetch the "now" and "last" tick values, updating "last" with "now" and
+ // incrementing the "rollovers" counter if the tick-value has wrapped back
+ // around. Atomic operations ensure that both "last" and "rollovers" are
+ // always updated together.
+ int32_t original = subtle::Acquire_Load(&g_last_time_and_rollovers);
+ state.as_opaque_32 = original;
+ now = g_tick_function();
+ uint8_t now_8 = static_cast<uint8_t>(now >> 24);
+ if (now_8 < state.as_values.last_8)
+ ++state.as_values.rollovers;
+ state.as_values.last_8 = now_8;
+
+ // If the state hasn't changed, exit the loop.
+ if (state.as_opaque_32 == original)
+ break;
+
+ // Save the changed state. If the existing value is unchanged from the
+ // original, exit the loop.
+ int32_t check = subtle::Release_CompareAndSwap(
+ &g_last_time_and_rollovers, original, state.as_opaque_32);
+ if (check == original)
+ break;
+
+ // Another thread has done something in between so retry from the top.
+ }
+
+ return TimeTicks() +
+ TimeDelta::FromMilliseconds(
+ now + (static_cast<uint64_t>(state.as_values.rollovers) << 32));
+}
+
+// Discussion of tick counter options on Windows:
+//
+// (1) CPU cycle counter. (Retrieved via RDTSC)
+// The CPU counter provides the highest resolution time stamp and is the least
+// expensive to retrieve. However, on older CPUs, two issues can affect its
+// reliability: First it is maintained per processor and not synchronized
+// between processors. Also, the counters will change frequency due to thermal
+// and power changes, and stop in some states.
+//
+// (2) QueryPerformanceCounter (QPC). The QPC counter provides a high-
+// resolution (<1 microsecond) time stamp. On most hardware running today, it
+// auto-detects and uses the constant-rate RDTSC counter to provide extremely
+// efficient and reliable time stamps.
+//
+// On older CPUs where RDTSC is unreliable, it falls back to using more
+// expensive (20X to 40X more costly) alternate clocks, such as HPET or the ACPI
+// PM timer, and can involve system calls; and all this is up to the HAL (with
+// some help from ACPI). According to
+// http://blogs.msdn.com/oldnewthing/archive/2005/09/02/459952.aspx, in the
+// worst case, it gets the counter from the rollover interrupt on the
+// programmable interrupt timer. In best cases, the HAL may conclude that the
+// RDTSC counter runs at a constant frequency, then it uses that instead. On
+// multiprocessor machines, it will try to verify the values returned from
+// RDTSC on each processor are consistent with each other, and apply a handful
+// of workarounds for known buggy hardware. In other words, QPC is supposed to
+// give consistent results on a multiprocessor computer, but for older CPUs it
+// can be unreliable due bugs in BIOS or HAL.
+//
+// (3) System time. The system time provides a low-resolution (from ~1 to ~15.6
+// milliseconds) time stamp but is comparatively less expensive to retrieve and
+// more reliable. Time::EnableHighResolutionTimer() and
+// Time::ActivateHighResolutionTimer() can be called to alter the resolution of
+// this timer; and also other Windows applications can alter it, affecting this
+// one.
+
+TimeTicks InitialNowFunction();
+
+// See "threading notes" in InitializeNowFunctionPointer() for details on how
+// concurrent reads/writes to these globals has been made safe.
+TimeTicksNowFunction g_time_ticks_now_ignoring_override_function =
+ &InitialNowFunction;
+int64_t g_qpc_ticks_per_second = 0;
+
+// As of January 2015, use of <atomic> is forbidden in Chromium code. This is
+// what std::atomic_thread_fence does on Windows on all Intel architectures when
+// the memory_order argument is anything but std::memory_order_seq_cst:
+#define ATOMIC_THREAD_FENCE(memory_order) _ReadWriteBarrier();
+
+TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
+ // Ensure that the assignment to |g_qpc_ticks_per_second|, made in
+ // InitializeNowFunctionPointer(), has happened by this point.
+ ATOMIC_THREAD_FENCE(memory_order_acquire);
+
+ DCHECK_GT(g_qpc_ticks_per_second, 0);
+
+ // If the QPC Value is below the overflow threshold, we proceed with
+ // simple multiply and divide.
+ if (qpc_value < Time::kQPCOverflowThreshold) {
+ return TimeDelta::FromMicroseconds(
+ qpc_value * Time::kMicrosecondsPerSecond / g_qpc_ticks_per_second);
+ }
+ // Otherwise, calculate microseconds in a round about manner to avoid
+ // overflow and precision issues.
+ int64_t whole_seconds = qpc_value / g_qpc_ticks_per_second;
+ int64_t leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second);
+ return TimeDelta::FromMicroseconds(
+ (whole_seconds * Time::kMicrosecondsPerSecond) +
+ ((leftover_ticks * Time::kMicrosecondsPerSecond) /
+ g_qpc_ticks_per_second));
+}
+
+TimeTicks QPCNow() {
+ return TimeTicks() + QPCValueToTimeDelta(QPCNowRaw());
+}
+
+void InitializeNowFunctionPointer() {
+ LARGE_INTEGER ticks_per_sec = {};
+ if (!QueryPerformanceFrequency(&ticks_per_sec))
+ ticks_per_sec.QuadPart = 0;
+
+ // If Windows cannot provide a QPC implementation, TimeTicks::Now() must use
+ // the low-resolution clock.
+ //
+ // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now()
+ // will still use the low-resolution clock. A CPU lacking a non-stop time
+ // counter will cause Windows to provide an alternate QPC implementation that
+ // works, but is expensive to use.
+ //
+ // Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015,
+ // ~72% of users fall within this category.
+ TimeTicksNowFunction now_function;
+ CPU cpu;
+ if (ticks_per_sec.QuadPart <= 0 || !cpu.has_non_stop_time_stamp_counter()) {
+ now_function = &RolloverProtectedNow;
+ } else {
+ now_function = &QPCNow;
+ }
+
+ // Threading note 1: In an unlikely race condition, it's possible for two or
+ // more threads to enter InitializeNowFunctionPointer() in parallel. This is
+ // not a problem since all threads should end up writing out the same values
+ // to the global variables.
+ //
+ // Threading note 2: A release fence is placed here to ensure, from the
+ // perspective of other threads using the function pointers, that the
+ // assignment to |g_qpc_ticks_per_second| happens before the function pointers
+ // are changed.
+ g_qpc_ticks_per_second = ticks_per_sec.QuadPart;
+ ATOMIC_THREAD_FENCE(memory_order_release);
+ // Also set g_time_ticks_now_function to avoid the additional indirection via
+ // TimeTicksNowIgnoringOverride() for future calls to TimeTicks::Now(). But
+ // g_time_ticks_now_function may have already be overridden.
+ if (internal::g_time_ticks_now_function ==
+ &subtle::TimeTicksNowIgnoringOverride) {
+ internal::g_time_ticks_now_function = now_function;
+ }
+ g_time_ticks_now_ignoring_override_function = now_function;
+}
+
+TimeTicks InitialNowFunction() {
+ InitializeNowFunctionPointer();
+ return g_time_ticks_now_ignoring_override_function();
+}
+
+} // namespace
+
+// static
+TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
+ TickFunctionType ticker) {
+ TickFunctionType old = g_tick_function;
+ g_tick_function = ticker;
+ subtle::NoBarrier_Store(&g_last_time_and_rollovers, 0);
+ return old;
+}
+
+namespace subtle {
+TimeTicks TimeTicksNowIgnoringOverride() {
+ return g_time_ticks_now_ignoring_override_function();
+}
+} // namespace subtle
+
+// static
+bool TimeTicks::IsHighResolution() {
+ if (g_time_ticks_now_ignoring_override_function == &InitialNowFunction)
+ InitializeNowFunctionPointer();
+ return g_time_ticks_now_ignoring_override_function == &QPCNow;
+}
+
+// static
+bool TimeTicks::IsConsistentAcrossProcesses() {
+ // According to Windows documentation [1] QPC is consistent post-Windows
+ // Vista. So if we are using QPC then we are consistent which is the same as
+ // being high resolution.
+ //
+ // [1] https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
+ //
+ // "In general, the performance counter results are consistent across all
+ // processors in multi-core and multi-processor systems, even when measured on
+ // different threads or processes. Here are some exceptions to this rule:
+ // - Pre-Windows Vista operating systems that run on certain processors might
+ // violate this consistency because of one of these reasons:
+ // 1. The hardware processors have a non-invariant TSC and the BIOS
+ // doesn't indicate this condition correctly.
+ // 2. The TSC synchronization algorithm that was used wasn't suitable for
+ // systems with large numbers of processors."
+ return IsHighResolution();
+}
+
+// static
+TimeTicks::Clock TimeTicks::GetClock() {
+ return IsHighResolution() ?
+ Clock::WIN_QPC : Clock::WIN_ROLLOVER_PROTECTED_TIME_GET_TIME;
+}
+
+// ThreadTicks ----------------------------------------------------------------
+
+namespace subtle {
+ThreadTicks ThreadTicksNowIgnoringOverride() {
+ return ThreadTicks::GetForThread(PlatformThread::CurrentHandle());
+}
+} // namespace subtle
+
+// static
+ThreadTicks ThreadTicks::GetForThread(
+ const PlatformThreadHandle& thread_handle) {
+ DCHECK(IsSupported());
+
+#if defined(ARCH_CPU_ARM64)
+ // QueryThreadCycleTime versus TSCTicksPerSecond doesn't have much relation to
+ // actual elapsed time on Windows on Arm, because QueryThreadCycleTime is
+ // backed by the actual number of CPU cycles executed, rather than a
+ // constant-rate timer like Intel. To work around this, use GetThreadTimes
+ // (which isn't as accurate but is meaningful as a measure of elapsed
+ // per-thread time).
+ FILETIME creation_time, exit_time, kernel_time, user_time;
+ ::GetThreadTimes(thread_handle.platform_handle(), &creation_time, &exit_time,
+ &kernel_time, &user_time);
+
+ int64_t us = FileTimeToMicroseconds(user_time);
+ return ThreadTicks(us);
+#else
+ // Get the number of TSC ticks used by the current thread.
+ ULONG64 thread_cycle_time = 0;
+ ::QueryThreadCycleTime(thread_handle.platform_handle(), &thread_cycle_time);
+
+ // Get the frequency of the TSC.
+ double tsc_ticks_per_second = TSCTicksPerSecond();
+ if (tsc_ticks_per_second == 0)
+ return ThreadTicks();
+
+ // Return the CPU time of the current thread.
+ double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
+ return ThreadTicks(
+ static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
+#endif
+}
+
+// static
+bool ThreadTicks::IsSupportedWin() {
+ static bool is_supported = CPU().has_non_stop_time_stamp_counter();
+ return is_supported;
+}
+
+// static
+void ThreadTicks::WaitUntilInitializedWin() {
+#if !defined(ARCH_CPU_ARM64)
+ while (TSCTicksPerSecond() == 0)
+ ::Sleep(10);
+#endif
+}
+
+#if !defined(ARCH_CPU_ARM64)
+double ThreadTicks::TSCTicksPerSecond() {
+ DCHECK(IsSupported());
+ // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
+ // frequency, because there is no guarantee that the TSC frequency is equal to
+ // the performance counter frequency.
+ // The TSC frequency is cached in a static variable because it takes some time
+ // to compute it.
+ static double tsc_ticks_per_second = 0;
+ if (tsc_ticks_per_second != 0)
+ return tsc_ticks_per_second;
+
+ // Increase the thread priority to reduces the chances of having a context
+ // switch during a reading of the TSC and the performance counter.
+ int previous_priority = ::GetThreadPriority(::GetCurrentThread());
+ ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+
+ // The first time that this function is called, make an initial reading of the
+ // TSC and the performance counter.
+
+ static const uint64_t tsc_initial = __rdtsc();
+ static const uint64_t perf_counter_initial = QPCNowRaw();
+
+ // Make a another reading of the TSC and the performance counter every time
+ // that this function is called.
+ uint64_t tsc_now = __rdtsc();
+ uint64_t perf_counter_now = QPCNowRaw();
+
+ // Reset the thread priority.
+ ::SetThreadPriority(::GetCurrentThread(), previous_priority);
+
+ // Make sure that at least 50 ms elapsed between the 2 readings. The first
+ // time that this function is called, we don't expect this to be the case.
+ // Note: The longer the elapsed time between the 2 readings is, the more
+ // accurate the computed TSC frequency will be. The 50 ms value was
+ // chosen because local benchmarks show that it allows us to get a
+ // stddev of less than 1 tick/us between multiple runs.
+ // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
+ // this will never fail on systems that run XP or later.
+ // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
+ LARGE_INTEGER perf_counter_frequency = {};
+ ::QueryPerformanceFrequency(&perf_counter_frequency);
+ DCHECK_GE(perf_counter_now, perf_counter_initial);
+ uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
+ double elapsed_time_seconds =
+ perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
+
+ static constexpr double kMinimumEvaluationPeriodSeconds = 0.05;
+ if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
+ return 0;
+
+ // Compute the frequency of the TSC.
+ DCHECK_GE(tsc_now, tsc_initial);
+ uint64_t tsc_ticks = tsc_now - tsc_initial;
+ tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
+
+ return tsc_ticks_per_second;
+}
+#endif // defined(ARCH_CPU_ARM64)
+
+// static
+TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
+ return TimeTicks() + QPCValueToTimeDelta(qpc_value);
+}
+
+// TimeDelta ------------------------------------------------------------------
+
+// static
+TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
+ return QPCValueToTimeDelta(qpc_value);
+}
+
+// static
+TimeDelta TimeDelta::FromFileTime(FILETIME ft) {
+ return TimeDelta::FromMicroseconds(FileTimeToMicroseconds(ft));
+}
+
+// static
+TimeDelta TimeDelta::FromWinrtDateTime(ABI::Windows::Foundation::DateTime dt) {
+ // UniversalTime is 100 ns intervals since January 1, 1601 (UTC)
+ return TimeDelta::FromMicroseconds(dt.UniversalTime / 10);
+}
+
+ABI::Windows::Foundation::DateTime TimeDelta::ToWinrtDateTime() const {
+ ABI::Windows::Foundation::DateTime date_time;
+ date_time.UniversalTime = InMicroseconds() * 10;
+ return date_time;
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/time/time_win_features.cc b/security/sandbox/chromium/base/time/time_win_features.cc
new file mode 100644
index 0000000000..edf3024e70
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time_win_features.cc
@@ -0,0 +1,14 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time/time_win_features.h"
+
+#include "base/feature_list.h"
+
+namespace base {
+
+const Feature kSlowDCTimerInterruptsWin{"SlowDCTimerInterruptsWin",
+ FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/time/time_win_features.h b/security/sandbox/chromium/base/time/time_win_features.h
new file mode 100644
index 0000000000..b586ec2419
--- /dev/null
+++ b/security/sandbox/chromium/base/time/time_win_features.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIME_TIME_WIN_FEATURES_H_
+#define BASE_TIME_TIME_WIN_FEATURES_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+struct Feature;
+
+// Slow the maximum interrupt timer on battery power to 8 ms, instead of the
+// default 4 ms.
+extern const BASE_EXPORT Feature kSlowDCTimerInterruptsWin;
+
+} // namespace base
+
+#endif // BASE_TIME_TIME_WIN_FEATURES_H_
diff --git a/security/sandbox/chromium/base/token.cc b/security/sandbox/chromium/base/token.cc
new file mode 100644
index 0000000000..e7ad896713
--- /dev/null
+++ b/security/sandbox/chromium/base/token.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/token.h"
+
+#include <inttypes.h>
+
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+// static
+Token Token::CreateRandom() {
+ Token token;
+
+ // Use base::RandBytes instead of crypto::RandBytes, because crypto calls the
+ // base version directly, and to prevent the dependency from base/ to crypto/.
+ base::RandBytes(&token, sizeof(token));
+ return token;
+}
+
+std::string Token::ToString() const {
+ return base::StringPrintf("%016" PRIX64 "%016" PRIX64, high_, low_);
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/token.h b/security/sandbox/chromium/base/token.h
new file mode 100644
index 0000000000..e2843a6d14
--- /dev/null
+++ b/security/sandbox/chromium/base/token.h
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TOKEN_H_
+#define BASE_TOKEN_H_
+
+#include <stdint.h>
+
+#include <iosfwd>
+#include <tuple>
+
+#include "base/base_export.h"
+#include "base/hash/hash.h"
+
+namespace base {
+
+// A Token is a randomly chosen 128-bit integer. This class supports generation
+// from a cryptographically strong random source, or constexpr construction over
+// fixed values (e.g. to store a pre-generated constant value). Tokens are
+// similar in spirit and purpose to UUIDs, without many of the constraints and
+// expectations (such as byte layout and string representation) clasically
+// associated with UUIDs.
+class BASE_EXPORT Token {
+ public:
+ // Constructs a zero Token.
+ constexpr Token() : high_(0), low_(0) {}
+
+ // Constructs a Token with |high| and |low| as its contents.
+ constexpr Token(uint64_t high, uint64_t low) : high_(high), low_(low) {}
+
+ // Constructs a new Token with random |high| and |low| values taken from a
+ // cryptographically strong random source.
+ static Token CreateRandom();
+
+ // The high and low 64 bits of this Token.
+ uint64_t high() const { return high_; }
+ uint64_t low() const { return low_; }
+
+ bool is_zero() const { return high_ == 0 && low_ == 0; }
+
+ bool operator==(const Token& other) const {
+ return high_ == other.high_ && low_ == other.low_;
+ }
+
+ bool operator!=(const Token& other) const { return !(*this == other); }
+
+ bool operator<(const Token& other) const {
+ return std::tie(high_, low_) < std::tie(other.high_, other.low_);
+ }
+
+ // Generates a string representation of this Token useful for e.g. logging.
+ std::string ToString() const;
+
+ private:
+ // Note: Two uint64_t are used instead of uint8_t[16] in order to have a
+ // simpler implementation, paricularly for |ToString()|, |is_zero()|, and
+ // constexpr value construction.
+ uint64_t high_;
+ uint64_t low_;
+};
+
+// For use in std::unordered_map.
+struct TokenHash {
+ size_t operator()(const base::Token& token) const {
+ return base::HashInts64(token.high(), token.low());
+ }
+};
+
+} // namespace base
+
+#endif // BASE_TOKEN_H_
diff --git a/security/sandbox/chromium/base/tuple.h b/security/sandbox/chromium/base/tuple.h
new file mode 100644
index 0000000000..58681d515a
--- /dev/null
+++ b/security/sandbox/chromium/base/tuple.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Use std::tuple as tuple type. This file contains helper functions for
+// working with std::tuples.
+// The functions DispatchToMethod and DispatchToFunction take a function pointer
+// or instance and method pointer, and unpack a tuple into arguments to the
+// call.
+//
+// Example usage:
+// // These two methods of creating a Tuple are identical.
+// std::tuple<int, const char*> tuple_a(1, "wee");
+// std::tuple<int, const char*> tuple_b = std::make_tuple(1, "wee");
+//
+// void SomeFunc(int a, const char* b) { }
+// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee")
+// DispatchToFunction(
+// &SomeFunc, std::make_tuple(10, "foo")); // SomeFunc(10, "foo")
+//
+// struct { void SomeMeth(int a, int b, int c) { } } foo;
+// DispatchToMethod(&foo, &Foo::SomeMeth, std::make_tuple(1, 2, 3));
+// // foo->SomeMeth(1, 2, 3);
+
+#ifndef BASE_TUPLE_H_
+#define BASE_TUPLE_H_
+
+#include <stddef.h>
+#include <tuple>
+#include <utility>
+
+#include "build/build_config.h"
+
+namespace base {
+
+// Dispatchers ----------------------------------------------------------------
+//
+// Helper functions that call the given method on an object, with the unpacked
+// tuple arguments. Notice that they all have the same number of arguments,
+// so you need only write:
+// DispatchToMethod(object, &Object::method, args);
+// This is very useful for templated dispatchers, since they don't need to know
+// what type |args| is.
+
+// Non-Static Dispatchers with no out params.
+
+template <typename ObjT, typename Method, typename Tuple, size_t... Ns>
+inline void DispatchToMethodImpl(const ObjT& obj,
+ Method method,
+ Tuple&& args,
+ std::index_sequence<Ns...>) {
+ (obj->*method)(std::get<Ns>(std::forward<Tuple>(args))...);
+}
+
+template <typename ObjT, typename Method, typename Tuple>
+inline void DispatchToMethod(const ObjT& obj,
+ Method method,
+ Tuple&& args) {
+ constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
+ DispatchToMethodImpl(obj, method, std::forward<Tuple>(args),
+ std::make_index_sequence<size>());
+}
+
+// Static Dispatchers with no out params.
+
+template <typename Function, typename Tuple, size_t... Ns>
+inline void DispatchToFunctionImpl(Function function,
+ Tuple&& args,
+ std::index_sequence<Ns...>) {
+ (*function)(std::get<Ns>(std::forward<Tuple>(args))...);
+}
+
+template <typename Function, typename Tuple>
+inline void DispatchToFunction(Function function, Tuple&& args) {
+ constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
+ DispatchToFunctionImpl(function, std::forward<Tuple>(args),
+ std::make_index_sequence<size>());
+}
+
+// Dispatchers with out parameters.
+
+template <typename ObjT,
+ typename Method,
+ typename InTuple,
+ typename OutTuple,
+ size_t... InNs,
+ size_t... OutNs>
+inline void DispatchToMethodImpl(const ObjT& obj,
+ Method method,
+ InTuple&& in,
+ OutTuple* out,
+ std::index_sequence<InNs...>,
+ std::index_sequence<OutNs...>) {
+ (obj->*method)(std::get<InNs>(std::forward<InTuple>(in))...,
+ &std::get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename InTuple, typename OutTuple>
+inline void DispatchToMethod(const ObjT& obj,
+ Method method,
+ InTuple&& in,
+ OutTuple* out) {
+ constexpr size_t in_size = std::tuple_size<std::decay_t<InTuple>>::value;
+ constexpr size_t out_size = std::tuple_size<OutTuple>::value;
+ DispatchToMethodImpl(obj, method, std::forward<InTuple>(in), out,
+ std::make_index_sequence<in_size>(),
+ std::make_index_sequence<out_size>());
+}
+
+} // namespace base
+
+#endif // BASE_TUPLE_H_
diff --git a/security/sandbox/chromium/base/unguessable_token.cc b/security/sandbox/chromium/base/unguessable_token.cc
new file mode 100644
index 0000000000..973b4167bd
--- /dev/null
+++ b/security/sandbox/chromium/base/unguessable_token.cc
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/unguessable_token.h"
+
+#include "base/format_macros.h"
+#include "base/no_destructor.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+UnguessableToken::UnguessableToken(const base::Token& token) : token_(token) {}
+
+// static
+UnguessableToken UnguessableToken::Create() {
+ return UnguessableToken(Token::CreateRandom());
+}
+
+// static
+const UnguessableToken& UnguessableToken::Null() {
+ static const NoDestructor<UnguessableToken> null_token;
+ return *null_token;
+}
+
+// static
+UnguessableToken UnguessableToken::Deserialize(uint64_t high, uint64_t low) {
+ // Receiving a zeroed out UnguessableToken from another process means that it
+ // was never initialized via Create(). Treat this case as a security issue.
+ DCHECK(!(high == 0 && low == 0));
+ return UnguessableToken(Token{high, low});
+}
+
+std::ostream& operator<<(std::ostream& out, const UnguessableToken& token) {
+ return out << "(" << token.ToString() << ")";
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/unguessable_token.h b/security/sandbox/chromium/base/unguessable_token.h
new file mode 100644
index 0000000000..895dbc46c4
--- /dev/null
+++ b/security/sandbox/chromium/base/unguessable_token.h
@@ -0,0 +1,120 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_UNGUESSABLE_TOKEN_H_
+#define BASE_UNGUESSABLE_TOKEN_H_
+
+#include <stdint.h>
+#include <string.h>
+#include <iosfwd>
+#include <tuple>
+
+#include "base/base_export.h"
+#include "base/hash/hash.h"
+#include "base/logging.h"
+#include "base/token.h"
+
+namespace base {
+
+struct UnguessableTokenHash;
+
+// UnguessableToken is, like Token, a randomly chosen 128-bit value. Unlike
+// Token, a new UnguessableToken is always generated at runtime from a
+// cryptographically strong random source (or copied or serialized and
+// deserialized from another such UnguessableToken). It can be used as part of a
+// larger aggregate type, or as an ID in and of itself.
+//
+// An UnguessableToken is a strong *bearer token*. Bearer tokens are like HTTP
+// cookies: if a caller has the token, the callee thereby considers the caller
+// authorized to request the operation the callee performs.
+//
+// UnguessableToken can be used when the resource associated with the ID needs
+// to be protected against manipulation by other untrusted agents in the system,
+// and there is no other convenient way to verify the authority of the agent to
+// do so (because the resource is part of a table shared across processes, for
+// instance). In such a scheme, knowledge of the token value in and of itself is
+// sufficient proof of authority to carry out an operation on the associated
+// resource.
+//
+// Use Create() for creating new UnguessableTokens.
+//
+// NOTE: It is illegal to send empty UnguessableTokens across processes, and
+// sending/receiving empty tokens should be treated as a security issue. If
+// there is a valid scenario for sending "no token" across processes, use
+// base::Optional instead of an empty token.
+
+class BASE_EXPORT UnguessableToken {
+ public:
+ // Create a unique UnguessableToken.
+ static UnguessableToken Create();
+
+ // Returns a reference to a global null UnguessableToken. This should only be
+ // used for functions that need to return a reference to an UnguessableToken,
+ // and should not be used as a general-purpose substitute for invoking the
+ // default constructor.
+ static const UnguessableToken& Null();
+
+ // Return a UnguessableToken built from the high/low bytes provided.
+ // It should only be used in deserialization scenarios.
+ //
+ // NOTE: If the deserialized token is empty, it means that it was never
+ // initialized via Create(). This is a security issue, and should be handled.
+ static UnguessableToken Deserialize(uint64_t high, uint64_t low);
+
+ // Creates an empty UnguessableToken.
+ // Assign to it with Create() before using it.
+ constexpr UnguessableToken() = default;
+
+ // NOTE: Serializing an empty UnguessableToken is an illegal operation.
+ uint64_t GetHighForSerialization() const {
+ DCHECK(!is_empty());
+ return token_.high();
+ }
+
+ // NOTE: Serializing an empty UnguessableToken is an illegal operation.
+ uint64_t GetLowForSerialization() const {
+ DCHECK(!is_empty());
+ return token_.low();
+ }
+
+ bool is_empty() const { return token_.is_zero(); }
+
+ // Hex representation of the unguessable token.
+ std::string ToString() const { return token_.ToString(); }
+
+ explicit operator bool() const { return !is_empty(); }
+
+ bool operator<(const UnguessableToken& other) const {
+ return token_ < other.token_;
+ }
+
+ bool operator==(const UnguessableToken& other) const {
+ return token_ == other.token_;
+ }
+
+ bool operator!=(const UnguessableToken& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ friend struct UnguessableTokenHash;
+ explicit UnguessableToken(const Token& token);
+
+ base::Token token_;
+};
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& out,
+ const UnguessableToken& token);
+
+// For use in std::unordered_map.
+struct UnguessableTokenHash {
+ size_t operator()(const base::UnguessableToken& token) const {
+ DCHECK(token);
+ return TokenHash()(token.token_);
+ }
+};
+
+} // namespace base
+
+#endif // BASE_UNGUESSABLE_TOKEN_H_
diff --git a/security/sandbox/chromium/base/version.cc b/security/sandbox/chromium/base/version.cc
new file mode 100644
index 0000000000..2ee8793c03
--- /dev/null
+++ b/security/sandbox/chromium/base/version.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/version.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+namespace {
+
+// Parses the |numbers| vector representing the different numbers
+// inside the version string and constructs a vector of valid integers. It stops
+// when it reaches an invalid item (including the wildcard character). |parsed|
+// is the resulting integer vector. Function returns true if all numbers were
+// parsed successfully, false otherwise.
+bool ParseVersionNumbers(StringPiece version_str,
+ std::vector<uint32_t>* parsed) {
+ std::vector<StringPiece> numbers =
+ SplitStringPiece(version_str, ".", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+ if (numbers.empty())
+ return false;
+
+ for (auto it = numbers.begin(); it != numbers.end(); ++it) {
+ if (StartsWith(*it, "+", CompareCase::SENSITIVE))
+ return false;
+
+ unsigned int num;
+ if (!StringToUint(*it, &num))
+ return false;
+
+ // This throws out leading zeros for the first item only.
+ if (it == numbers.begin() && NumberToString(num) != *it)
+ return false;
+
+ // StringToUint returns unsigned int but Version fields are uint32_t.
+ static_assert(sizeof (uint32_t) == sizeof (unsigned int),
+ "uint32_t must be same as unsigned int");
+ parsed->push_back(num);
+ }
+ return true;
+}
+
+// Compares version components in |components1| with components in
+// |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to,
+// or greater than |components2|, respectively.
+int CompareVersionComponents(const std::vector<uint32_t>& components1,
+ const std::vector<uint32_t>& components2) {
+ const size_t count = std::min(components1.size(), components2.size());
+ for (size_t i = 0; i < count; ++i) {
+ if (components1[i] > components2[i])
+ return 1;
+ if (components1[i] < components2[i])
+ return -1;
+ }
+ if (components1.size() > components2.size()) {
+ for (size_t i = count; i < components1.size(); ++i) {
+ if (components1[i] > 0)
+ return 1;
+ }
+ } else if (components1.size() < components2.size()) {
+ for (size_t i = count; i < components2.size(); ++i) {
+ if (components2[i] > 0)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+} // namespace
+
+Version::Version() = default;
+
+Version::Version(const Version& other) = default;
+
+Version::~Version() = default;
+
+Version::Version(StringPiece version_str) {
+ std::vector<uint32_t> parsed;
+ if (!ParseVersionNumbers(version_str, &parsed))
+ return;
+
+ components_.swap(parsed);
+}
+
+Version::Version(std::vector<uint32_t> components)
+ : components_(std::move(components)) {}
+
+bool Version::IsValid() const {
+ return (!components_.empty());
+}
+
+// static
+bool Version::IsValidWildcardString(StringPiece wildcard_string) {
+ StringPiece version_string = wildcard_string;
+ if (EndsWith(version_string, ".*", CompareCase::SENSITIVE))
+ version_string = version_string.substr(0, version_string.size() - 2);
+
+ Version version(version_string);
+ return version.IsValid();
+}
+
+int Version::CompareToWildcardString(StringPiece wildcard_string) const {
+ DCHECK(IsValid());
+ DCHECK(Version::IsValidWildcardString(wildcard_string));
+
+ // Default behavior if the string doesn't end with a wildcard.
+ if (!EndsWith(wildcard_string, ".*", CompareCase::SENSITIVE)) {
+ Version version(wildcard_string);
+ DCHECK(version.IsValid());
+ return CompareTo(version);
+ }
+
+ std::vector<uint32_t> parsed;
+ const bool success = ParseVersionNumbers(
+ wildcard_string.substr(0, wildcard_string.length() - 2), &parsed);
+ DCHECK(success);
+ const int comparison = CompareVersionComponents(components_, parsed);
+ // If the version is smaller than the wildcard version's |parsed| vector,
+ // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the
+ // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to
+ // 1.2.2.* is 0 regardless of the wildcard). Under this logic,
+ // 1.2.0.0.0.0 compared to 1.2.* is 0.
+ if (comparison == -1 || comparison == 0)
+ return comparison;
+
+ // Catch the case where the digits of |parsed| are found in |components_|,
+ // which means that the two are equal since |parsed| has a trailing "*".
+ // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since
+ // components is greater (e.g. 3.2.3 vs 1.*).
+ DCHECK_GT(parsed.size(), 0UL);
+ const size_t min_num_comp = std::min(components_.size(), parsed.size());
+ for (size_t i = 0; i < min_num_comp; ++i) {
+ if (components_[i] != parsed[i])
+ return 1;
+ }
+ return 0;
+}
+
+int Version::CompareTo(const Version& other) const {
+ DCHECK(IsValid());
+ DCHECK(other.IsValid());
+ return CompareVersionComponents(components_, other.components_);
+}
+
+std::string Version::GetString() const {
+ DCHECK(IsValid());
+ std::string version_str;
+ size_t count = components_.size();
+ for (size_t i = 0; i < count - 1; ++i) {
+ version_str.append(NumberToString(components_[i]));
+ version_str.append(".");
+ }
+ version_str.append(NumberToString(components_[count - 1]));
+ return version_str;
+}
+
+bool operator==(const Version& v1, const Version& v2) {
+ return v1.CompareTo(v2) == 0;
+}
+
+bool operator!=(const Version& v1, const Version& v2) {
+ return !(v1 == v2);
+}
+
+bool operator<(const Version& v1, const Version& v2) {
+ return v1.CompareTo(v2) < 0;
+}
+
+bool operator<=(const Version& v1, const Version& v2) {
+ return v1.CompareTo(v2) <= 0;
+}
+
+bool operator>(const Version& v1, const Version& v2) {
+ return v1.CompareTo(v2) > 0;
+}
+
+bool operator>=(const Version& v1, const Version& v2) {
+ return v1.CompareTo(v2) >= 0;
+}
+
+std::ostream& operator<<(std::ostream& stream, const Version& v) {
+ return stream << v.GetString();
+}
+
+} // namespace base
diff --git a/security/sandbox/chromium/base/version.h b/security/sandbox/chromium/base/version.h
new file mode 100644
index 0000000000..9199449de6
--- /dev/null
+++ b/security/sandbox/chromium/base/version.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_VERSION_H_
+#define BASE_VERSION_H_
+
+#include <stdint.h>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Version represents a dotted version number, like "1.2.3.4", supporting
+// parsing and comparison.
+class BASE_EXPORT Version {
+ public:
+ // The only thing you can legally do to a default constructed
+ // Version object is assign to it.
+ Version();
+
+ Version(const Version& other);
+
+ // Initializes from a decimal dotted version number, like "0.1.1".
+ // Each component is limited to a uint16_t. Call IsValid() to learn
+ // the outcome.
+ explicit Version(StringPiece version_str);
+
+ // Initializes from a vector of components, like {1, 2, 3, 4}. Call IsValid()
+ // to learn the outcome.
+ explicit Version(std::vector<uint32_t> components);
+
+ ~Version();
+
+ // Returns true if the object contains a valid version number.
+ bool IsValid() const;
+
+ // Returns true if the version wildcard string is valid. The version wildcard
+ // string may end with ".*" (e.g. 1.2.*, 1.*). Any other arrangement with "*"
+ // is invalid (e.g. 1.*.3 or 1.2.3*). This functions defaults to standard
+ // Version behavior (IsValid) if no wildcard is present.
+ static bool IsValidWildcardString(StringPiece wildcard_string);
+
+ // Returns -1, 0, 1 for <, ==, >.
+ int CompareTo(const Version& other) const;
+
+ // Given a valid version object, compare if a |wildcard_string| results in a
+ // newer version. This function will default to CompareTo if the string does
+ // not end in wildcard sequence ".*". IsValidWildcard(wildcard_string) must be
+ // true before using this function.
+ int CompareToWildcardString(StringPiece wildcard_string) const;
+
+ // Return the string representation of this version.
+ std::string GetString() const;
+
+ const std::vector<uint32_t>& components() const { return components_; }
+
+ private:
+ std::vector<uint32_t> components_;
+};
+
+BASE_EXPORT bool operator==(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator!=(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator<(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator<=(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator>(const Version& v1, const Version& v2);
+BASE_EXPORT bool operator>=(const Version& v1, const Version& v2);
+BASE_EXPORT std::ostream& operator<<(std::ostream& stream, const Version& v);
+
+} // namespace base
+
+#endif // BASE_VERSION_H_
diff --git a/security/sandbox/chromium/base/win/current_module.h b/security/sandbox/chromium/base/win/current_module.h
new file mode 100644
index 0000000000..ee141db211
--- /dev/null
+++ b/security/sandbox/chromium/base/win/current_module.h
@@ -0,0 +1,17 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_CURRENT_MODULE_H_
+#define BASE_WIN_CURRENT_MODULE_H_
+
+#include <windows.h>
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+// Returns the HMODULE of the dll the macro was expanded in.
+// Only use in cc files, not in h files.
+#define CURRENT_MODULE() reinterpret_cast<HMODULE>(&__ImageBase)
+
+#endif // BASE_WIN_CURRENT_MODULE_H_
diff --git a/security/sandbox/chromium/base/win/pe_image.cc b/security/sandbox/chromium/base/win/pe_image.cc
new file mode 100644
index 0000000000..3d52964a24
--- /dev/null
+++ b/security/sandbox/chromium/base/win/pe_image.cc
@@ -0,0 +1,652 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file implements PEImage, a generic class to manipulate PE files.
+// This file was adapted from GreenBorder's Code.
+
+#include "base/win/pe_image.h"
+
+#include <stddef.h>
+#include <set>
+#include <string>
+
+#include "base/no_destructor.h"
+#include "base/win/current_module.h"
+
+namespace base {
+namespace win {
+
+// Structure to perform imports enumerations.
+struct EnumAllImportsStorage {
+ PEImage::EnumImportsFunction callback;
+ PVOID cookie;
+};
+
+namespace {
+
+// PdbInfo Signature
+const DWORD kPdbInfoSignature = 'SDSR';
+
+// Compare two strings byte by byte on an unsigned basis.
+// if s1 == s2, return 0
+// if s1 < s2, return negative
+// if s1 > s2, return positive
+// Exception if inputs are invalid.
+int StrCmpByByte(LPCSTR s1, LPCSTR s2) {
+ while (*s1 != '\0' && *s1 == *s2) {
+ ++s1;
+ ++s2;
+ }
+
+ return (*reinterpret_cast<const unsigned char*>(s1) -
+ *reinterpret_cast<const unsigned char*>(s2));
+}
+
+struct PdbInfo {
+ DWORD Signature;
+ GUID Guid;
+ DWORD Age;
+ char PdbFileName[1];
+};
+
+#define LDR_IS_DATAFILE(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)1)
+#define LDR_IS_IMAGEMAPPING(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)2)
+#define LDR_IS_RESOURCE(handle) \
+ (LDR_IS_IMAGEMAPPING(handle) || LDR_IS_DATAFILE(handle))
+
+} // namespace
+
+// Callback used to enumerate imports. See EnumImportChunksFunction.
+bool ProcessImportChunk(const PEImage& image,
+ LPCSTR module,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) {
+ EnumAllImportsStorage& storage =
+ *reinterpret_cast<EnumAllImportsStorage*>(cookie);
+
+ return image.EnumOneImportChunk(storage.callback, module, name_table, iat,
+ storage.cookie);
+}
+
+// Callback used to enumerate delay imports. See EnumDelayImportChunksFunction.
+bool ProcessDelayImportChunk(const PEImage& image,
+ PImgDelayDescr delay_descriptor,
+ LPCSTR module,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) {
+ EnumAllImportsStorage& storage =
+ *reinterpret_cast<EnumAllImportsStorage*>(cookie);
+
+ return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor,
+ module, name_table, iat, storage.cookie);
+}
+
+void PEImage::set_module(HMODULE module) {
+ module_ = module;
+}
+
+PIMAGE_DOS_HEADER PEImage::GetDosHeader() const {
+ return reinterpret_cast<PIMAGE_DOS_HEADER>(module_);
+}
+
+PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const {
+ PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+ return reinterpret_cast<PIMAGE_NT_HEADERS>(
+ reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew);
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const {
+ PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+ PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers);
+
+ if (section < nt_headers->FileHeader.NumberOfSections)
+ return first_section + section;
+ else
+ return nullptr;
+}
+
+WORD PEImage::GetNumSections() const {
+ return GetNTHeaders()->FileHeader.NumberOfSections;
+}
+
+DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const {
+ const IMAGE_DATA_DIRECTORY* const entry = GetDataDirectory(directory);
+ return entry ? entry->Size : 0;
+}
+
+PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const {
+ const IMAGE_DATA_DIRECTORY* const entry = GetDataDirectory(directory);
+ return entry ? RVAToAddr(entry->VirtualAddress) : nullptr;
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const {
+ PBYTE target = reinterpret_cast<PBYTE>(address);
+ PIMAGE_SECTION_HEADER section;
+
+ for (UINT i = 0; nullptr != (section = GetSectionHeader(i)); i++) {
+ // Don't use the virtual RVAToAddr.
+ PBYTE start =
+ reinterpret_cast<PBYTE>(PEImage::RVAToAddr(section->VirtualAddress));
+
+ DWORD size = section->Misc.VirtualSize;
+
+ if ((start <= target) && (start + size > target))
+ return section;
+ }
+
+ return nullptr;
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
+ LPCSTR section_name) const {
+ if (nullptr == section_name)
+ return nullptr;
+
+ PIMAGE_SECTION_HEADER ret = nullptr;
+ int num_sections = GetNumSections();
+
+ for (int i = 0; i < num_sections; i++) {
+ PIMAGE_SECTION_HEADER section = GetSectionHeader(i);
+ if (_strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name,
+ sizeof(section->Name)) == 0) {
+ ret = section;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+bool PEImage::GetDebugId(LPGUID guid,
+ LPDWORD age,
+ LPCSTR* pdb_filename,
+ size_t* pdb_filename_length) const {
+ DWORD debug_directory_size =
+ GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);
+ PIMAGE_DEBUG_DIRECTORY debug_directory =
+ reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(
+ GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
+ if (!debug_directory)
+ return false;
+
+ size_t directory_count = debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY);
+ for (size_t index = 0; index < directory_count; ++index) {
+ const IMAGE_DEBUG_DIRECTORY& entry = debug_directory[index];
+ if (entry.Type != IMAGE_DEBUG_TYPE_CODEVIEW)
+ continue; // Unsupported debugging info format.
+ if (entry.SizeOfData < sizeof(PdbInfo))
+ continue; // The data is too small to hold PDB info.
+ const PdbInfo* pdb_info =
+ reinterpret_cast<const PdbInfo*>(RVAToAddr(entry.AddressOfRawData));
+ if (!pdb_info)
+ continue; // The data is not present in a mapped section.
+ if (pdb_info->Signature != kPdbInfoSignature)
+ continue; // Unsupported PdbInfo signature
+
+ if (guid)
+ *guid = pdb_info->Guid;
+ if (age)
+ *age = pdb_info->Age;
+ if (pdb_filename) {
+ const size_t length_max =
+ entry.SizeOfData - offsetof(PdbInfo, PdbFileName);
+ const char* eos = pdb_info->PdbFileName;
+ for (const char* const end = pdb_info->PdbFileName + length_max;
+ eos < end && *eos; ++eos)
+ ;
+ *pdb_filename_length = eos - pdb_info->PdbFileName;
+ *pdb_filename = pdb_info->PdbFileName;
+ }
+ return true;
+ }
+ return false;
+}
+
+PDWORD PEImage::GetExportEntry(LPCSTR name) const {
+ PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
+
+ if (nullptr == exports)
+ return nullptr;
+
+ WORD ordinal = 0;
+ if (!GetProcOrdinal(name, &ordinal))
+ return nullptr;
+
+ PDWORD functions =
+ reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfFunctions));
+
+ return functions + ordinal - exports->Base;
+}
+
+FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
+ PDWORD export_entry = GetExportEntry(function_name);
+ if (nullptr == export_entry)
+ return nullptr;
+
+ PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry));
+
+ PBYTE exports = reinterpret_cast<PBYTE>(
+ GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+ DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+ if (!exports || !size)
+ return nullptr;
+
+ // Check for forwarded exports as a special case.
+ if (exports <= function && exports + size > function)
+ return reinterpret_cast<FARPROC>(-1);
+
+ return reinterpret_cast<FARPROC>(function);
+}
+
+bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD* ordinal) const {
+ if (nullptr == ordinal)
+ return false;
+
+ PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
+
+ if (nullptr == exports)
+ return false;
+
+ if (IsOrdinal(function_name)) {
+ *ordinal = ToOrdinal(function_name);
+ } else {
+ PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+ PDWORD lower = names;
+ PDWORD upper = names + exports->NumberOfNames;
+ int cmp = -1;
+
+ // Binary Search for the name.
+ while (lower != upper) {
+ PDWORD middle = lower + (upper - lower) / 2;
+ LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle));
+
+ // This may be called by sandbox before MSVCRT dll loads, so can't use
+ // CRT function here.
+ cmp = StrCmpByByte(function_name, name);
+
+ if (cmp == 0) {
+ lower = middle;
+ break;
+ }
+
+ if (cmp > 0)
+ lower = middle + 1;
+ else
+ upper = middle;
+ }
+
+ if (cmp != 0)
+ return false;
+
+ PWORD ordinals =
+ reinterpret_cast<PWORD>(RVAToAddr(exports->AddressOfNameOrdinals));
+
+ *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base);
+ }
+
+ return true;
+}
+
+bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const {
+ PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+ UINT num_sections = nt_headers->FileHeader.NumberOfSections;
+ PIMAGE_SECTION_HEADER section = GetSectionHeader(0);
+
+ for (UINT i = 0; i < num_sections; i++, section++) {
+ PVOID section_start = RVAToAddr(section->VirtualAddress);
+ DWORD size = section->Misc.VirtualSize;
+
+ if (!callback(*this, section, section_start, size, cookie))
+ return false;
+ }
+
+ return true;
+}
+
+bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const {
+ PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT);
+ DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+ // Check if there are any exports at all.
+ if (!directory || !size)
+ return true;
+
+ PIMAGE_EXPORT_DIRECTORY exports =
+ reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(directory);
+ UINT ordinal_base = exports->Base;
+ UINT num_funcs = exports->NumberOfFunctions;
+ UINT num_names = exports->NumberOfNames;
+ PDWORD functions =
+ reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfFunctions));
+ PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+ PWORD ordinals =
+ reinterpret_cast<PWORD>(RVAToAddr(exports->AddressOfNameOrdinals));
+
+ for (UINT count = 0; count < num_funcs; count++) {
+ PVOID func = RVAToAddr(functions[count]);
+ if (nullptr == func)
+ continue;
+
+ // Check for a name.
+ LPCSTR name = nullptr;
+ UINT hint;
+ for (hint = 0; hint < num_names; hint++) {
+ if (ordinals[hint] == count) {
+ name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint]));
+ break;
+ }
+ }
+
+ if (name == nullptr)
+ hint = 0;
+
+ // Check for forwarded exports.
+ LPCSTR forward = nullptr;
+ if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) &&
+ reinterpret_cast<char*>(func) <=
+ reinterpret_cast<char*>(directory) + size) {
+ forward = reinterpret_cast<LPCSTR>(func);
+ func = nullptr;
+ }
+
+ if (!callback(*this, ordinal_base + count, hint, name, func, forward,
+ cookie))
+ return false;
+ }
+
+ return true;
+}
+
+bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const {
+ PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+ DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+
+ if (!directory || !size)
+ return true;
+
+ PIMAGE_BASE_RELOCATION base =
+ reinterpret_cast<PIMAGE_BASE_RELOCATION>(directory);
+ while (size >= sizeof(IMAGE_BASE_RELOCATION) && base->SizeOfBlock &&
+ size >= base->SizeOfBlock) {
+ PWORD reloc = reinterpret_cast<PWORD>(base + 1);
+ UINT num_relocs =
+ (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
+
+ for (UINT i = 0; i < num_relocs; i++, reloc++) {
+ WORD type = *reloc >> 12;
+ PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF));
+
+ if (!callback(*this, type, address, cookie))
+ return false;
+ }
+
+ size -= base->SizeOfBlock;
+ base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
+ reinterpret_cast<char*>(base) + base->SizeOfBlock);
+ }
+
+ return true;
+}
+
+bool PEImage::EnumImportChunks(EnumImportChunksFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const {
+ DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
+ PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk();
+
+ if (import == nullptr || size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
+ return true;
+
+ for (; import->FirstThunk; import++) {
+ LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name));
+ PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+ RVAToAddr(import->OriginalFirstThunk));
+ PIMAGE_THUNK_DATA iat =
+ reinterpret_cast<PIMAGE_THUNK_DATA>(RVAToAddr(import->FirstThunk));
+
+ if (target_module_name == nullptr ||
+ (lstrcmpiA(module_name, target_module_name) == 0)) {
+ if (!callback(*this, module_name, name_table, iat, cookie))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PEImage::EnumOneImportChunk(EnumImportsFunction callback,
+ LPCSTR module_name,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) const {
+ if (nullptr == name_table)
+ return false;
+
+ for (; name_table && name_table->u1.Ordinal; name_table++, iat++) {
+ LPCSTR name = nullptr;
+ WORD ordinal = 0;
+ WORD hint = 0;
+
+ if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+ ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+ } else {
+ PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+ RVAToAddr(name_table->u1.ForwarderString));
+
+ hint = import->Hint;
+ name = reinterpret_cast<LPCSTR>(&import->Name);
+ }
+
+ if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+ return false;
+ }
+
+ return true;
+}
+
+bool PEImage::EnumAllImports(EnumImportsFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const {
+ EnumAllImportsStorage temp = {callback, cookie};
+ return EnumImportChunks(ProcessImportChunk, &temp, target_module_name);
+}
+
+bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const {
+ PVOID directory =
+ GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+ DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+
+ if (!directory || !size)
+ return true;
+
+ PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory);
+ for (; delay_descriptor->rvaHmod; delay_descriptor++) {
+ PIMAGE_THUNK_DATA name_table;
+ PIMAGE_THUNK_DATA iat;
+ LPCSTR module_name;
+
+ // check if VC7-style imports, using RVAs instead of
+ // VC6-style addresses.
+ bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+ if (rvas) {
+ module_name =
+ reinterpret_cast<LPCSTR>(RVAToAddr(delay_descriptor->rvaDLLName));
+ name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+ RVAToAddr(delay_descriptor->rvaINT));
+ iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+ RVAToAddr(delay_descriptor->rvaIAT));
+ } else {
+ // Values in IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT are 32-bit, even on 64-bit
+ // platforms. See section 4.8 of PECOFF image spec rev 8.3.
+ module_name = reinterpret_cast<LPCSTR>(
+ static_cast<uintptr_t>(delay_descriptor->rvaDLLName));
+ name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+ static_cast<uintptr_t>(delay_descriptor->rvaINT));
+ iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+ static_cast<uintptr_t>(delay_descriptor->rvaIAT));
+ }
+
+ if (target_module_name == nullptr ||
+ (lstrcmpiA(module_name, target_module_name) == 0)) {
+ if (target_module_name) {
+ // Ensure all imports are properly loaded for the target module so that
+ // the callback is operating on a fully-realized set of imports.
+ // This call only loads the imports for the module where this code is
+ // executing, so it is only helpful or meaningful to do this if the
+ // current module is the module whose IAT we are enumerating.
+ // Use the module_name as retrieved from the IAT because this method
+ // is case sensitive.
+ if (module_ == CURRENT_MODULE() && !LDR_IS_RESOURCE(module_)) {
+ static base::NoDestructor<std::set<std::string>> loaded_dlls;
+ // pair.second is true if this is a new element
+ if (loaded_dlls.get()->emplace(module_name).second)
+ ::__HrLoadAllImportsForDll(module_name);
+ }
+ }
+
+ if (!callback(*this, delay_descriptor, module_name, name_table, iat,
+ cookie))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
+ PImgDelayDescr delay_descriptor,
+ LPCSTR module_name,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) const {
+ for (; name_table->u1.Ordinal; name_table++, iat++) {
+ LPCSTR name = nullptr;
+ WORD ordinal = 0;
+ WORD hint = 0;
+
+ if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+ ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+ } else {
+ PIMAGE_IMPORT_BY_NAME import;
+ bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+ if (rvas) {
+ import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+ RVAToAddr(name_table->u1.ForwarderString));
+ } else {
+ import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+ name_table->u1.ForwarderString);
+ }
+
+ hint = import->Hint;
+ name = reinterpret_cast<LPCSTR>(&import->Name);
+ }
+
+ if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+ return false;
+ }
+
+ return true;
+}
+
+bool PEImage::EnumAllDelayImports(EnumImportsFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const {
+ EnumAllImportsStorage temp = {callback, cookie};
+ return EnumDelayImportChunks(ProcessDelayImportChunk, &temp,
+ target_module_name);
+}
+
+bool PEImage::VerifyMagic() const {
+ PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+ if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
+ return false;
+
+ PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+ if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
+ return false;
+
+ if (nt_headers->FileHeader.SizeOfOptionalHeader !=
+ sizeof(IMAGE_OPTIONAL_HEADER))
+ return false;
+
+ if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
+ return false;
+
+ return true;
+}
+
+bool PEImage::ImageRVAToOnDiskOffset(uintptr_t rva,
+ DWORD* on_disk_offset) const {
+ LPVOID address = RVAToAddr(rva);
+ return ImageAddrToOnDiskOffset(address, on_disk_offset);
+}
+
+bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
+ DWORD* on_disk_offset) const {
+ if (nullptr == address)
+ return false;
+
+ // Get the section that this address belongs to.
+ PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address);
+ if (nullptr == section_header)
+ return false;
+
+ // Don't follow the virtual RVAToAddr, use the one on the base.
+ DWORD offset_within_section =
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(
+ PEImage::RVAToAddr(section_header->VirtualAddress)));
+
+ *on_disk_offset = section_header->PointerToRawData + offset_within_section;
+ return true;
+}
+
+PVOID PEImage::RVAToAddr(uintptr_t rva) const {
+ if (rva == 0)
+ return nullptr;
+
+ return reinterpret_cast<char*>(module_) + rva;
+}
+
+const IMAGE_DATA_DIRECTORY* PEImage::GetDataDirectory(UINT directory) const {
+ PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+ // Does the image report that it includes this directory entry?
+ if (directory >= nt_headers->OptionalHeader.NumberOfRvaAndSizes)
+ return nullptr;
+
+ // Is there space for this directory entry in the optional header?
+ if (nt_headers->FileHeader.SizeOfOptionalHeader <
+ (offsetof(IMAGE_OPTIONAL_HEADER, DataDirectory) +
+ (directory + 1) * sizeof(IMAGE_DATA_DIRECTORY))) {
+ return nullptr;
+ }
+
+ return &nt_headers->OptionalHeader.DataDirectory[directory];
+}
+
+PVOID PEImageAsData::RVAToAddr(uintptr_t rva) const {
+ if (rva == 0)
+ return nullptr;
+
+ PVOID in_memory = PEImage::RVAToAddr(rva);
+ DWORD disk_offset;
+
+ if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset))
+ return nullptr;
+
+ return PEImage::RVAToAddr(disk_offset);
+}
+
+} // namespace win
+} // namespace base
diff --git a/security/sandbox/chromium/base/win/pe_image.h b/security/sandbox/chromium/base/win/pe_image.h
new file mode 100644
index 0000000000..cec959a940
--- /dev/null
+++ b/security/sandbox/chromium/base/win/pe_image.h
@@ -0,0 +1,308 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file was adapted from GreenBorder's Code.
+// To understand what this class is about (for other than well known functions
+// as GetProcAddress), a good starting point is "An In-Depth Look into the
+// Win32 Portable Executable File Format" by Matt Pietrek:
+// http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
+
+#ifndef BASE_WIN_PE_IMAGE_H_
+#define BASE_WIN_PE_IMAGE_H_
+
+#include <windows.h>
+
+#include <stdint.h>
+
+#if defined(_WIN32_WINNT_WIN8)
+// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
+#undef FACILITY_VISUALCPP
+#endif
+#include <delayimp.h>
+
+namespace base {
+namespace win {
+
+// This class is a wrapper for the Portable Executable File Format (PE).
+// Its main purpose is to provide an easy way to work with imports and exports
+// from a file, mapped in memory as image.
+class PEImage {
+ public:
+ // Callback to enumerate sections.
+ // cookie is the value passed to the enumerate method.
+ // Returns true to continue the enumeration.
+ using EnumSectionsFunction =
+ bool (*)(const PEImage&, PIMAGE_SECTION_HEADER, PVOID, DWORD, PVOID);
+
+ // Callback to enumerate exports.
+ // function is the actual address of the symbol. If forward is not null, it
+ // contains the dll and symbol to forward this export to. cookie is the value
+ // passed to the enumerate method.
+ // Returns true to continue the enumeration.
+ using EnumExportsFunction =
+ bool (*)(const PEImage&, DWORD, DWORD, LPCSTR, PVOID, LPCSTR, PVOID);
+
+ // Callback to enumerate import blocks.
+ // name_table and iat point to the imports name table and address table for
+ // this block. cookie is the value passed to the enumerate method.
+ // Returns true to continue the enumeration.
+ using EnumImportChunksFunction = bool (*)(const PEImage&,
+ LPCSTR,
+ PIMAGE_THUNK_DATA,
+ PIMAGE_THUNK_DATA,
+ PVOID);
+
+ // Callback to enumerate imports.
+ // module is the dll that exports this symbol. cookie is the value passed to
+ // the enumerate method.
+ // Returns true to continue the enumeration.
+ using EnumImportsFunction = bool (*)(const PEImage&,
+ LPCSTR,
+ DWORD,
+ LPCSTR,
+ DWORD,
+ PIMAGE_THUNK_DATA,
+ PVOID);
+
+ // Callback to enumerate delayed import blocks.
+ // module is the dll that exports this block of symbols. cookie is the value
+ // passed to the enumerate method.
+ // Returns true to continue the enumeration.
+ using EnumDelayImportChunksFunction = bool (*)(const PEImage&,
+ PImgDelayDescr,
+ LPCSTR,
+ PIMAGE_THUNK_DATA,
+ PIMAGE_THUNK_DATA,
+ PVOID);
+
+ // Callback to enumerate relocations.
+ // cookie is the value passed to the enumerate method.
+ // Returns true to continue the enumeration.
+ using EnumRelocsFunction = bool (*)(const PEImage&, WORD, PVOID, PVOID);
+
+ explicit PEImage(HMODULE module) : module_(module) {}
+ explicit PEImage(const void* module) {
+ module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
+ }
+
+ virtual ~PEImage() = default;
+
+ // Gets the HMODULE for this object.
+ HMODULE module() const;
+
+ // Sets this object's HMODULE.
+ void set_module(HMODULE module);
+
+ // Checks if this symbol is actually an ordinal.
+ static bool IsOrdinal(LPCSTR name);
+
+ // Converts a named symbol to the corresponding ordinal.
+ static WORD ToOrdinal(LPCSTR name);
+
+ // Returns the DOS_HEADER for this PE.
+ PIMAGE_DOS_HEADER GetDosHeader() const;
+
+ // Returns the NT_HEADER for this PE.
+ PIMAGE_NT_HEADERS GetNTHeaders() const;
+
+ // Returns number of sections of this PE.
+ WORD GetNumSections() const;
+
+ // Returns the header for a given section.
+ // returns NULL if there is no such section.
+ PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const;
+
+ // Returns the size of a given directory entry or 0 if |directory| is out of
+ // bounds.
+ DWORD GetImageDirectoryEntrySize(UINT directory) const;
+
+ // Returns the address of a given directory entry or NULL if |directory| is
+ // out of bounds.
+ PVOID GetImageDirectoryEntryAddr(UINT directory) const;
+
+ // Returns the section header for a given address.
+ // Use: s = image.GetImageSectionFromAddr(a);
+ // Post: 's' is the section header of the section that contains 'a'
+ // or NULL if there is no such section.
+ PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const;
+
+ // Returns the section header for a given section.
+ PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const;
+
+ // Returns the first block of imports.
+ PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const;
+
+ // Returns the exports directory.
+ PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
+
+ // Retrieves the contents of the image's CodeView debug entry, returning true
+ // if such an entry is found and is within a section mapped into the current
+ // process's memory. |guid|, |age|, and |pdb_filename| are each optional and
+ // may be NULL. |pdb_filename_length| is mandatory if |pdb_filename| is not
+ // NULL, as the latter is populated with a direct reference to a string in the
+ // image that is is not guaranteed to be terminated (note: informal
+ // documentation indicates that it should be terminated, but the data is
+ // untrusted). Furthermore, owing to its nature of being a string in the
+ // image, it is only valid while the image is mapped into the process, and the
+ // caller is not responsible for freeing it. |pdb_filename_length| is
+ // populated with the string length of |pdb_filename| (not including a
+ // terminator) and must be used rather than relying on |pdb_filename| being
+ // properly terminated.
+ bool GetDebugId(LPGUID guid,
+ LPDWORD age,
+ LPCSTR* pdb_filename,
+ size_t* pdb_filename_length) const;
+
+ // Returns a given export entry.
+ // Use: e = image.GetExportEntry(f);
+ // Pre: 'f' is either a zero terminated string or ordinal
+ // Post: 'e' is a pointer to the export directory entry
+ // that contains 'f's export RVA, or NULL if 'f'
+ // is not exported from this image
+ PDWORD GetExportEntry(LPCSTR name) const;
+
+ // Returns the address for a given exported symbol.
+ // Use: p = image.GetProcAddress(f);
+ // Pre: 'f' is either a zero terminated string or ordinal.
+ // Post: if 'f' is a non-forwarded export from image, 'p' is
+ // the exported function. If 'f' is a forwarded export
+ // then p is the special value -1. In this case
+ // RVAToAddr(*GetExportEntry) can be used to resolve
+ // the string that describes the forward.
+ FARPROC GetProcAddress(LPCSTR function_name) const;
+
+ // Retrieves the ordinal for a given exported symbol.
+ // Returns true if the symbol was found.
+ bool GetProcOrdinal(LPCSTR function_name, WORD* ordinal) const;
+
+ // Enumerates PE sections.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const;
+
+ // Enumerates PE exports.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ bool EnumExports(EnumExportsFunction callback, PVOID cookie) const;
+
+ // Enumerates PE imports.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ // Use |target_module_name| to ensure the callback is only invoked for the
+ // specified module.
+ bool EnumAllImports(EnumImportsFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const;
+
+ // Enumerates PE import blocks.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ // Use |target_module_name| to ensure the callback is only invoked for the
+ // specified module.
+ bool EnumImportChunks(EnumImportChunksFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const;
+
+ // Enumerates the imports from a single PE import block.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ bool EnumOneImportChunk(EnumImportsFunction callback,
+ LPCSTR module_name,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) const;
+
+ // Enumerates PE delay imports.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ // Use |target_module_name| to ensure the callback is only invoked for the
+ // specified module. If this parameter is non-null then all delayloaded
+ // imports are resolved when the target module is found.
+ bool EnumAllDelayImports(EnumImportsFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const;
+
+ // Enumerates PE delay import blocks.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ // Use |target_module_name| to ensure the callback is only invoked for the
+ // specified module. If this parameter is non-null then all delayloaded
+ // imports are resolved when the target module is found.
+ bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+ PVOID cookie,
+ LPCSTR target_module_name) const;
+
+ // Enumerates imports from a single PE delay import block.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ bool EnumOneDelayImportChunk(EnumImportsFunction callback,
+ PImgDelayDescr delay_descriptor,
+ LPCSTR module_name,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) const;
+
+ // Enumerates PE relocation entries.
+ // cookie is a generic cookie to pass to the callback.
+ // Returns true on success.
+ bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const;
+
+ // Verifies the magic values on the PE file.
+ // Returns true if all values are correct.
+ bool VerifyMagic() const;
+
+ // Converts an rva value to the appropriate address.
+ virtual PVOID RVAToAddr(uintptr_t rva) const;
+
+ // Converts an rva value to an offset on disk.
+ // Returns true on success.
+ bool ImageRVAToOnDiskOffset(uintptr_t rva, DWORD* on_disk_offset) const;
+
+ // Converts an address to an offset on disk.
+ // Returns true on success.
+ bool ImageAddrToOnDiskOffset(LPVOID address, DWORD* on_disk_offset) const;
+
+ private:
+ // Returns a pointer to a data directory, or NULL if |directory| is out of
+ // range.
+ const IMAGE_DATA_DIRECTORY* GetDataDirectory(UINT directory) const;
+
+ HMODULE module_;
+};
+
+// This class is an extension to the PEImage class that allows working with PE
+// files mapped as data instead of as image file.
+class PEImageAsData : public PEImage {
+ public:
+ explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
+
+ PVOID RVAToAddr(uintptr_t rva) const override;
+};
+
+inline bool PEImage::IsOrdinal(LPCSTR name) {
+ return reinterpret_cast<uintptr_t>(name) <= 0xFFFF;
+}
+
+inline WORD PEImage::ToOrdinal(LPCSTR name) {
+ return static_cast<WORD>(reinterpret_cast<intptr_t>(name));
+}
+
+inline HMODULE PEImage::module() const {
+ return module_;
+}
+
+inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const {
+ return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
+ GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT));
+}
+
+inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const {
+ return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
+ GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+}
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_PE_IMAGE_H_
diff --git a/security/sandbox/chromium/base/win/scoped_handle.cc b/security/sandbox/chromium/base/win/scoped_handle.cc
new file mode 100644
index 0000000000..de6854591b
--- /dev/null
+++ b/security/sandbox/chromium/base/win/scoped_handle.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_handle_verifier.h"
+#include "base/win/windows_types.h"
+
+namespace base {
+namespace win {
+
+using base::win::internal::ScopedHandleVerifier;
+
+// Static.
+bool HandleTraits::CloseHandle(HANDLE handle) {
+ return ScopedHandleVerifier::Get()->CloseHandle(handle);
+}
+
+// Static.
+void VerifierTraits::StartTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {
+ return ScopedHandleVerifier::Get()->StartTracking(handle, owner, pc1, pc2);
+}
+
+// Static.
+void VerifierTraits::StopTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {
+ return ScopedHandleVerifier::Get()->StopTracking(handle, owner, pc1, pc2);
+}
+
+void DisableHandleVerifier() {
+ return ScopedHandleVerifier::Get()->Disable();
+}
+
+void OnHandleBeingClosed(HANDLE handle) {
+ return ScopedHandleVerifier::Get()->OnHandleBeingClosed(handle);
+}
+
+} // namespace win
+} // namespace base
diff --git a/security/sandbox/chromium/base/win/scoped_handle.h b/security/sandbox/chromium/base/win/scoped_handle.h
new file mode 100644
index 0000000000..02c2533649
--- /dev/null
+++ b/security/sandbox/chromium/base/win/scoped_handle.h
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HANDLE_H_
+#define BASE_WIN_SCOPED_HANDLE_H_
+
+#include "base/win/windows_types.h"
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+
+// TODO(rvargas): remove this with the rest of the verifier.
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#define BASE_WIN_GET_CALLER _ReturnAddress()
+#elif defined(COMPILER_GCC)
+#define BASE_WIN_GET_CALLER \
+ __builtin_extract_return_addr(__builtin_return_address(0))
+#endif
+
+namespace base {
+namespace win {
+
+// Generic wrapper for raw handles that takes care of closing handles
+// automatically. The class interface follows the style of
+// the ScopedFILE class with two additions:
+// - IsValid() method can tolerate multiple invalid handle values such as NULL
+// and INVALID_HANDLE_VALUE (-1) for Win32 handles.
+// - Set() (and the constructors and assignment operators that call it)
+// preserve the Windows LastError code. This ensures that GetLastError() can
+// be called after stashing a handle in a GenericScopedHandle object. Doing
+// this explicitly is necessary because of bug 528394 and VC++ 2015.
+template <class Traits, class Verifier>
+class GenericScopedHandle {
+ public:
+ using Handle = typename Traits::Handle;
+
+ GenericScopedHandle() : handle_(Traits::NullHandle()) {}
+
+ explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
+ Set(handle);
+ }
+
+ GenericScopedHandle(GenericScopedHandle&& other)
+ : handle_(Traits::NullHandle()) {
+ Set(other.Take());
+ }
+
+ ~GenericScopedHandle() { Close(); }
+
+ bool IsValid() const { return Traits::IsHandleValid(handle_); }
+
+ GenericScopedHandle& operator=(GenericScopedHandle&& other) {
+ DCHECK_NE(this, &other);
+ Set(other.Take());
+ return *this;
+ }
+
+ void Set(Handle handle) {
+ if (handle_ != handle) {
+ // Preserve old LastError to avoid bug 528394.
+ auto last_error = ::GetLastError();
+ Close();
+
+ if (Traits::IsHandleValid(handle)) {
+ handle_ = handle;
+ Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
+ GetProgramCounter());
+ }
+ ::SetLastError(last_error);
+ }
+ }
+
+ Handle Get() const { return handle_; }
+
+ // Transfers ownership away from this object.
+ Handle Take() WARN_UNUSED_RESULT {
+ Handle temp = handle_;
+ handle_ = Traits::NullHandle();
+ if (Traits::IsHandleValid(temp)) {
+ Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
+ GetProgramCounter());
+ }
+ return temp;
+ }
+
+ // Explicitly closes the owned handle.
+ void Close() {
+ if (Traits::IsHandleValid(handle_)) {
+ Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
+ GetProgramCounter());
+
+ Traits::CloseHandle(handle_);
+ handle_ = Traits::NullHandle();
+ }
+ }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, ActiveVerifierWrongOwner);
+ FRIEND_TEST_ALL_PREFIXES(ScopedHandleTest, ActiveVerifierUntrackedHandle);
+ Handle handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(GenericScopedHandle);
+};
+
+#undef BASE_WIN_GET_CALLER
+
+// The traits class for Win32 handles that can be closed via CloseHandle() API.
+class HandleTraits {
+ public:
+ using Handle = HANDLE;
+
+ // Closes the handle.
+ static bool BASE_EXPORT CloseHandle(HANDLE handle);
+
+ // Returns true if the handle value is valid.
+ static bool IsHandleValid(HANDLE handle) {
+ return handle != nullptr && handle != INVALID_HANDLE_VALUE;
+ }
+
+ // Returns NULL handle value.
+ static HANDLE NullHandle() { return nullptr; }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);
+};
+
+// Do-nothing verifier.
+class DummyVerifierTraits {
+ public:
+ using Handle = HANDLE;
+
+ static void StartTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {}
+ static void StopTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {}
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits);
+};
+
+// Performs actual run-time tracking.
+class BASE_EXPORT VerifierTraits {
+ public:
+ using Handle = HANDLE;
+
+ static void StartTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2);
+ static void StopTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
+};
+
+using ScopedHandle = GenericScopedHandle<HandleTraits, VerifierTraits>;
+
+// This function may be called by the embedder to disable the use of
+// VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
+// for ScopedHandle.
+BASE_EXPORT void DisableHandleVerifier();
+
+// This should be called whenever the OS is closing a handle, if extended
+// verification of improper handle closing is desired. If |handle| is being
+// tracked by the handle verifier and ScopedHandle is not the one closing it,
+// a CHECK is generated.
+BASE_EXPORT void OnHandleBeingClosed(HANDLE handle);
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SCOPED_HANDLE_H_
diff --git a/security/sandbox/chromium/base/win/scoped_handle_verifier.cc b/security/sandbox/chromium/base/win/scoped_handle_verifier.cc
new file mode 100644
index 0000000000..316606c0bf
--- /dev/null
+++ b/security/sandbox/chromium/base/win/scoped_handle_verifier.cc
@@ -0,0 +1,238 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_handle_verifier.h"
+
+#include <windows.h>
+
+#include <stddef.h>
+
+#include <unordered_map>
+
+#include "base/debug/alias.h"
+#include "base/debug/stack_trace.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/win/base_win_buildflags.h"
+#include "base/win/current_module.h"
+
+extern "C" {
+__declspec(dllexport) void* GetHandleVerifier();
+
+void* GetHandleVerifier() {
+ return base::win::internal::ScopedHandleVerifier::Get();
+}
+} // extern C
+
+namespace {
+
+base::win::internal::ScopedHandleVerifier* g_active_verifier = nullptr;
+using GetHandleVerifierFn = void* (*)();
+using HandleMap =
+ std::unordered_map<HANDLE,
+ base::win::internal::ScopedHandleVerifierInfo,
+ base::win::internal::HandleHash>;
+using NativeLock = base::internal::LockImpl;
+
+NativeLock* GetLock() {
+ static auto* native_lock = new NativeLock();
+ return native_lock;
+}
+
+// Simple automatic locking using a native critical section so it supports
+// recursive locking.
+class AutoNativeLock {
+ public:
+ explicit AutoNativeLock(NativeLock& lock) : lock_(lock) { lock_.Lock(); }
+
+ ~AutoNativeLock() { lock_.Unlock(); }
+
+ private:
+ NativeLock& lock_;
+ DISALLOW_COPY_AND_ASSIGN(AutoNativeLock);
+};
+
+} // namespace
+
+namespace base {
+namespace win {
+namespace internal {
+
+ScopedHandleVerifier::ScopedHandleVerifier(bool enabled)
+ : enabled_(enabled), lock_(GetLock()) {}
+
+// static
+ScopedHandleVerifier* ScopedHandleVerifier::Get() {
+ if (!g_active_verifier)
+ ScopedHandleVerifier::InstallVerifier();
+
+ return g_active_verifier;
+}
+
+bool CloseHandleWrapper(HANDLE handle) {
+ if (!::CloseHandle(handle))
+ // Making this DCHECK on non-Nighly as we are hitting this frequently,
+ // looks like we are closing handles twice somehow. See bug 1564899.
+#if defined(NIGHTLY_BUILD)
+ CHECK(false); // CloseHandle failed.
+#else
+ DCHECK(false); // CloseHandle failed.
+#endif
+ return true;
+}
+
+// Assigns the g_active_verifier global within the GetLock() lock.
+// If |existing_verifier| is non-null then |enabled| is ignored.
+void ThreadSafeAssignOrCreateScopedHandleVerifier(
+ ScopedHandleVerifier* existing_verifier,
+ bool enabled) {
+ AutoNativeLock lock(*GetLock());
+ // Another thread in this module might be trying to assign the global
+ // verifier, so check that within the lock here.
+ if (g_active_verifier)
+ return;
+ g_active_verifier =
+ existing_verifier ? existing_verifier : new ScopedHandleVerifier(enabled);
+}
+
+// static
+void ScopedHandleVerifier::InstallVerifier() {
+#if BUILDFLAG(SINGLE_MODULE_MODE_HANDLE_VERIFIER)
+ // Component build has one Active Verifier per module.
+ ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, true);
+#else
+ // If you are reading this, wondering why your process seems deadlocked, take
+ // a look at your DllMain code and remove things that should not be done
+ // there, like doing whatever gave you that nice windows handle you are trying
+ // to store in a ScopedHandle.
+ HMODULE main_module = ::GetModuleHandle(NULL);
+ GetHandleVerifierFn get_handle_verifier =
+ reinterpret_cast<GetHandleVerifierFn>(
+ ::GetProcAddress(main_module, "GetHandleVerifier"));
+
+ // This should only happen if running in a DLL is linked with base but the
+ // hosting EXE is not. In this case, create an ScopedHandleVerifier for the
+ // current
+ // module but leave it disabled.
+ if (!get_handle_verifier) {
+ ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, false);
+ return;
+ }
+
+ // Check if in the main module.
+ if (get_handle_verifier == GetHandleVerifier) {
+ ThreadSafeAssignOrCreateScopedHandleVerifier(nullptr, true);
+ return;
+ }
+
+ ScopedHandleVerifier* main_module_verifier =
+ reinterpret_cast<ScopedHandleVerifier*>(get_handle_verifier());
+
+ // Main module should always on-demand create a verifier.
+ DCHECK(main_module_verifier);
+
+ ThreadSafeAssignOrCreateScopedHandleVerifier(main_module_verifier, false);
+#endif
+}
+
+bool ScopedHandleVerifier::CloseHandle(HANDLE handle) {
+ if (!enabled_)
+ return CloseHandleWrapper(handle);
+
+ closing_.Set(true);
+ CloseHandleWrapper(handle);
+ closing_.Set(false);
+
+ return true;
+}
+
+// static
+NativeLock* ScopedHandleVerifier::GetLock() {
+ return ::GetLock();
+}
+
+void ScopedHandleVerifier::StartTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {
+ if (!enabled_)
+ return;
+
+ // Grab the thread id before the lock.
+ DWORD thread_id = GetCurrentThreadId();
+
+ AutoNativeLock lock(*lock_);
+
+ ScopedHandleVerifierInfo handle_info = {owner, pc1, pc2,
+ base::debug::StackTrace(), thread_id};
+ std::pair<HANDLE, ScopedHandleVerifierInfo> item(handle, handle_info);
+ std::pair<HandleMap::iterator, bool> result = map_.insert(item);
+ if (!result.second) {
+ ScopedHandleVerifierInfo other = result.first->second;
+ base::debug::Alias(&other);
+ auto creation_stack = creation_stack_;
+ base::debug::Alias(&creation_stack);
+ CHECK(false); // Attempt to start tracking already tracked handle.
+ }
+}
+
+void ScopedHandleVerifier::StopTracking(HANDLE handle,
+ const void* owner,
+ const void* pc1,
+ const void* pc2) {
+ if (!enabled_)
+ return;
+
+ AutoNativeLock lock(*lock_);
+ HandleMap::iterator i = map_.find(handle);
+ if (i == map_.end()) {
+ auto creation_stack = creation_stack_;
+ base::debug::Alias(&creation_stack);
+ CHECK(false); // Attempting to close an untracked handle.
+ }
+
+ ScopedHandleVerifierInfo other = i->second;
+ if (other.owner != owner) {
+ base::debug::Alias(&other);
+ auto creation_stack = creation_stack_;
+ base::debug::Alias(&creation_stack);
+ CHECK(false); // Attempting to close a handle not owned by opener.
+ }
+
+ map_.erase(i);
+}
+
+void ScopedHandleVerifier::Disable() {
+ enabled_ = false;
+}
+
+void ScopedHandleVerifier::OnHandleBeingClosed(HANDLE handle) {
+ if (!enabled_)
+ return;
+
+ if (closing_.Get())
+ return;
+
+ AutoNativeLock lock(*lock_);
+ HandleMap::iterator i = map_.find(handle);
+ if (i == map_.end())
+ return;
+
+ ScopedHandleVerifierInfo other = i->second;
+ base::debug::Alias(&other);
+ auto creation_stack = creation_stack_;
+ base::debug::Alias(&creation_stack);
+ CHECK(false); // CloseHandle called on tracked handle.
+}
+
+HMODULE ScopedHandleVerifier::GetModule() const {
+ return CURRENT_MODULE();
+}
+
+HMODULE GetHandleVerifierModuleForTesting() {
+ return g_active_verifier->GetModule();
+}
+
+} // namespace internal
+} // namespace win
+} // namespace base
diff --git a/security/sandbox/chromium/base/win/scoped_handle_verifier.h b/security/sandbox/chromium/base/win/scoped_handle_verifier.h
new file mode 100644
index 0000000000..596e2c47eb
--- /dev/null
+++ b/security/sandbox/chromium/base/win/scoped_handle_verifier.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_HANDLE_VERIFIER_H_
+#define BASE_WIN_SCOPED_HANDLE_VERIFIER_H_
+
+#include "base/win/windows_types.h"
+
+#include <unordered_map>
+
+#include "base/base_export.h"
+#include "base/debug/stack_trace.h"
+#include "base/hash/hash.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+namespace win {
+namespace internal {
+
+struct HandleHash {
+ size_t operator()(const HANDLE& handle) const {
+ return base::FastHash(as_bytes(make_span(&handle, 1)));
+ }
+};
+
+struct ScopedHandleVerifierInfo {
+ const void* owner;
+ const void* pc1;
+ const void* pc2;
+ base::debug::StackTrace stack;
+ DWORD thread_id;
+};
+
+// Implements the actual object that is verifying handles for this process.
+// The active instance is shared across the module boundary but there is no
+// way to delete this object from the wrong side of it (or any side, actually).
+// We need [[clang::lto_visibility_public]] because instances of this class are
+// passed across module boundaries. This means different modules must have
+// compatible definitions of the class even when whole program optimization is
+// enabled - which is what this attribute accomplishes. The pragma stops MSVC
+// from emitting an unrecognized attribute warning.
+#pragma warning(push)
+#pragma warning(disable : 5030)
+class [[clang::lto_visibility_public]] ScopedHandleVerifier {
+#pragma warning(pop)
+ public:
+ explicit ScopedHandleVerifier(bool enabled);
+
+ // Retrieves the current verifier.
+ static ScopedHandleVerifier* Get();
+
+ // The methods required by HandleTraits. They are virtual because we need to
+ // forward the call execution to another module, instead of letting the
+ // compiler call the version that is linked in the current module.
+ virtual bool CloseHandle(HANDLE handle);
+ virtual void StartTracking(HANDLE handle, const void* owner, const void* pc1,
+ const void* pc2);
+ virtual void StopTracking(HANDLE handle, const void* owner, const void* pc1,
+ const void* pc2);
+ virtual void Disable();
+ virtual void OnHandleBeingClosed(HANDLE handle);
+ virtual HMODULE GetModule() const;
+
+ private:
+ ~ScopedHandleVerifier(); // Not implemented.
+
+ static base::internal::LockImpl* GetLock();
+ static void InstallVerifier();
+
+ base::debug::StackTrace creation_stack_;
+ bool enabled_;
+ base::ThreadLocalBoolean closing_;
+ base::internal::LockImpl* lock_;
+ std::unordered_map<HANDLE, ScopedHandleVerifierInfo, HandleHash> map_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedHandleVerifier);
+};
+
+// This testing function returns the module that the ActiveVerifier concrete
+// implementation was instantiated in.
+BASE_EXPORT HMODULE GetHandleVerifierModuleForTesting();
+
+} // namespace internal
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SCOPED_HANDLE_VERIFIER_H_
diff --git a/security/sandbox/chromium/base/win/scoped_process_information.cc b/security/sandbox/chromium/base/win/scoped_process_information.cc
new file mode 100644
index 0000000000..d3024bb5e9
--- /dev/null
+++ b/security/sandbox/chromium/base/win/scoped_process_information.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_process_information.h"
+
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Duplicates source into target, returning true upon success. |target| is
+// guaranteed to be untouched in case of failure. Succeeds with no side-effects
+// if source is NULL.
+bool CheckAndDuplicateHandle(HANDLE source, ScopedHandle* target) {
+ if (!source)
+ return true;
+
+ HANDLE temp = nullptr;
+ if (!::DuplicateHandle(::GetCurrentProcess(), source, ::GetCurrentProcess(),
+ &temp, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ DWORD last_error = ::GetLastError();
+ DPLOG(ERROR) << "Failed to duplicate a handle " << last_error;
+ ::SetLastError(last_error);
+ return false;
+ }
+ target->Set(temp);
+ return true;
+}
+
+} // namespace
+
+ScopedProcessInformation::ScopedProcessInformation() = default;
+
+ScopedProcessInformation::ScopedProcessInformation(
+ const PROCESS_INFORMATION& process_info) {
+ Set(process_info);
+}
+
+ScopedProcessInformation::~ScopedProcessInformation() {
+ Close();
+}
+
+bool ScopedProcessInformation::IsValid() const {
+ return process_id_ || process_handle_.Get() || thread_id_ ||
+ thread_handle_.Get();
+}
+
+void ScopedProcessInformation::Close() {
+ process_handle_.Close();
+ thread_handle_.Close();
+ process_id_ = 0;
+ thread_id_ = 0;
+}
+
+void ScopedProcessInformation::Set(const PROCESS_INFORMATION& process_info) {
+ if (IsValid())
+ Close();
+
+ process_handle_.Set(process_info.hProcess);
+ thread_handle_.Set(process_info.hThread);
+ process_id_ = process_info.dwProcessId;
+ thread_id_ = process_info.dwThreadId;
+}
+
+bool ScopedProcessInformation::DuplicateFrom(
+ const ScopedProcessInformation& other) {
+ DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL";
+ DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid";
+
+ if (CheckAndDuplicateHandle(other.process_handle(), &process_handle_) &&
+ CheckAndDuplicateHandle(other.thread_handle(), &thread_handle_)) {
+ process_id_ = other.process_id();
+ thread_id_ = other.thread_id();
+ return true;
+ }
+
+ return false;
+}
+
+PROCESS_INFORMATION ScopedProcessInformation::Take() {
+ PROCESS_INFORMATION process_information = {};
+ process_information.hProcess = process_handle_.Take();
+ process_information.hThread = thread_handle_.Take();
+ process_information.dwProcessId = process_id();
+ process_information.dwThreadId = thread_id();
+ process_id_ = 0;
+ thread_id_ = 0;
+
+ return process_information;
+}
+
+HANDLE ScopedProcessInformation::TakeProcessHandle() {
+ process_id_ = 0;
+ return process_handle_.Take();
+}
+
+HANDLE ScopedProcessInformation::TakeThreadHandle() {
+ thread_id_ = 0;
+ return thread_handle_.Take();
+}
+
+} // namespace win
+} // namespace base
diff --git a/security/sandbox/chromium/base/win/scoped_process_information.h b/security/sandbox/chromium/base/win/scoped_process_information.h
new file mode 100644
index 0000000000..3b85d1bfab
--- /dev/null
+++ b/security/sandbox/chromium/base/win/scoped_process_information.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
+#define BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Manages the closing of process and thread handles from PROCESS_INFORMATION
+// structures. Allows clients to take ownership of either handle independently.
+class BASE_EXPORT ScopedProcessInformation {
+ public:
+ ScopedProcessInformation();
+ explicit ScopedProcessInformation(const PROCESS_INFORMATION& process_info);
+ ~ScopedProcessInformation();
+
+ // Returns true iff this instance is holding a thread and/or process handle.
+ bool IsValid() const;
+
+ // Closes the held thread and process handles, if any.
+ void Close();
+
+ // Populates this instance with the provided |process_info|.
+ void Set(const PROCESS_INFORMATION& process_info);
+
+ // Populates this instance with duplicate handles and the thread/process IDs
+ // from |other|. Returns false in case of failure, in which case this instance
+ // will be completely unpopulated.
+ bool DuplicateFrom(const ScopedProcessInformation& other);
+
+ // Transfers ownership of the held PROCESS_INFORMATION, if any, away from this
+ // instance.
+ PROCESS_INFORMATION Take();
+
+ // Transfers ownership of the held process handle, if any, away from this
+ // instance. Note that the related process_id will also be cleared.
+ HANDLE TakeProcessHandle();
+
+ // Transfers ownership of the held thread handle, if any, away from this
+ // instance. Note that the related thread_id will also be cleared.
+ HANDLE TakeThreadHandle();
+
+ // Returns the held process handle, if any, while retaining ownership.
+ HANDLE process_handle() const { return process_handle_.Get(); }
+
+ // Returns the held thread handle, if any, while retaining ownership.
+ HANDLE thread_handle() const { return thread_handle_.Get(); }
+
+ // Returns the held process id, if any.
+ DWORD process_id() const { return process_id_; }
+
+ // Returns the held thread id, if any.
+ DWORD thread_id() const { return thread_id_; }
+
+ private:
+ ScopedHandle process_handle_;
+ ScopedHandle thread_handle_;
+ DWORD process_id_ = 0;
+ DWORD thread_id_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedProcessInformation);
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
diff --git a/security/sandbox/chromium/base/win/startup_information.cc b/security/sandbox/chromium/base/win/startup_information.cc
new file mode 100644
index 0000000000..a78508dcad
--- /dev/null
+++ b/security/sandbox/chromium/base/win/startup_information.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/startup_information.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+StartupInformation::StartupInformation() : startup_info_() {
+ startup_info_.StartupInfo.cb = sizeof(startup_info_);
+}
+
+StartupInformation::~StartupInformation() {
+ if (startup_info_.lpAttributeList) {
+ ::DeleteProcThreadAttributeList(startup_info_.lpAttributeList);
+ }
+}
+
+bool StartupInformation::InitializeProcThreadAttributeList(
+ DWORD attribute_count) {
+ if (startup_info_.StartupInfo.cb != sizeof(startup_info_) ||
+ startup_info_.lpAttributeList) {
+ return false;
+ }
+
+ SIZE_T size = 0;
+ ::InitializeProcThreadAttributeList(nullptr, attribute_count, 0, &size);
+ if (size == 0)
+ return false;
+
+ auto attribute_list = std::make_unique<char[]>(size);
+ auto* attribute_list_ptr =
+ reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(attribute_list.get());
+ if (!::InitializeProcThreadAttributeList(attribute_list_ptr, attribute_count,
+ 0, &size)) {
+ return false;
+ }
+
+ attribute_list_ = std::move(attribute_list);
+ startup_info_.lpAttributeList = attribute_list_ptr;
+
+ return true;
+}
+
+bool StartupInformation::UpdateProcThreadAttribute(DWORD_PTR attribute,
+ void* value,
+ size_t size) {
+ if (!startup_info_.lpAttributeList)
+ return false;
+ return !!::UpdateProcThreadAttribute(startup_info_.lpAttributeList, 0,
+ attribute, value, size, nullptr,
+ nullptr);
+}
+
+} // namespace win
+} // namespace base
diff --git a/security/sandbox/chromium/base/win/startup_information.h b/security/sandbox/chromium/base/win/startup_information.h
new file mode 100644
index 0000000000..7ef6965dd5
--- /dev/null
+++ b/security/sandbox/chromium/base/win/startup_information.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_STARTUP_INFORMATION_H_
+#define BASE_WIN_STARTUP_INFORMATION_H_
+
+#include <windows.h>
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace win {
+
+// Manages the lifetime of additional attributes in STARTUPINFOEX.
+class BASE_EXPORT StartupInformation {
+ public:
+ StartupInformation();
+
+ ~StartupInformation();
+
+ // Initialize the attribute list for the specified number of entries.
+ bool InitializeProcThreadAttributeList(DWORD attribute_count);
+
+ // Sets one entry in the initialized attribute list.
+ // |value| needs to live at least as long as the StartupInformation object
+ // this is called on.
+ bool UpdateProcThreadAttribute(DWORD_PTR attribute, void* value, size_t size);
+
+ LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; }
+ LPSTARTUPINFOW startup_info() const {
+ return const_cast<const LPSTARTUPINFOW>(&startup_info_.StartupInfo);
+ }
+
+ bool has_extended_startup_info() const {
+ return !!startup_info_.lpAttributeList;
+ }
+
+ private:
+ std::unique_ptr<char[]> attribute_list_;
+ STARTUPINFOEXW startup_info_;
+ DISALLOW_COPY_AND_ASSIGN(StartupInformation);
+};
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_STARTUP_INFORMATION_H_
diff --git a/security/sandbox/chromium/base/win/static_constants.cc b/security/sandbox/chromium/base/win/static_constants.cc
new file mode 100644
index 0000000000..f9894a22bd
--- /dev/null
+++ b/security/sandbox/chromium/base/win/static_constants.cc
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/static_constants.h"
+
+namespace base {
+namespace win {
+
+const char kApplicationVerifierDllName[] = "verifier.dll";
+
+} // namespace win
+} // namespace base
diff --git a/security/sandbox/chromium/base/win/static_constants.h b/security/sandbox/chromium/base/win/static_constants.h
new file mode 100644
index 0000000000..98a631f7cf
--- /dev/null
+++ b/security/sandbox/chromium/base/win/static_constants.h
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines constants needed before imports (like base.dll) are fully resolved.
+// For example, constants defined here can be used by interceptions (i.e. hooks)
+// in the sandbox, which run before imports are resolved, and can therefore only
+// reference static variables.
+
+#ifndef BASE_WIN_STATIC_CONSTANTS_H_
+#define BASE_WIN_STATIC_CONSTANTS_H_
+
+namespace base {
+namespace win {
+
+extern const char kApplicationVerifierDllName[];
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_STATIC_CONSTANTS_H_
diff --git a/security/sandbox/chromium/base/win/windows_types.h b/security/sandbox/chromium/base/win/windows_types.h
new file mode 100644
index 0000000000..9be05f3c25
--- /dev/null
+++ b/security/sandbox/chromium/base/win/windows_types.h
@@ -0,0 +1,278 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains defines and typedefs that allow popular Windows types to
+// be used without the overhead of including windows.h.
+
+#ifndef BASE_WIN_WINDOWS_TYPES_H
+#define BASE_WIN_WINDOWS_TYPES_H
+
+// Needed for function prototypes.
+#if defined(__MINGW32__)
+// MinGW doesn't have this file yet, but we only need this define.
+// Bug 1552706 tracks removing this and the one below.
+#define _Releases_exclusive_lock_(lock)
+// MinGW doesn't appear to have this in specstrings.h either.
+#define _Post_equals_last_error_
+#else
+#include <concurrencysal.h>
+#endif
+#include <sal.h>
+#include <specstrings.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// typedef and define the most commonly used Windows integer types.
+
+typedef unsigned long DWORD;
+typedef long LONG;
+typedef __int64 LONGLONG;
+typedef unsigned __int64 ULONGLONG;
+
+#define VOID void
+typedef char CHAR;
+typedef short SHORT;
+typedef long LONG;
+typedef int INT;
+typedef unsigned int UINT;
+typedef unsigned int* PUINT;
+typedef void* LPVOID;
+typedef void* PVOID;
+typedef void* HANDLE;
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef BYTE BOOLEAN;
+typedef DWORD ULONG;
+typedef unsigned short WORD;
+typedef WORD UWORD;
+typedef WORD ATOM;
+
+#if defined(_WIN64)
+typedef __int64 INT_PTR, *PINT_PTR;
+typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
+
+typedef __int64 LONG_PTR, *PLONG_PTR;
+typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
+#else
+typedef __w64 int INT_PTR, *PINT_PTR;
+typedef __w64 unsigned int UINT_PTR, *PUINT_PTR;
+
+typedef __w64 long LONG_PTR, *PLONG_PTR;
+typedef __w64 unsigned long ULONG_PTR, *PULONG_PTR;
+#endif
+
+typedef UINT_PTR WPARAM;
+typedef LONG_PTR LPARAM;
+typedef LONG_PTR LRESULT;
+#define LRESULT LONG_PTR
+typedef _Return_type_success_(return >= 0) long HRESULT;
+
+typedef ULONG_PTR SIZE_T, *PSIZE_T;
+typedef LONG_PTR SSIZE_T, *PSSIZE_T;
+
+typedef DWORD ACCESS_MASK;
+typedef ACCESS_MASK REGSAM;
+
+// As defined in guiddef.h.
+#ifndef _REFGUID_DEFINED
+#define _REFGUID_DEFINED
+#define REFGUID const GUID&
+#endif
+
+// Forward declare Windows compatible handles.
+
+#define CHROME_DECLARE_HANDLE(name) \
+ struct name##__; \
+ typedef struct name##__* name
+CHROME_DECLARE_HANDLE(HDESK);
+CHROME_DECLARE_HANDLE(HGLRC);
+CHROME_DECLARE_HANDLE(HICON);
+CHROME_DECLARE_HANDLE(HINSTANCE);
+CHROME_DECLARE_HANDLE(HKEY);
+CHROME_DECLARE_HANDLE(HKL);
+CHROME_DECLARE_HANDLE(HMENU);
+CHROME_DECLARE_HANDLE(HWINSTA);
+CHROME_DECLARE_HANDLE(HWND);
+#undef CHROME_DECLARE_HANDLE
+
+typedef LPVOID HINTERNET;
+typedef HINSTANCE HMODULE;
+typedef PVOID LSA_HANDLE;
+
+// Forward declare some Windows struct/typedef sets.
+
+typedef struct _OVERLAPPED OVERLAPPED;
+typedef struct tagMSG MSG, *PMSG, *NPMSG, *LPMSG;
+
+typedef struct _RTL_SRWLOCK RTL_SRWLOCK;
+typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
+
+typedef struct _GUID GUID;
+typedef GUID CLSID;
+
+typedef struct tagLOGFONTW LOGFONTW, *PLOGFONTW, *NPLOGFONTW, *LPLOGFONTW;
+typedef LOGFONTW LOGFONT;
+
+typedef struct _FILETIME FILETIME;
+
+typedef struct tagMENUITEMINFOW MENUITEMINFOW, MENUITEMINFO;
+
+typedef struct tagNMHDR NMHDR;
+
+typedef PVOID PSID;
+
+// Declare Chrome versions of some Windows structures. These are needed for
+// when we need a concrete type but don't want to pull in Windows.h. We can't
+// declare the Windows types so we declare our types and cast to the Windows
+// types in a few places.
+
+struct CHROME_SRWLOCK {
+ PVOID Ptr;
+};
+
+struct CHROME_CONDITION_VARIABLE {
+ PVOID Ptr;
+};
+
+// Define some commonly used Windows constants. Note that the layout of these
+// macros - including internal spacing - must be 100% consistent with windows.h.
+
+// clang-format off
+
+#ifndef INVALID_HANDLE_VALUE
+// Work around there being two slightly different definitions in the SDK.
+#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
+#endif
+#define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
+#define HTNOWHERE 0
+#define MAX_PATH 260
+#define CS_GLOBALCLASS 0x4000
+
+#define ERROR_SUCCESS 0L
+#define ERROR_FILE_NOT_FOUND 2L
+#define ERROR_ACCESS_DENIED 5L
+#define ERROR_INVALID_HANDLE 6L
+#define ERROR_SHARING_VIOLATION 32L
+#define ERROR_LOCK_VIOLATION 33L
+#define REG_BINARY ( 3ul )
+
+#define STATUS_PENDING ((DWORD )0x00000103L)
+#define STILL_ACTIVE STATUS_PENDING
+#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
+#define FAILED(hr) (((HRESULT)(hr)) < 0)
+
+#define HKEY_CLASSES_ROOT (( HKEY ) (ULONG_PTR)((LONG)0x80000000) )
+#define HKEY_LOCAL_MACHINE (( HKEY ) (ULONG_PTR)((LONG)0x80000002) )
+#define HKEY_CURRENT_USER (( HKEY ) (ULONG_PTR)((LONG)0x80000001) )
+#define KEY_QUERY_VALUE (0x0001)
+#define KEY_SET_VALUE (0x0002)
+#define KEY_CREATE_SUB_KEY (0x0004)
+#define KEY_ENUMERATE_SUB_KEYS (0x0008)
+#define KEY_NOTIFY (0x0010)
+#define KEY_CREATE_LINK (0x0020)
+#define KEY_WOW64_32KEY (0x0200)
+#define KEY_WOW64_64KEY (0x0100)
+#define KEY_WOW64_RES (0x0300)
+
+#define READ_CONTROL (0x00020000L)
+#define SYNCHRONIZE (0x00100000L)
+
+#define STANDARD_RIGHTS_READ (READ_CONTROL)
+#define STANDARD_RIGHTS_WRITE (READ_CONTROL)
+#define STANDARD_RIGHTS_ALL (0x001F0000L)
+
+#define KEY_READ ((STANDARD_RIGHTS_READ |\
+ KEY_QUERY_VALUE |\
+ KEY_ENUMERATE_SUB_KEYS |\
+ KEY_NOTIFY) \
+ & \
+ (~SYNCHRONIZE))
+
+
+#define KEY_WRITE ((STANDARD_RIGHTS_WRITE |\
+ KEY_SET_VALUE |\
+ KEY_CREATE_SUB_KEY) \
+ & \
+ (~SYNCHRONIZE))
+
+#define KEY_ALL_ACCESS ((STANDARD_RIGHTS_ALL |\
+ KEY_QUERY_VALUE |\
+ KEY_SET_VALUE |\
+ KEY_CREATE_SUB_KEY |\
+ KEY_ENUMERATE_SUB_KEYS |\
+ KEY_NOTIFY |\
+ KEY_CREATE_LINK) \
+ & \
+ (~SYNCHRONIZE))
+
+// clang-format on
+
+// Define some macros needed when prototyping Windows functions.
+
+#define DECLSPEC_IMPORT __declspec(dllimport)
+#define WINBASEAPI DECLSPEC_IMPORT
+#define WINUSERAPI DECLSPEC_IMPORT
+#define WINAPI __stdcall
+#define CALLBACK __stdcall
+
+// Needed for optimal lock performance.
+WINBASEAPI _Releases_exclusive_lock_(*SRWLock) VOID WINAPI
+ ReleaseSRWLockExclusive(_Inout_ PSRWLOCK SRWLock);
+
+// Needed to support protobuf's GetMessage macro magic.
+WINUSERAPI BOOL WINAPI GetMessageW(_Out_ LPMSG lpMsg,
+ _In_opt_ HWND hWnd,
+ _In_ UINT wMsgFilterMin,
+ _In_ UINT wMsgFilterMax);
+
+// Needed for thread_local_storage.h
+WINBASEAPI LPVOID WINAPI TlsGetValue(_In_ DWORD dwTlsIndex);
+
+// Needed for scoped_handle.h
+WINBASEAPI _Check_return_ _Post_equals_last_error_ DWORD WINAPI
+ GetLastError(VOID);
+
+WINBASEAPI VOID WINAPI SetLastError(_In_ DWORD dwErrCode);
+
+#ifdef __cplusplus
+}
+#endif
+
+// These macros are all defined by windows.h and are also used as the names of
+// functions in the Chromium code base. Add to this list as needed whenever
+// there is a Windows macro which causes a function call to be renamed. This
+// ensures that the same renaming will happen everywhere. Includes of this file
+// can be added wherever needed to ensure this consistent renaming.
+
+#define CopyFile CopyFileW
+#define CreateDirectory CreateDirectoryW
+#define CreateEvent CreateEventW
+#define CreateFile CreateFileW
+#define CreateService CreateServiceW
+#define DeleteFile DeleteFileW
+#define DispatchMessage DispatchMessageW
+#define DrawText DrawTextW
+#define FindFirstFile FindFirstFileW
+#define FindNextFile FindNextFileW
+#define GetComputerName GetComputerNameW
+#define GetCurrentDirectory GetCurrentDirectoryW
+#define GetCurrentTime() GetTickCount()
+#define GetFileAttributes GetFileAttributesW
+#define GetMessage GetMessageW
+#define GetUserName GetUserNameW
+#define LoadIcon LoadIconW
+#define LoadImage LoadImageW
+#define PostMessage PostMessageW
+#define RemoveDirectory RemoveDirectoryW
+#define ReplaceFile ReplaceFileW
+#define ReportEvent ReportEventW
+#define SendMessage SendMessageW
+#define SendMessageCallback SendMessageCallbackW
+#define SetCurrentDirectory SetCurrentDirectoryW
+#define StartService StartServiceW
+#define UpdateResource UpdateResourceW
+
+#endif // BASE_WIN_WINDOWS_TYPES_H
diff --git a/security/sandbox/chromium/base/win/windows_version.cc b/security/sandbox/chromium/base/win/windows_version.cc
new file mode 100644
index 0000000000..ef96f8796f
--- /dev/null
+++ b/security/sandbox/chromium/base/win/windows_version.cc
@@ -0,0 +1,313 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/windows_version.h"
+
+#include <windows.h>
+
+#include <memory>
+#include <tuple>
+#include <utility>
+
+#include "base/file_version_info_win.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+
+#if !defined(__clang__) && _MSC_FULL_VER < 191125507
+#error VS 2017 Update 3.2 or higher is required
+#endif
+
+#if !defined(NTDDI_WIN10_RS4)
+#error Windows 10.0.17134.0 SDK or higher required.
+#endif
+
+namespace base {
+namespace win {
+
+namespace {
+
+// The values under the CurrentVersion registry hive are mirrored under
+// the corresponding Wow6432 hive.
+constexpr wchar_t kRegKeyWindowsNTCurrentVersion[] =
+ L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
+
+// Returns the "UBR" (Windows 10 patch number) and "ReleaseId" (Windows 10
+// release number) from the registry. "UBR" is an undocumented value and will be
+// 0 if the value was not found. "ReleaseId" will be an empty string if the
+// value is not found.
+std::pair<int, std::string> GetVersionData() {
+ DWORD ubr = 0;
+ std::wstring release_id;
+ RegKey key;
+
+ if (key.Open(HKEY_LOCAL_MACHINE, kRegKeyWindowsNTCurrentVersion,
+ KEY_QUERY_VALUE) == ERROR_SUCCESS) {
+ key.ReadValueDW(L"UBR", &ubr);
+ key.ReadValue(L"ReleaseId", &release_id);
+ }
+
+ return std::make_pair(static_cast<int>(ubr), WideToUTF8(release_id));
+}
+
+const _SYSTEM_INFO& GetSystemInfoStorage() {
+ static const NoDestructor<_SYSTEM_INFO> system_info([] {
+ _SYSTEM_INFO info = {};
+ ::GetNativeSystemInfo(&info);
+ return info;
+ }());
+ return *system_info;
+}
+
+} // namespace
+
+// static
+OSInfo** OSInfo::GetInstanceStorage() {
+ // Note: we don't use the Singleton class because it depends on AtExitManager,
+ // and it's convenient for other modules to use this class without it.
+ static OSInfo* info = []() {
+ _OSVERSIONINFOEXW version_info = {sizeof(version_info)};
+ ::GetVersionEx(reinterpret_cast<_OSVERSIONINFOW*>(&version_info));
+
+ DWORD os_type = 0;
+ ::GetProductInfo(version_info.dwMajorVersion, version_info.dwMinorVersion,
+ 0, 0, &os_type);
+
+ return new OSInfo(version_info, GetSystemInfoStorage(), os_type);
+ }();
+
+ return &info;
+}
+
+// static
+OSInfo* OSInfo::GetInstance() {
+ return *GetInstanceStorage();
+}
+
+// static
+OSInfo::WindowsArchitecture OSInfo::GetArchitecture() {
+ switch (GetSystemInfoStorage().wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ return X86_ARCHITECTURE;
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ return X64_ARCHITECTURE;
+ case PROCESSOR_ARCHITECTURE_IA64:
+ return IA64_ARCHITECTURE;
+ case PROCESSOR_ARCHITECTURE_ARM64:
+ return ARM64_ARCHITECTURE;
+ default:
+ return OTHER_ARCHITECTURE;
+ }
+}
+
+OSInfo::OSInfo(const _OSVERSIONINFOEXW& version_info,
+ const _SYSTEM_INFO& system_info,
+ int os_type)
+ : version_(Version::PRE_XP),
+ wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
+ version_number_.major = version_info.dwMajorVersion;
+ version_number_.minor = version_info.dwMinorVersion;
+ version_number_.build = version_info.dwBuildNumber;
+ std::tie(version_number_.patch, release_id_) = GetVersionData();
+ version_ = MajorMinorBuildToVersion(
+ version_number_.major, version_number_.minor, version_number_.build);
+ service_pack_.major = version_info.wServicePackMajor;
+ service_pack_.minor = version_info.wServicePackMinor;
+ service_pack_str_ = WideToUTF8(version_info.szCSDVersion);
+
+ processors_ = system_info.dwNumberOfProcessors;
+ allocation_granularity_ = system_info.dwAllocationGranularity;
+
+ if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) {
+ // Only present on Vista+.
+ switch (os_type) {
+ case PRODUCT_CLUSTER_SERVER:
+ case PRODUCT_DATACENTER_SERVER:
+ case PRODUCT_DATACENTER_SERVER_CORE:
+ case PRODUCT_ENTERPRISE_SERVER:
+ case PRODUCT_ENTERPRISE_SERVER_CORE:
+ case PRODUCT_ENTERPRISE_SERVER_IA64:
+ case PRODUCT_SMALLBUSINESS_SERVER:
+ case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
+ case PRODUCT_STANDARD_SERVER:
+ case PRODUCT_STANDARD_SERVER_CORE:
+ case PRODUCT_WEB_SERVER:
+ version_type_ = SUITE_SERVER;
+ break;
+ case PRODUCT_PROFESSIONAL:
+ case PRODUCT_ULTIMATE:
+ version_type_ = SUITE_PROFESSIONAL;
+ break;
+ case PRODUCT_ENTERPRISE:
+ case PRODUCT_ENTERPRISE_E:
+ case PRODUCT_ENTERPRISE_EVALUATION:
+ case PRODUCT_ENTERPRISE_N:
+ case PRODUCT_ENTERPRISE_N_EVALUATION:
+ case PRODUCT_ENTERPRISE_S:
+ case PRODUCT_ENTERPRISE_S_EVALUATION:
+ case PRODUCT_ENTERPRISE_S_N:
+ case PRODUCT_ENTERPRISE_S_N_EVALUATION:
+ case PRODUCT_BUSINESS:
+ case PRODUCT_BUSINESS_N:
+ version_type_ = SUITE_ENTERPRISE;
+ break;
+ case PRODUCT_EDUCATION:
+ case PRODUCT_EDUCATION_N:
+ version_type_ = SUITE_EDUCATION;
+ break;
+ case PRODUCT_HOME_BASIC:
+ case PRODUCT_HOME_PREMIUM:
+ case PRODUCT_STARTER:
+ default:
+ version_type_ = SUITE_HOME;
+ break;
+ }
+ } else if (version_info.dwMajorVersion == 5 &&
+ version_info.dwMinorVersion == 2) {
+ if (version_info.wProductType == VER_NT_WORKSTATION &&
+ system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+ version_type_ = SUITE_PROFESSIONAL;
+ } else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER) {
+ version_type_ = SUITE_HOME;
+ } else {
+ version_type_ = SUITE_SERVER;
+ }
+ } else if (version_info.dwMajorVersion == 5 &&
+ version_info.dwMinorVersion == 1) {
+ if (version_info.wSuiteMask & VER_SUITE_PERSONAL)
+ version_type_ = SUITE_HOME;
+ else
+ version_type_ = SUITE_PROFESSIONAL;
+ } else {
+ // Windows is pre XP so we don't care but pick a safe default.
+ version_type_ = SUITE_HOME;
+ }
+}
+
+OSInfo::~OSInfo() = default;
+
+Version OSInfo::Kernel32Version() const {
+ static const Version kernel32_version =
+ MajorMinorBuildToVersion(Kernel32BaseVersion().components()[0],
+ Kernel32BaseVersion().components()[1],
+ Kernel32BaseVersion().components()[2]);
+ return kernel32_version;
+}
+
+Version OSInfo::UcrtVersion() const {
+ auto ucrt_version_info = FileVersionInfoWin::CreateFileVersionInfoWin(
+ FilePath(FILE_PATH_LITERAL("ucrtbase.dll")));
+ if (ucrt_version_info) {
+ auto ucrt_components = ucrt_version_info->GetFileVersion().components();
+ if (ucrt_components.size() == 4) {
+ return MajorMinorBuildToVersion(ucrt_components[0], ucrt_components[1],
+ ucrt_components[2]);
+ }
+ }
+ return Version();
+}
+
+// Retrieve a version from kernel32. This is useful because when running in
+// compatibility mode for a down-level version of the OS, the file version of
+// kernel32 will still be the "real" version.
+base::Version OSInfo::Kernel32BaseVersion() const {
+ static const NoDestructor<base::Version> version([] {
+ std::unique_ptr<FileVersionInfoWin> file_version_info =
+ FileVersionInfoWin::CreateFileVersionInfoWin(
+ FilePath(FILE_PATH_LITERAL("kernel32.dll")));
+ if (!file_version_info) {
+ // crbug.com/912061: on some systems it seems kernel32.dll might be
+ // corrupted or not in a state to get version info. In this case try
+ // kernelbase.dll as a fallback.
+ file_version_info = FileVersionInfoWin::CreateFileVersionInfoWin(
+ FilePath(FILE_PATH_LITERAL("kernelbase.dll")));
+ }
+ CHECK(file_version_info);
+ return file_version_info->GetFileVersion();
+ }());
+ return *version;
+}
+
+std::string OSInfo::processor_model_name() {
+ if (processor_model_name_.empty()) {
+ const wchar_t kProcessorNameString[] =
+ L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
+ RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ);
+ std::wstring value;
+ key.ReadValue(L"ProcessorNameString", &value);
+ processor_model_name_ = WideToUTF8(value);
+ }
+ return processor_model_name_;
+}
+
+// static
+OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) {
+ BOOL is_wow64 = FALSE;
+ if (!::IsWow64Process(process_handle, &is_wow64))
+ return WOW64_UNKNOWN;
+ return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
+}
+
+// With the exception of Server 2003, server variants are treated the same as
+// the corresponding workstation release.
+// static
+Version OSInfo::MajorMinorBuildToVersion(int major, int minor, int build) {
+ if (major == 10) {
+ if (build >= 19041)
+ return Version::WIN10_20H1;
+ if (build >= 18362)
+ return Version::WIN10_19H1;
+ if (build >= 17763)
+ return Version::WIN10_RS5;
+ if (build >= 17134)
+ return Version::WIN10_RS4;
+ if (build >= 16299)
+ return Version::WIN10_RS3;
+ if (build >= 15063)
+ return Version::WIN10_RS2;
+ if (build >= 14393)
+ return Version::WIN10_RS1;
+ if (build >= 10586)
+ return Version::WIN10_TH2;
+ return Version::WIN10;
+ }
+
+ if (major > 6) {
+ // Hitting this likely means that it's time for a >10 block above.
+ NOTREACHED() << major << "." << minor << "." << build;
+ return Version::WIN_LAST;
+ }
+
+ if (major == 6) {
+ switch (minor) {
+ case 0:
+ return Version::VISTA;
+ case 1:
+ return Version::WIN7;
+ case 2:
+ return Version::WIN8;
+ default:
+ DCHECK_EQ(minor, 3);
+ return Version::WIN8_1;
+ }
+ }
+
+ if (major == 5 && minor != 0) {
+ // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
+ return minor == 1 ? Version::XP : Version::SERVER_2003;
+ }
+
+ // Win 2000 or older.
+ return Version::PRE_XP;
+}
+
+Version GetVersion() {
+ return OSInfo::GetInstance()->version();
+}
+
+} // namespace win
+} // namespace base
diff --git a/security/sandbox/chromium/base/win/windows_version.h b/security/sandbox/chromium/base/win/windows_version.h
new file mode 100644
index 0000000000..08d6e274ef
--- /dev/null
+++ b/security/sandbox/chromium/base/win/windows_version.h
@@ -0,0 +1,187 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_WINDOWS_VERSION_H_
+#define BASE_WIN_WINDOWS_VERSION_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/version.h"
+
+using HANDLE = void*;
+struct _OSVERSIONINFOEXW;
+struct _SYSTEM_INFO;
+
+namespace base {
+namespace test {
+class ScopedOSInfoOverride;
+} // namespace test
+} // namespace base
+
+namespace base {
+namespace win {
+
+// The running version of Windows. This is declared outside OSInfo for
+// syntactic sugar reasons; see the declaration of GetVersion() below.
+// NOTE: Keep these in order so callers can do things like
+// "if (base::win::GetVersion() >= base::win::Version::VISTA) ...".
+//
+// This enum is used in metrics histograms, so they shouldn't be reordered or
+// removed. New values can be added before Version::WIN_LAST.
+enum class Version {
+ PRE_XP = 0, // Not supported.
+ XP = 1,
+ SERVER_2003 = 2, // Also includes XP Pro x64 and Server 2003 R2.
+ VISTA = 3, // Also includes Windows Server 2008.
+ WIN7 = 4, // Also includes Windows Server 2008 R2.
+ WIN8 = 5, // Also includes Windows Server 2012.
+ WIN8_1 = 6, // Also includes Windows Server 2012 R2.
+ WIN10 = 7, // Threshold 1: Version 1507, Build 10240.
+ WIN10_TH2 = 8, // Threshold 2: Version 1511, Build 10586.
+ WIN10_RS1 = 9, // Redstone 1: Version 1607, Build 14393.
+ WIN10_RS2 = 10, // Redstone 2: Version 1703, Build 15063.
+ WIN10_RS3 = 11, // Redstone 3: Version 1709, Build 16299.
+ WIN10_RS4 = 12, // Redstone 4: Version 1803, Build 17134.
+ WIN10_RS5 = 13, // Redstone 5: Version 1809, Build 17763.
+ WIN10_19H1 = 14, // 19H1: Version 1903, Build 18362.
+ WIN10_20H1 = 15, // 20H1: Version 2004, Build 19041.
+ // On edit, update tools\metrics\histograms\enums.xml "WindowsVersion" and
+ // "GpuBlacklistFeatureTestResultsWindows2".
+ WIN_LAST, // Indicates error condition.
+};
+
+// A rough bucketing of the available types of versions of Windows. This is used
+// to distinguish enterprise enabled versions from home versions and potentially
+// server versions. Keep these values in the same order, since they are used as
+// is for metrics histogram ids.
+enum VersionType {
+ SUITE_HOME = 0,
+ SUITE_PROFESSIONAL,
+ SUITE_SERVER,
+ SUITE_ENTERPRISE,
+ SUITE_EDUCATION,
+ SUITE_LAST,
+};
+
+// A singleton that can be used to query various pieces of information about the
+// OS and process state. Note that this doesn't use the base Singleton class, so
+// it can be used without an AtExitManager.
+class BASE_EXPORT OSInfo {
+ public:
+ struct VersionNumber {
+ int major;
+ int minor;
+ int build;
+ int patch;
+ };
+
+ struct ServicePack {
+ int major;
+ int minor;
+ };
+
+ // The processor architecture this copy of Windows natively uses. For
+ // example, given an x64-capable processor, we have three possibilities:
+ // 32-bit Chrome running on 32-bit Windows: X86_ARCHITECTURE
+ // 32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE
+ // 64-bit Chrome running on 64-bit Windows: X64_ARCHITECTURE
+ enum WindowsArchitecture {
+ X86_ARCHITECTURE,
+ X64_ARCHITECTURE,
+ IA64_ARCHITECTURE,
+ ARM64_ARCHITECTURE,
+ OTHER_ARCHITECTURE,
+ };
+
+ // Whether a process is running under WOW64 (the wrapper that allows 32-bit
+ // processes to run on 64-bit versions of Windows). This will return
+ // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
+ // Chrome on 64-bit Windows". WOW64_UNKNOWN means "an error occurred", e.g.
+ // the process does not have sufficient access rights to determine this.
+ enum WOW64Status {
+ WOW64_DISABLED,
+ WOW64_ENABLED,
+ WOW64_UNKNOWN,
+ };
+
+ static OSInfo* GetInstance();
+
+ // Separate from the rest of OSInfo so it can be used during early process
+ // initialization.
+ static WindowsArchitecture GetArchitecture();
+
+ // Like wow64_status(), but for the supplied handle instead of the current
+ // process. This doesn't touch member state, so you can bypass the singleton.
+ static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle);
+
+ const Version& version() const { return version_; }
+ Version Kernel32Version() const;
+ Version UcrtVersion() const;
+ base::Version Kernel32BaseVersion() const;
+ // The next two functions return arrays of values, [major, minor(, build)].
+ const VersionNumber& version_number() const { return version_number_; }
+ const VersionType& version_type() const { return version_type_; }
+ const ServicePack& service_pack() const { return service_pack_; }
+ const std::string& service_pack_str() const { return service_pack_str_; }
+ const int& processors() const { return processors_; }
+ const size_t& allocation_granularity() const {
+ return allocation_granularity_;
+ }
+ const WOW64Status& wow64_status() const { return wow64_status_; }
+ std::string processor_model_name();
+ const std::string& release_id() const { return release_id_; }
+
+ private:
+ friend class base::test::ScopedOSInfoOverride;
+ FRIEND_TEST_ALL_PREFIXES(OSInfo, MajorMinorBuildToVersion);
+ static OSInfo** GetInstanceStorage();
+
+ OSInfo(const _OSVERSIONINFOEXW& version_info,
+ const _SYSTEM_INFO& system_info,
+ int os_type);
+ ~OSInfo();
+
+ // Returns a Version value for a given OS version tuple.
+ static Version MajorMinorBuildToVersion(int major, int minor, int build);
+
+ Version version_;
+ VersionNumber version_number_;
+ VersionType version_type_;
+ ServicePack service_pack_;
+
+ // Represents the version of the OS associated to a release of
+ // Windows 10. Each version may have different releases (such as patch
+ // updates). This is the identifier of the release.
+ // Example:
+ // Windows 10 Version 1809 (OS build 17763) has multiple releases
+ // (i.e. build 17763.1, build 17763.195, build 17763.379, ...).
+ // See https://docs.microsoft.com/en-us/windows/windows-10/release-information
+ // for more information.
+ std::string release_id_;
+
+ // A string, such as "Service Pack 3", that indicates the latest Service Pack
+ // installed on the system. If no Service Pack has been installed, the string
+ // is empty.
+ std::string service_pack_str_;
+ int processors_;
+ size_t allocation_granularity_;
+ WOW64Status wow64_status_;
+ std::string processor_model_name_;
+
+ DISALLOW_COPY_AND_ASSIGN(OSInfo);
+};
+
+// Because this is by far the most commonly-requested value from the above
+// singleton, we add a global-scope accessor here as syntactic sugar.
+BASE_EXPORT Version GetVersion();
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_WINDOWS_VERSION_H_
diff --git a/security/sandbox/chromium/build/build_config.h b/security/sandbox/chromium/build/build_config.h
new file mode 100644
index 0000000000..b1e05cdf9f
--- /dev/null
+++ b/security/sandbox/chromium/build/build_config.h
@@ -0,0 +1,215 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file adds defines about the platform we're currently building on.
+// Operating System:
+// OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX) /
+// OS_NACL (NACL_SFI or NACL_NONSFI) / OS_NACL_SFI / OS_NACL_NONSFI
+// OS_CHROMEOS is set by the build system
+// Compiler:
+// COMPILER_MSVC / COMPILER_GCC
+// Processor:
+// ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64)
+// ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
+
+#ifndef BUILD_BUILD_CONFIG_H_
+#define BUILD_BUILD_CONFIG_H_
+
+// A set of macros to use for platform detection.
+#if defined(__native_client__)
+// __native_client__ must be first, so that other OS_ defines are not set.
+#define OS_NACL 1
+// OS_NACL comes in two sandboxing technology flavors, SFI or Non-SFI.
+// PNaCl toolchain defines __native_client_nonsfi__ macro in Non-SFI build
+// mode, while it does not in SFI build mode.
+#if defined(__native_client_nonsfi__)
+#define OS_NACL_NONSFI
+#else
+#define OS_NACL_SFI
+#endif
+#elif defined(ANDROID)
+#define OS_ANDROID 1
+#elif defined(__APPLE__)
+// only include TargetConditions after testing ANDROID as some android builds
+// on mac don't have this header available and it's not needed unless the target
+// is really mac/ios.
+#include <TargetConditionals.h>
+#define OS_MACOSX 1
+#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#define OS_IOS 1
+#endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#elif defined(__linux__)
+#define OS_LINUX 1
+// include a system header to pull in features.h for glibc/uclibc macros.
+#include <unistd.h>
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+// we really are using glibc, not uClibc pretending to be glibc
+#define LIBC_GLIBC 1
+#endif
+#elif defined(_WIN32)
+#define OS_WIN 1
+#elif defined(__Fuchsia__)
+#define OS_FUCHSIA 1
+#elif defined(__FreeBSD__)
+#define OS_FREEBSD 1
+#elif defined(__NetBSD__)
+#define OS_NETBSD 1
+#elif defined(__OpenBSD__)
+#define OS_OPENBSD 1
+#elif defined(__sun)
+#define OS_SOLARIS 1
+#elif defined(__QNXNTO__)
+#define OS_QNX 1
+#elif defined(_AIX)
+#define OS_AIX 1
+#elif defined(__asmjs__) || defined(__wasm__)
+#define OS_ASMJS
+#else
+#error Please add support for your platform in build/build_config.h
+#endif
+// NOTE: Adding a new port? Please follow
+// https://chromium.googlesource.com/chromium/src/+/master/docs/new_port_policy.md
+
+// For access to standard BSD features, use OS_BSD instead of a
+// more specific macro.
+#if defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD)
+#define OS_BSD 1
+#endif
+
+// For access to standard POSIXish features, use OS_POSIX instead of a
+// more specific macro.
+#if defined(OS_AIX) || defined(OS_ANDROID) || defined(OS_ASMJS) || \
+ defined(OS_FREEBSD) || defined(OS_LINUX) || defined(OS_MACOSX) || \
+ defined(OS_NACL) || defined(OS_NETBSD) || defined(OS_OPENBSD) || \
+ defined(OS_QNX) || defined(OS_SOLARIS)
+#define OS_POSIX 1
+#endif
+
+// Compiler detection.
+#if defined(__GNUC__)
+#define COMPILER_GCC 1
+#elif defined(_MSC_VER)
+#define COMPILER_MSVC 1
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+// Processor architecture detection. For more info on what's defined, see:
+// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+// http://www.agner.org/optimize/calling_conventions.pdf
+// or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86_64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__s390x__)
+#define ARCH_CPU_S390_FAMILY 1
+#define ARCH_CPU_S390X 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__s390__)
+#define ARCH_CPU_S390_FAMILY 1
+#define ARCH_CPU_S390 1
+#define ARCH_CPU_31_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif (defined(__PPC64__) || defined(__PPC__)) && defined(__BIG_ENDIAN__)
+#define ARCH_CPU_PPC64_FAMILY 1
+#define ARCH_CPU_PPC64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__PPC64__)
+#define ARCH_CPU_PPC64_FAMILY 1
+#define ARCH_CPU_PPC64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__ARMEL__)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARMEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__aarch64__) || defined(_M_ARM64)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARM64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__pnacl__) || defined(__asmjs__) || defined(__wasm__)
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__MIPSEL__)
+#if defined(__LP64__)
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPS64EL 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#else
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPSEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#endif
+#elif defined(__MIPSEB__)
+#if defined(__LP64__)
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPS64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#else
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPS 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#endif
+#elif defined(__riscv) && __riscv_xlen == 64
+#define ARCH_CPU_RISCV64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__loongarch__)
+#define ARCH_CPU_LOONGARCH_FAMILY 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#if __loongarch_grlen == 64
+#define ARCH_CPU_LOONGARCH64 1
+#define ARCH_CPU_64_BITS 1
+#else
+#define ARCH_CPU_LOONGARCH32 1
+#define ARCH_CPU_32_BITS 1
+#endif
+#else
+#error Please add support for your architecture in build/build_config.h
+#endif
+
+// Type detection for wchar_t.
+#if defined(OS_WIN)
+#define WCHAR_T_IS_UTF16
+#elif defined(OS_FUCHSIA)
+#define WCHAR_T_IS_UTF32
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && defined(__WCHAR_MAX__) && \
+ (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
+#define WCHAR_T_IS_UTF32
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && defined(__WCHAR_MAX__) && \
+ (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
+// On Posix, we'll detect short wchar_t, but projects aren't guaranteed to
+// compile in this mode (in particular, Chrome doesn't). This is intended for
+// other projects using base who manage their own dependencies and make sure
+// short wchar works for them.
+#define WCHAR_T_IS_UTF16
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+#if defined(OS_ANDROID)
+// The compiler thinks std::string::const_iterator and "const char*" are
+// equivalent types.
+#define STD_STRING_ITERATOR_IS_CHAR_POINTER
+// The compiler thinks base::string16::const_iterator and "char16*" are
+// equivalent types.
+#define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER
+#endif
+
+#endif // BUILD_BUILD_CONFIG_H_
diff --git a/security/sandbox/chromium/build/buildflag.h b/security/sandbox/chromium/build/buildflag.h
new file mode 100644
index 0000000000..5776a754c4
--- /dev/null
+++ b/security/sandbox/chromium/build/buildflag.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BUILD_BUILDFLAG_H_
+#define BUILD_BUILDFLAG_H_
+
+// These macros un-mangle the names of the build flags in a way that looks
+// natural, and gives errors if the flag is not defined. Normally in the
+// preprocessor it's easy to make mistakes that interpret "you haven't done
+// the setup to know what the flag is" as "flag is off". Normally you would
+// include the generated header rather than include this file directly.
+//
+// This is for use with generated headers. See build/buildflag_header.gni.
+
+// This dance of two macros does a concatenation of two preprocessor args using
+// ## doubly indirectly because using ## directly prevents macros in that
+// parameter from being expanded.
+#define BUILDFLAG_CAT_INDIRECT(a, b) a ## b
+#define BUILDFLAG_CAT(a, b) BUILDFLAG_CAT_INDIRECT(a, b)
+
+// Accessor for build flags.
+//
+// To test for a value, if the build file specifies:
+//
+// ENABLE_FOO=true
+//
+// Then you would check at build-time in source code with:
+//
+// #include "foo_flags.h" // The header the build file specified.
+//
+// #if BUILDFLAG(ENABLE_FOO)
+// ...
+// #endif
+//
+// There will no #define called ENABLE_FOO so if you accidentally test for
+// whether that is defined, it will always be negative. You can also use
+// the value in expressions:
+//
+// const char kSpamServerName[] = BUILDFLAG(SPAM_SERVER_NAME);
+//
+// Because the flag is accessed as a preprocessor macro with (), an error
+// will be thrown if the proper header defining the internal flag value has
+// not been included.
+#define BUILDFLAG(flag) (BUILDFLAG_CAT(BUILDFLAG_INTERNAL_, flag)())
+
+#endif // BUILD_BUILDFLAG_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
new file mode 100644
index 0000000000..fed6368db6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.cc
@@ -0,0 +1,343 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/errorcode.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+namespace {
+
+class ReturnResultExprImpl : public internal::ResultExprImpl {
+ public:
+ explicit ReturnResultExprImpl(uint32_t ret) : ret_(ret) {}
+ ~ReturnResultExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc) const override {
+ return pc->Return(ret_);
+ }
+
+ bool IsAllow() const override { return IsAction(SECCOMP_RET_ALLOW); }
+
+ bool IsDeny() const override {
+ return IsAction(SECCOMP_RET_ERRNO) || IsAction(SECCOMP_RET_KILL);
+ }
+
+ private:
+ bool IsAction(uint32_t action) const {
+ return (ret_ & SECCOMP_RET_ACTION) == action;
+ }
+
+ uint32_t ret_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReturnResultExprImpl);
+};
+
+class TrapResultExprImpl : public internal::ResultExprImpl {
+ public:
+ TrapResultExprImpl(TrapRegistry::TrapFnc func, const void* arg, bool safe)
+ : func_(func), arg_(arg), safe_(safe) {
+ DCHECK(func_);
+ }
+ ~TrapResultExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc) const override {
+ return pc->Trap(func_, arg_, safe_);
+ }
+
+ bool HasUnsafeTraps() const override { return safe_ == false; }
+
+ bool IsDeny() const override { return true; }
+
+ private:
+ TrapRegistry::TrapFnc func_;
+ const void* arg_;
+ bool safe_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrapResultExprImpl);
+};
+
+class IfThenResultExprImpl : public internal::ResultExprImpl {
+ public:
+ IfThenResultExprImpl(BoolExpr cond,
+ ResultExpr then_result,
+ ResultExpr else_result)
+ : cond_(std::move(cond)),
+ then_result_(std::move(then_result)),
+ else_result_(std::move(else_result)) {}
+ ~IfThenResultExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc) const override {
+ // We compile the "then" and "else" expressions in separate statements so
+ // they have a defined sequencing. See https://crbug.com/529480.
+ CodeGen::Node then_node = then_result_->Compile(pc);
+ CodeGen::Node else_node = else_result_->Compile(pc);
+ return cond_->Compile(pc, then_node, else_node);
+ }
+
+ bool HasUnsafeTraps() const override {
+ return then_result_->HasUnsafeTraps() || else_result_->HasUnsafeTraps();
+ }
+
+ private:
+ BoolExpr cond_;
+ ResultExpr then_result_;
+ ResultExpr else_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(IfThenResultExprImpl);
+};
+
+class ConstBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ ConstBoolExprImpl(bool value) : value_(value) {}
+ ~ConstBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return value_ ? then_node : else_node;
+ }
+
+ private:
+ bool value_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConstBoolExprImpl);
+};
+
+class MaskedEqualBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ MaskedEqualBoolExprImpl(int argno,
+ size_t width,
+ uint64_t mask,
+ uint64_t value)
+ : argno_(argno), width_(width), mask_(mask), value_(value) {}
+ ~MaskedEqualBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return pc->MaskedEqual(argno_, width_, mask_, value_, then_node, else_node);
+ }
+
+ private:
+ int argno_;
+ size_t width_;
+ uint64_t mask_;
+ uint64_t value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MaskedEqualBoolExprImpl);
+};
+
+class NegateBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ explicit NegateBoolExprImpl(BoolExpr cond) : cond_(std::move(cond)) {}
+ ~NegateBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return cond_->Compile(pc, else_node, then_node);
+ }
+
+ private:
+ BoolExpr cond_;
+
+ DISALLOW_COPY_AND_ASSIGN(NegateBoolExprImpl);
+};
+
+class AndBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ AndBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
+ : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+ ~AndBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return lhs_->Compile(pc, rhs_->Compile(pc, then_node, else_node),
+ else_node);
+ }
+
+ private:
+ BoolExpr lhs_;
+ BoolExpr rhs_;
+
+ DISALLOW_COPY_AND_ASSIGN(AndBoolExprImpl);
+};
+
+class OrBoolExprImpl : public internal::BoolExprImpl {
+ public:
+ OrBoolExprImpl(BoolExpr lhs, BoolExpr rhs)
+ : lhs_(std::move(lhs)), rhs_(std::move(rhs)) {}
+ ~OrBoolExprImpl() override {}
+
+ CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const override {
+ return lhs_->Compile(pc, then_node,
+ rhs_->Compile(pc, then_node, else_node));
+ }
+
+ private:
+ BoolExpr lhs_;
+ BoolExpr rhs_;
+
+ DISALLOW_COPY_AND_ASSIGN(OrBoolExprImpl);
+};
+
+} // namespace
+
+namespace internal {
+
+bool ResultExprImpl::HasUnsafeTraps() const {
+ return false;
+}
+
+bool ResultExprImpl::IsAllow() const {
+ return false;
+}
+
+bool ResultExprImpl::IsDeny() const {
+ return false;
+}
+
+uint64_t DefaultMask(size_t size) {
+ switch (size) {
+ case 4:
+ return std::numeric_limits<uint32_t>::max();
+ case 8:
+ return std::numeric_limits<uint64_t>::max();
+ default:
+ CHECK(false) << "Unimplemented DefaultMask case";
+ return 0;
+ }
+}
+
+BoolExpr ArgEq(int num, size_t size, uint64_t mask, uint64_t val) {
+ // If this is changed, update Arg<T>::EqualTo's static_cast rules
+ // accordingly.
+ CHECK(size == 4 || size == 8);
+
+ return std::make_shared<MaskedEqualBoolExprImpl>(num, size, mask, val);
+}
+
+} // namespace internal
+
+ResultExpr Allow() {
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ALLOW);
+}
+
+ResultExpr Error(int err) {
+ CHECK(err >= ErrorCode::ERR_MIN_ERRNO && err <= ErrorCode::ERR_MAX_ERRNO);
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_ERRNO + err);
+}
+
+ResultExpr Kill() {
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_KILL);
+}
+
+ResultExpr Trace(uint16_t aux) {
+ return std::make_shared<ReturnResultExprImpl>(SECCOMP_RET_TRACE + aux);
+}
+
+ResultExpr Trap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+ return std::make_shared<TrapResultExprImpl>(trap_func, aux, true /* safe */);
+}
+
+ResultExpr UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux) {
+ return std::make_shared<TrapResultExprImpl>(trap_func, aux,
+ false /* unsafe */);
+}
+
+BoolExpr BoolConst(bool value) {
+ return std::make_shared<ConstBoolExprImpl>(value);
+}
+
+BoolExpr Not(BoolExpr cond) {
+ return std::make_shared<NegateBoolExprImpl>(std::move(cond));
+}
+
+BoolExpr AllOf() {
+ return BoolConst(true);
+}
+
+BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs) {
+ return std::make_shared<AndBoolExprImpl>(std::move(lhs), std::move(rhs));
+}
+
+BoolExpr AnyOf() {
+ return BoolConst(false);
+}
+
+BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs) {
+ return std::make_shared<OrBoolExprImpl>(std::move(lhs), std::move(rhs));
+}
+
+Elser If(BoolExpr cond, ResultExpr then_result) {
+ return Elser(nullptr).ElseIf(std::move(cond), std::move(then_result));
+}
+
+Elser::Elser(cons::List<Clause> clause_list) : clause_list_(clause_list) {
+}
+
+Elser::Elser(const Elser& elser) : clause_list_(elser.clause_list_) {
+}
+
+Elser::~Elser() {
+}
+
+Elser Elser::ElseIf(BoolExpr cond, ResultExpr then_result) const {
+ return Elser(Cons(std::make_pair(std::move(cond), std::move(then_result)),
+ clause_list_));
+}
+
+ResultExpr Elser::Else(ResultExpr else_result) const {
+ // We finally have the default result expression for this
+ // if/then/else sequence. Also, we've already accumulated all
+ // if/then pairs into a list of reverse order (i.e., lower priority
+ // conditions are listed before higher priority ones). E.g., an
+ // expression like
+ //
+ // If(b1, e1).ElseIf(b2, e2).ElseIf(b3, e3).Else(e4)
+ //
+ // will have built up a list like
+ //
+ // [(b3, e3), (b2, e2), (b1, e1)].
+ //
+ // Now that we have e4, we can walk the list and create a ResultExpr
+ // tree like:
+ //
+ // expr = e4
+ // expr = (b3 ? e3 : expr) = (b3 ? e3 : e4)
+ // expr = (b2 ? e2 : expr) = (b2 ? e2 : (b3 ? e3 : e4))
+ // expr = (b1 ? e1 : expr) = (b1 ? e1 : (b2 ? e2 : (b3 ? e3 : e4)))
+ //
+ // and end up with an appropriately chained tree.
+
+ ResultExpr expr = std::move(else_result);
+ for (const Clause& clause : clause_list_) {
+ expr = std::make_shared<IfThenResultExprImpl>(clause.first, clause.second,
+ std::move(expr));
+ }
+ return expr;
+}
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+namespace std {
+template class shared_ptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
+template class shared_ptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
+} // namespace std
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h
new file mode 100644
index 0000000000..555d820e01
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl.h
@@ -0,0 +1,338 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/cons.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/sandbox_export.h"
+
+// The sandbox::bpf_dsl namespace provides a domain-specific language
+// to make writing BPF policies more expressive. In general, the
+// object types all have value semantics (i.e., they can be copied
+// around, returned from or passed to function calls, etc. without any
+// surprising side effects), though not all support assignment.
+//
+// An idiomatic and demonstrative (albeit silly) example of this API
+// would be:
+//
+// #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+//
+// namespace dsl = sandbox::bpf_dsl;
+//
+// class SillyPolicy : public dsl::Policy {
+// public:
+// SillyPolicy() = default;
+// SillyPolicy(const SillyPolicy&) = delete;
+// SillyPolicy& operator=(const SillyPolicy&) = delete;
+// ~SillyPolicy() override = default;
+//
+// dsl::ResultExpr EvaluateSyscall(int sysno) const override {
+// if (sysno != __NR_fcntl)
+// return dsl::Allow();
+// dsl::Arg<int> fd(0), cmd(1);
+// dsl::Arg<unsigned long> flags(2);
+// constexpr uint64_t kGoodFlags = O_ACCMODE | O_NONBLOCK;
+// return dsl::If(dsl::AllOf(fd == 0,
+// cmd == F_SETFL,
+// (flags & ~kGoodFlags) == 0),
+// dsl::Allow())
+// .dsl::ElseIf(dsl::AnyOf(cmd == F_DUPFD, cmd == F_DUPFD_CLOEXEC),
+// dsl::Error(EMFILE))
+// .dsl::Else(dsl::Trap(SetFlagHandler, nullptr));
+// }
+// };
+//
+// More generally, the DSL currently supports the following grammar:
+//
+// result = Allow() | Error(errno) | Kill() | Trace(aux)
+// | Trap(trap_func, aux) | UnsafeTrap(trap_func, aux)
+// | If(bool, result)[.ElseIf(bool, result)].Else(result)
+// | Switch(arg)[.Case(val, result)].Default(result)
+// bool = BoolConst(boolean) | Not(bool) | AllOf(bool...) | AnyOf(bool...)
+// | arg == val | arg != val
+// arg = Arg<T>(num) | arg & mask
+//
+// The semantics of each function and operator are intended to be
+// intuitive, but are described in more detail below.
+//
+// (Credit to Sean Parent's "Inheritance is the Base Class of Evil"
+// talk at Going Native 2013 for promoting value semantics via shared
+// pointers to immutable state.)
+
+namespace sandbox {
+namespace bpf_dsl {
+
+template <typename T>
+class Caser;
+
+class Elser;
+
+// ResultExpr is an opaque reference to an immutable result expression tree.
+using ResultExpr = std::shared_ptr<const internal::ResultExprImpl>;
+
+// BoolExpr is an opaque reference to an immutable boolean expression tree.
+using BoolExpr = std::shared_ptr<const internal::BoolExprImpl>;
+
+// Allow specifies a result that the system call should be allowed to
+// execute normally.
+SANDBOX_EXPORT ResultExpr Allow();
+
+// Error specifies a result that the system call should fail with
+// error number |err|. As a special case, Error(0) will result in the
+// system call appearing to have succeeded, but without having any
+// side effects.
+SANDBOX_EXPORT ResultExpr Error(int err);
+
+// Kill specifies a result to kill the process (task) immediately.
+SANDBOX_EXPORT ResultExpr Kill();
+
+// Trace specifies a result to notify a tracing process via the
+// PTRACE_EVENT_SECCOMP event and allow it to change or skip the system call.
+// The value of |aux| will be available to the tracer via PTRACE_GETEVENTMSG.
+SANDBOX_EXPORT ResultExpr Trace(uint16_t aux);
+
+// Trap specifies a result that the system call should be handled by
+// trapping back into userspace and invoking |trap_func|, passing
+// |aux| as the second parameter.
+SANDBOX_EXPORT ResultExpr
+ Trap(TrapRegistry::TrapFnc trap_func, const void* aux);
+
+// UnsafeTrap is like Trap, except the policy is marked as "unsafe"
+// and allowed to use SandboxSyscall to invoke any system call.
+//
+// NOTE: This feature, by definition, disables all security features of
+// the sandbox. It should never be used in production, but it can be
+// very useful to diagnose code that is incompatible with the sandbox.
+// If even a single system call returns "UnsafeTrap", the security of
+// entire sandbox should be considered compromised.
+SANDBOX_EXPORT ResultExpr
+ UnsafeTrap(TrapRegistry::TrapFnc trap_func, const void* aux);
+
+// BoolConst converts a bool value into a BoolExpr.
+SANDBOX_EXPORT BoolExpr BoolConst(bool value);
+
+// Not returns a BoolExpr representing the logical negation of |cond|.
+SANDBOX_EXPORT BoolExpr Not(BoolExpr cond);
+
+// AllOf returns a BoolExpr representing the logical conjunction ("and")
+// of zero or more BoolExprs.
+SANDBOX_EXPORT BoolExpr AllOf();
+SANDBOX_EXPORT BoolExpr AllOf(BoolExpr lhs, BoolExpr rhs);
+template <typename... Rest>
+SANDBOX_EXPORT BoolExpr AllOf(BoolExpr first, Rest&&... rest);
+
+// AnyOf returns a BoolExpr representing the logical disjunction ("or")
+// of zero or more BoolExprs.
+SANDBOX_EXPORT BoolExpr AnyOf();
+SANDBOX_EXPORT BoolExpr AnyOf(BoolExpr lhs, BoolExpr rhs);
+template <typename... Rest>
+SANDBOX_EXPORT BoolExpr AnyOf(BoolExpr first, Rest&&... rest);
+
+template <typename T>
+class SANDBOX_EXPORT Arg {
+ public:
+ // Initializes the Arg to represent the |num|th system call
+ // argument (indexed from 0), which is of type |T|.
+ explicit Arg(int num);
+
+ Arg(const Arg& arg) : num_(arg.num_), mask_(arg.mask_) {}
+
+ // Returns an Arg representing the current argument, but after
+ // bitwise-and'ing it with |rhs|.
+ friend Arg operator&(const Arg& lhs, uint64_t rhs) {
+ return Arg(lhs.num_, lhs.mask_ & rhs);
+ }
+
+ // Returns a boolean expression comparing whether the system call argument
+ // (after applying any bitmasks, if appropriate) equals |rhs|.
+ friend BoolExpr operator==(const Arg& lhs, T rhs) { return lhs.EqualTo(rhs); }
+
+ // Returns a boolean expression comparing whether the system call argument
+ // (after applying any bitmasks, if appropriate) does not equal |rhs|.
+ friend BoolExpr operator!=(const Arg& lhs, T rhs) { return Not(lhs == rhs); }
+
+ private:
+ Arg(int num, uint64_t mask) : num_(num), mask_(mask) {}
+
+ BoolExpr EqualTo(T val) const;
+
+ int num_;
+ uint64_t mask_;
+
+ DISALLOW_ASSIGN(Arg);
+};
+
+// If begins a conditional result expression predicated on the
+// specified boolean expression.
+SANDBOX_EXPORT Elser If(BoolExpr cond, ResultExpr then_result);
+
+class SANDBOX_EXPORT Elser {
+ public:
+ Elser(const Elser& elser);
+ ~Elser();
+
+ // ElseIf extends the conditional result expression with another
+ // "if then" clause, predicated on the specified boolean expression.
+ Elser ElseIf(BoolExpr cond, ResultExpr then_result) const;
+
+ // Else terminates a conditional result expression using |else_result| as
+ // the default fallback result expression.
+ ResultExpr Else(ResultExpr else_result) const;
+
+ private:
+ using Clause = std::pair<BoolExpr, ResultExpr>;
+
+ explicit Elser(cons::List<Clause> clause_list);
+
+ cons::List<Clause> clause_list_;
+
+ friend Elser If(BoolExpr, ResultExpr);
+ template <typename T>
+ friend Caser<T> Switch(const Arg<T>&);
+ DISALLOW_ASSIGN(Elser);
+};
+
+// Switch begins a switch expression dispatched according to the
+// specified argument value.
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg);
+
+template <typename T>
+class SANDBOX_EXPORT Caser {
+ public:
+ Caser(const Caser<T>& caser) : arg_(caser.arg_), elser_(caser.elser_) {}
+ ~Caser() {}
+
+ // Case adds a single-value "case" clause to the switch.
+ Caser<T> Case(T value, ResultExpr result) const;
+
+ // Cases adds a multiple-value "case" clause to the switch.
+ // See also the SANDBOX_BPF_DSL_CASES macro below for a more idiomatic way
+ // of using this function.
+ template <typename... Values>
+ Caser<T> CasesImpl(ResultExpr result, const Values&... values) const;
+
+ // Terminate the switch with a "default" clause.
+ ResultExpr Default(ResultExpr result) const;
+
+ private:
+ Caser(const Arg<T>& arg, Elser elser) : arg_(arg), elser_(elser) {}
+
+ Arg<T> arg_;
+ Elser elser_;
+
+ template <typename U>
+ friend Caser<U> Switch(const Arg<U>&);
+ DISALLOW_ASSIGN(Caser);
+};
+
+// Recommended usage is to put
+// #define CASES SANDBOX_BPF_DSL_CASES
+// near the top of the .cc file (e.g., nearby any "using" statements), then
+// use like:
+// Switch(arg).CASES((3, 5, 7), result)...;
+#define SANDBOX_BPF_DSL_CASES(values, result) \
+ CasesImpl(result, SANDBOX_BPF_DSL_CASES_HELPER values)
+
+// Helper macro to strip parentheses.
+#define SANDBOX_BPF_DSL_CASES_HELPER(...) __VA_ARGS__
+
+// =====================================================================
+// Official API ends here.
+// =====================================================================
+
+namespace internal {
+
+// Make argument-dependent lookup work. This is necessary because although
+// BoolExpr is defined in bpf_dsl, since it's merely a typedef for
+// scoped_refptr<const internal::BoolExplImpl>, argument-dependent lookup only
+// searches the "internal" nested namespace.
+using bpf_dsl::Not;
+using bpf_dsl::AllOf;
+using bpf_dsl::AnyOf;
+
+// Returns a boolean expression that represents whether system call
+// argument |num| of size |size| is equal to |val|, when masked
+// according to |mask|. Users should use the Arg template class below
+// instead of using this API directly.
+SANDBOX_EXPORT BoolExpr
+ ArgEq(int num, size_t size, uint64_t mask, uint64_t val);
+
+// Returns the default mask for a system call argument of the specified size.
+SANDBOX_EXPORT uint64_t DefaultMask(size_t size);
+
+} // namespace internal
+
+template <typename T>
+Arg<T>::Arg(int num)
+ : num_(num), mask_(internal::DefaultMask(sizeof(T))) {
+}
+
+// Definition requires ArgEq to have been declared. Moved out-of-line
+// to minimize how much internal clutter users have to ignore while
+// reading the header documentation.
+//
+// Additionally, we use this helper member function to avoid linker errors
+// caused by defining operator== out-of-line. For a more detailed explanation,
+// see http://www.parashift.com/c++-faq-lite/template-friends.html.
+template <typename T>
+BoolExpr Arg<T>::EqualTo(T val) const {
+ if (sizeof(T) == 4) {
+ // Prevent sign-extension of negative int32_t values.
+ return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint32_t>(val));
+ }
+ return internal::ArgEq(num_, sizeof(T), mask_, static_cast<uint64_t>(val));
+}
+
+template <typename T>
+SANDBOX_EXPORT Caser<T> Switch(const Arg<T>& arg) {
+ return Caser<T>(arg, Elser(nullptr));
+}
+
+template <typename T>
+Caser<T> Caser<T>::Case(T value, ResultExpr result) const {
+ return SANDBOX_BPF_DSL_CASES((value), std::move(result));
+}
+
+template <typename T>
+template <typename... Values>
+Caser<T> Caser<T>::CasesImpl(ResultExpr result, const Values&... values) const {
+ // Theoretically we could evaluate arg_ just once and emit a more efficient
+ // dispatch table, but for now we simply translate into an equivalent
+ // If/ElseIf/Else chain.
+
+ return Caser<T>(arg_,
+ elser_.ElseIf(AnyOf((arg_ == values)...), std::move(result)));
+}
+
+template <typename T>
+ResultExpr Caser<T>::Default(ResultExpr result) const {
+ return elser_.Else(std::move(result));
+}
+
+template <typename... Rest>
+BoolExpr AllOf(BoolExpr first, Rest&&... rest) {
+ return AllOf(std::move(first), AllOf(std::forward<Rest>(rest)...));
+}
+
+template <typename... Rest>
+BoolExpr AnyOf(BoolExpr first, Rest&&... rest) {
+ return AnyOf(std::move(first), AnyOf(std::forward<Rest>(rest)...));
+}
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_forward.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
new file mode 100644
index 0000000000..af1b48b407
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_forward.h
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
+
+#include <memory>
+
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// The bpf_dsl_forward.h header provides forward declarations for the
+// types defined in bpf_dsl.h. It's intended for use in user headers
+// that need to reference bpf_dsl types, but don't require definitions.
+
+namespace internal {
+class ResultExprImpl;
+class BoolExprImpl;
+}
+
+using ResultExpr = std::shared_ptr<const internal::ResultExprImpl>;
+using BoolExpr = std::shared_ptr<const internal::BoolExprImpl>;
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+namespace std {
+extern template class SANDBOX_EXPORT
+ shared_ptr<const sandbox::bpf_dsl::internal::BoolExprImpl>;
+extern template class SANDBOX_EXPORT
+ shared_ptr<const sandbox::bpf_dsl::internal::ResultExprImpl>;
+} // namespace std
+
+#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_FORWARD_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_impl.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
new file mode 100644
index 0000000000..f397321edd
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/bpf_dsl_impl.h
@@ -0,0 +1,67 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
+#define SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class PolicyCompiler;
+
+namespace internal {
+
+// Internal interface implemented by BoolExpr implementations.
+class BoolExprImpl {
+ public:
+ // Compile uses |pc| to emit a CodeGen::Node that conditionally continues
+ // to either |then_node| or |false_node|, depending on whether the represented
+ // boolean expression is true or false.
+ virtual CodeGen::Node Compile(PolicyCompiler* pc,
+ CodeGen::Node then_node,
+ CodeGen::Node else_node) const = 0;
+
+ protected:
+ BoolExprImpl() {}
+ virtual ~BoolExprImpl() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BoolExprImpl);
+};
+
+// Internal interface implemented by ResultExpr implementations.
+class ResultExprImpl {
+ public:
+ // Compile uses |pc| to emit a CodeGen::Node that executes the
+ // represented result expression.
+ virtual CodeGen::Node Compile(PolicyCompiler* pc) const = 0;
+
+ // HasUnsafeTraps returns whether the result expression is or recursively
+ // contains an unsafe trap expression.
+ virtual bool HasUnsafeTraps() const;
+
+ // IsAllow returns whether the result expression is an "allow" result.
+ virtual bool IsAllow() const;
+
+ // IsAllow returns whether the result expression is a "deny" result.
+ virtual bool IsDeny() const;
+
+ protected:
+ ResultExprImpl() {}
+ virtual ~ResultExprImpl() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResultExprImpl);
+};
+
+} // namespace internal
+} // namespace bpf_dsl
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_BPF_DSL_IMPL_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.cc b/security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.cc
new file mode 100644
index 0000000000..d88bd531a2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <utility>
+
+#include "base/logging.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+
+// This CodeGen implementation strives for simplicity while still
+// generating acceptable BPF programs under typical usage patterns
+// (e.g., by PolicyCompiler).
+//
+// The key to its simplicity is that BPF programs only support forward
+// jumps/branches, which allows constraining the DAG construction API
+// to make instruction nodes immutable. Immutable nodes admits a
+// simple greedy approach of emitting new instructions as needed and
+// then reusing existing ones that have already been emitted. This
+// cleanly avoids any need to compute basic blocks or apply
+// topological sorting because the API effectively sorts instructions
+// for us (e.g., before MakeInstruction() can be called to emit a
+// branch instruction, it must have already been called for each
+// branch path).
+//
+// This greedy algorithm is not without (theoretical) weakness though:
+//
+// 1. In the general case, we don't eliminate dead code. If needed,
+// we could trace back through the program in Compile() and elide
+// any unneeded instructions, but in practice we only emit live
+// instructions anyway.
+//
+// 2. By not dividing instructions into basic blocks and sorting, we
+// lose an opportunity to move non-branch/non-return instructions
+// adjacent to their successor instructions, which means we might
+// need to emit additional jumps. But in practice, they'll
+// already be nearby as long as callers don't go out of their way
+// to interleave MakeInstruction() calls for unrelated code
+// sequences.
+
+namespace sandbox {
+
+// kBranchRange is the maximum value that can be stored in
+// sock_filter's 8-bit jt and jf fields.
+const size_t kBranchRange = std::numeric_limits<uint8_t>::max();
+
+const CodeGen::Node CodeGen::kNullNode;
+
+CodeGen::CodeGen() : program_(), equivalent_(), memos_() {
+}
+
+CodeGen::~CodeGen() {
+}
+
+CodeGen::Program CodeGen::Compile(CodeGen::Node head) {
+ return Program(program_.rbegin() + Offset(head), program_.rend());
+}
+
+CodeGen::Node CodeGen::MakeInstruction(uint16_t code,
+ uint32_t k,
+ Node jt,
+ Node jf) {
+ // To avoid generating redundant code sequences, we memoize the
+ // results from AppendInstruction().
+ auto res = memos_.insert(std::make_pair(MemoKey(code, k, jt, jf), kNullNode));
+ CodeGen::Node* node = &res.first->second;
+ if (res.second) { // Newly inserted memo entry.
+ *node = AppendInstruction(code, k, jt, jf);
+ }
+ return *node;
+}
+
+CodeGen::Node CodeGen::AppendInstruction(uint16_t code,
+ uint32_t k,
+ Node jt,
+ Node jf) {
+ if (BPF_CLASS(code) == BPF_JMP) {
+ CHECK_NE(BPF_JA, BPF_OP(code)) << "CodeGen inserts JAs as needed";
+
+ // Optimally adding jumps is rather tricky, so we use a quick
+ // approximation: by artificially reducing |jt|'s range, |jt| will
+ // stay within its true range even if we add a jump for |jf|.
+ jt = WithinRange(jt, kBranchRange - 1);
+ jf = WithinRange(jf, kBranchRange);
+ return Append(code, k, Offset(jt), Offset(jf));
+ }
+
+ CHECK_EQ(kNullNode, jf) << "Non-branch instructions shouldn't provide jf";
+ if (BPF_CLASS(code) == BPF_RET) {
+ CHECK_EQ(kNullNode, jt) << "Return instructions shouldn't provide jt";
+ } else {
+ // For non-branch/non-return instructions, execution always
+ // proceeds to the next instruction; so we need to arrange for
+ // that to be |jt|.
+ jt = WithinRange(jt, 0);
+ CHECK_EQ(0U, Offset(jt)) << "ICE: Failed to setup next instruction";
+ }
+ return Append(code, k, 0, 0);
+}
+
+CodeGen::Node CodeGen::WithinRange(Node target, size_t range) {
+ // Just use |target| if it's already within range.
+ if (Offset(target) <= range) {
+ return target;
+ }
+
+ // Alternatively, look for an equivalent instruction within range.
+ if (Offset(equivalent_.at(target)) <= range) {
+ return equivalent_.at(target);
+ }
+
+ // Otherwise, fall back to emitting a jump instruction.
+ Node jump = Append(BPF_JMP | BPF_JA, Offset(target), 0, 0);
+ equivalent_.at(target) = jump;
+ return jump;
+}
+
+CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) {
+ if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) {
+ CHECK_LE(jt, kBranchRange);
+ CHECK_LE(jf, kBranchRange);
+ } else {
+ CHECK_EQ(0U, jt);
+ CHECK_EQ(0U, jf);
+ }
+
+ CHECK_LT(program_.size(), static_cast<size_t>(BPF_MAXINSNS));
+ CHECK_EQ(program_.size(), equivalent_.size());
+
+ Node res = program_.size();
+ program_.push_back(sock_filter{
+ code, static_cast<uint8_t>(jt), static_cast<uint8_t>(jf), k});
+ equivalent_.push_back(res);
+ return res;
+}
+
+size_t CodeGen::Offset(Node target) const {
+ CHECK_LT(target, program_.size()) << "Bogus offset target node";
+ return (program_.size() - 1) - target;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.h
new file mode 100644
index 0000000000..3fc3f35a0d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/codegen.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
+#define SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <tuple>
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+struct sock_filter;
+
+namespace sandbox {
+
+// The code generator implements a basic assembler that can convert a
+// graph of BPF instructions into a well-formed array of BPF
+// instructions. Most notably, it ensures that jumps are always
+// forward and don't exceed the limit of 255 instructions imposed by
+// the instruction set.
+//
+// Callers would typically create a new CodeGen object and then use it
+// to build a DAG of instruction nodes. They'll eventually call
+// Compile() to convert this DAG to a Program.
+//
+// CodeGen gen;
+// CodeGen::Node allow, branch, dag;
+//
+// allow =
+// gen.MakeInstruction(BPF_RET+BPF_K,
+// ErrorCode(ErrorCode::ERR_ALLOWED).err()));
+// branch =
+// gen.MakeInstruction(BPF_JMP+BPF_EQ+BPF_K, __NR_getpid,
+// Trap(GetPidHandler, NULL), allow);
+// dag =
+// gen.MakeInstruction(BPF_LD+BPF_W+BPF_ABS,
+// offsetof(struct arch_seccomp_data, nr), branch);
+//
+// // Simplified code follows; in practice, it is important to avoid calling
+// // any C++ destructors after starting the sandbox.
+// CodeGen::Program program = gen.Compile(dag);
+// const struct sock_fprog prog = {
+// static_cast<unsigned short>(program.size()), &program[0] };
+// prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
+//
+class SANDBOX_EXPORT CodeGen {
+ public:
+ // A vector of BPF instructions that need to be installed as a filter
+ // program in the kernel.
+ typedef std::vector<struct sock_filter> Program;
+
+ // Node represents a node within the instruction DAG being compiled.
+ using Node = Program::size_type;
+
+ // kNullNode represents the "null" node; i.e., the reserved node
+ // value guaranteed to not equal any actual nodes.
+ static const Node kNullNode = -1;
+
+ CodeGen();
+ ~CodeGen();
+
+ // MakeInstruction creates a node representing the specified
+ // instruction, or returns and existing equivalent node if one
+ // exists. For details on the possible parameters refer to
+ // https://www.kernel.org/doc/Documentation/networking/filter.txt.
+ // TODO(mdempsky): Reconsider using default arguments here.
+ Node MakeInstruction(uint16_t code,
+ uint32_t k,
+ Node jt = kNullNode,
+ Node jf = kNullNode);
+
+ // Compile linearizes the instruction DAG rooted at |head| into a
+ // program that can be executed by a BPF virtual machine.
+ Program Compile(Node head);
+
+ private:
+ using MemoKey = std::tuple<uint16_t, uint32_t, Node, Node>;
+
+ // AppendInstruction adds a new instruction, ensuring that |jt| and
+ // |jf| are within range as necessary for |code|.
+ Node AppendInstruction(uint16_t code, uint32_t k, Node jt, Node jf);
+
+ // WithinRange returns a node equivalent to |next| that is at most
+ // |range| instructions away from the (logical) beginning of the
+ // program.
+ Node WithinRange(Node next, size_t range);
+
+ // Append appends a new instruction to the physical end (i.e.,
+ // logical beginning) of |program_|.
+ Node Append(uint16_t code, uint32_t k, size_t jt, size_t jf);
+
+ // Offset returns how many instructions exist in |program_| after |target|.
+ size_t Offset(Node target) const;
+
+ // NOTE: program_ is the compiled program in *reverse*, so that
+ // indices remain stable as we add instructions.
+ Program program_;
+
+ // equivalent_ stores the most recent semantically-equivalent node for each
+ // instruction in program_. A node is defined as semantically-equivalent to N
+ // if it has the same instruction code and constant as N and its successor
+ // nodes (if any) are semantically-equivalent to N's successor nodes, or
+ // if it's an unconditional jump to a node semantically-equivalent to N.
+ std::vector<Node> equivalent_;
+
+ std::map<MemoKey, Node> memos_;
+
+ DISALLOW_COPY_AND_ASSIGN(CodeGen);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_CODEGEN_H__
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/cons.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/cons.h
new file mode 100644
index 0000000000..07ac3dfc23
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/cons.h
@@ -0,0 +1,137 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_CONS_H_
+#define SANDBOX_LINUX_BPF_DSL_CONS_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace cons {
+
+// Namespace cons provides an abstraction for immutable "cons list"
+// data structures as commonly provided in functional programming
+// languages like Lisp or Haskell.
+//
+// A cons list is a linked list consisting of "cells", each of which
+// have a "head" and a "tail" element. A cell's head element contains
+// a user specified value, while the tail element contains a (possibly
+// null) pointer to another cell.
+//
+// An empty list (idiomatically referred to as "nil") can be
+// constructed as "cons::List<Foo>()" or simply as "nullptr" if Foo
+// can be inferred from context (e.g., calling a function that has a
+// "cons::List<Foo>" parameter).
+//
+// Existing lists (including empty lists) can be extended by
+// prepending new values to the front using the "Cons(head, tail)"
+// function, which will allocate a new cons cell. Notably, cons lists
+// support creating multiple lists that share a common tail sequence.
+//
+// Lastly, lists support iteration via C++11's range-based for loop
+// construct.
+//
+// Examples:
+//
+// // basic construction
+// const cons::List<char> kNil = nullptr;
+// cons::List<char> ba = Cons('b', Cons('a', kNil));
+//
+// // common tail sequence
+// cons::List<char> cba = Cons('c', ba);
+// cons::List<char> dba = Cons('d', ba);
+//
+// // iteration
+// for (const char& ch : cba) {
+// // iterates 'c', 'b', 'a'
+// }
+// for (const char& ch : dba) {
+// // iterates 'd', 'b', 'a'
+// }
+
+// Forward declarations.
+template <typename T>
+class Cell;
+template <typename T>
+class ListIterator;
+
+// List represents a (possibly null) pointer to a cons cell.
+template <typename T>
+using List = std::shared_ptr<const Cell<T>>;
+
+// Cons extends a cons list by prepending a new value to the front.
+template <typename T>
+List<T> Cons(const T& head, List<T> tail) {
+ return std::make_shared<Cell<T>>(head, std::move(tail));
+}
+
+// Cell represents an individual "cons cell" within a cons list.
+template <typename T>
+class Cell {
+ public:
+ Cell(const T& head, List<T> tail) : head_(head), tail_(std::move(tail)) {}
+
+ // Head returns this cell's head element.
+ const T& head() const { return head_; }
+
+ // Tail returns this cell's tail element.
+ const List<T>& tail() const { return tail_; }
+
+ private:
+ T head_;
+ List<T> tail_;
+
+ DISALLOW_COPY_AND_ASSIGN(Cell);
+};
+
+// Begin returns a list iterator pointing to the first element of the
+// cons list. It's provided to support range-based for loops.
+template <typename T>
+ListIterator<T> begin(const List<T>& list) {
+ return ListIterator<T>(list);
+}
+
+// End returns a list iterator pointing to the "past-the-end" element
+// of the cons list (i.e., nil). It's provided to support range-based
+// for loops.
+template <typename T>
+ListIterator<T> end(const List<T>& list) {
+ return ListIterator<T>();
+}
+
+// ListIterator provides C++ forward iterator semantics for traversing
+// a cons list.
+template <typename T>
+class ListIterator {
+ public:
+ ListIterator() : list_() {}
+ explicit ListIterator(const List<T>& list) : list_(list) {}
+
+ const T& operator*() const { return list_->head(); }
+
+ ListIterator& operator++() {
+ list_ = list_->tail();
+ return *this;
+ }
+
+ friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) {
+ return lhs.list_ == rhs.list_;
+ }
+
+ private:
+ List<T> list_;
+};
+
+template <typename T>
+bool operator!=(const ListIterator<T>& lhs, const ListIterator<T>& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace cons
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_CONS_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.cc b/security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.cc
new file mode 100644
index 0000000000..2edf592f68
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.cc
@@ -0,0 +1,159 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/dump_bpf.h"
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+const char* AluOpToken(uint32_t code) {
+ switch (BPF_OP(code)) {
+ case BPF_ADD:
+ return "+";
+ case BPF_SUB:
+ return "-";
+ case BPF_MUL:
+ return "*";
+ case BPF_DIV:
+ return "/";
+ case BPF_MOD:
+ return "%";
+ case BPF_OR:
+ return "|";
+ case BPF_XOR:
+ return "^";
+ case BPF_AND:
+ return "&";
+ case BPF_LSH:
+ return "<<";
+ case BPF_RSH:
+ return ">>";
+ default:
+ return "???";
+ }
+}
+
+const char* JmpOpToken(uint32_t code) {
+ switch (BPF_OP(code)) {
+ case BPF_JSET:
+ return "&";
+ case BPF_JEQ:
+ return "==";
+ case BPF_JGE:
+ return ">=";
+ default:
+ return "???";
+ }
+}
+
+const char* DataOffsetName(size_t off) {
+ switch (off) {
+ case SECCOMP_NR_IDX:
+ return "System call number";
+ case SECCOMP_ARCH_IDX:
+ return "Architecture";
+ case SECCOMP_IP_LSB_IDX:
+ return "Instruction pointer (LSB)";
+ case SECCOMP_IP_MSB_IDX:
+ return "Instruction pointer (MSB)";
+ default:
+ return "???";
+ }
+}
+
+void AppendInstruction(std::string* dst, size_t pc, const sock_filter& insn) {
+ base::StringAppendF(dst, "%3zu) ", pc);
+ switch (BPF_CLASS(insn.code)) {
+ case BPF_LD:
+ if (insn.code == BPF_LD + BPF_W + BPF_ABS) {
+ base::StringAppendF(dst, "LOAD %" PRIu32 " // ", insn.k);
+ size_t maybe_argno =
+ (insn.k - offsetof(struct arch_seccomp_data, args)) /
+ sizeof(uint64_t);
+ if (maybe_argno < 6 && insn.k == SECCOMP_ARG_LSB_IDX(maybe_argno)) {
+ base::StringAppendF(dst, "Argument %zu (LSB)\n", maybe_argno);
+ } else if (maybe_argno < 6 &&
+ insn.k == SECCOMP_ARG_MSB_IDX(maybe_argno)) {
+ base::StringAppendF(dst, "Argument %zu (MSB)\n", maybe_argno);
+ } else {
+ base::StringAppendF(dst, "%s\n", DataOffsetName(insn.k));
+ }
+ } else {
+ base::StringAppendF(dst, "Load ???\n");
+ }
+ break;
+ case BPF_JMP:
+ if (BPF_OP(insn.code) == BPF_JA) {
+ base::StringAppendF(dst, "JMP %zu\n", pc + insn.k + 1);
+ } else {
+ base::StringAppendF(
+ dst, "if A %s 0x%" PRIx32 "; then JMP %zu else JMP %zu\n",
+ JmpOpToken(insn.code), insn.k, pc + insn.jt + 1, pc + insn.jf + 1);
+ }
+ break;
+ case BPF_RET:
+ base::StringAppendF(dst, "RET 0x%" PRIx32 " // ", insn.k);
+ if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRAP) {
+ base::StringAppendF(dst, "Trap #%" PRIu32 "\n",
+ insn.k & SECCOMP_RET_DATA);
+ } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
+ base::StringAppendF(dst, "errno = %" PRIu32 "\n",
+ insn.k & SECCOMP_RET_DATA);
+ } else if ((insn.k & SECCOMP_RET_ACTION) == SECCOMP_RET_TRACE) {
+ base::StringAppendF(dst, "Trace #%" PRIu32 "\n",
+ insn.k & SECCOMP_RET_DATA);
+ } else if (insn.k == SECCOMP_RET_ALLOW) {
+ base::StringAppendF(dst, "Allowed\n");
+ } else if (insn.k == SECCOMP_RET_KILL) {
+ base::StringAppendF(dst, "Kill\n");
+ } else {
+ base::StringAppendF(dst, "???\n");
+ }
+ break;
+ case BPF_ALU:
+ if (BPF_OP(insn.code) == BPF_NEG) {
+ base::StringAppendF(dst, "A := -A\n");
+ } else {
+ base::StringAppendF(dst, "A := A %s 0x%" PRIx32 "\n",
+ AluOpToken(insn.code), insn.k);
+ }
+ break;
+ default:
+ base::StringAppendF(dst, "???\n");
+ break;
+ }
+}
+
+} // namespace
+
+void DumpBPF::PrintProgram(const CodeGen::Program& program) {
+ fputs(StringPrintProgram(program).c_str(), stderr);
+}
+
+std::string DumpBPF::StringPrintProgram(const CodeGen::Program& program) {
+ std::string res;
+ for (size_t i = 0; i < program.size(); i++) {
+ AppendInstruction(&res, i + 1, program[i]);
+ }
+ return res;
+}
+
+} // namespace bpf_dsl
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.h
new file mode 100644
index 0000000000..34f1aa99f2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/dump_bpf.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_DUMP_BPF_H_
+#define SANDBOX_LINUX_BPF_DSL_DUMP_BPF_H_
+
+#include <string>
+
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+class SANDBOX_EXPORT DumpBPF {
+ public:
+ // PrintProgram writes |program| in a human-readable format to stderr.
+ static void PrintProgram(const CodeGen::Program& program);
+
+ // StringPrintProgram writes |program| in a human-readable format to
+ // a std::string.
+ static std::string StringPrintProgram(const CodeGen::Program& program);
+};
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_DUMP_BPF_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/errorcode.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/errorcode.h
new file mode 100644
index 0000000000..611c27dd80
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/errorcode.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
+#define SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// TODO(mdempsky): Find a proper home for ERR_{MIN,MAX}_ERRNO and
+// remove this header.
+class SANDBOX_EXPORT ErrorCode {
+ public:
+ enum {
+ ERR_MIN_ERRNO = 0,
+#if defined(__mips__)
+ // MIPS only supports errno up to 1133
+ ERR_MAX_ERRNO = 1133,
+#else
+ // TODO(markus): Android only supports errno up to 255
+ // (crbug.com/181647).
+ ERR_MAX_ERRNO = 4095,
+#endif
+ };
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ErrorCode);
+};
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_ERRORCODE_H__
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
new file mode 100644
index 0000000000..313511f22e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/linux_syscall_ranges.h
@@ -0,0 +1,63 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
+#define SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
+
+#include "build/build_config.h"
+
+#if defined(__x86_64__)
+
+#define MIN_SYSCALL 0u
+#define MAX_PUBLIC_SYSCALL 1024u
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+
+#elif defined(__i386__)
+
+#define MIN_SYSCALL 0u
+#define MAX_PUBLIC_SYSCALL 1024u
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+
+#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
+
+// ARM EABI includes "ARM private" system calls starting at |__ARM_NR_BASE|,
+// and a "ghost syscall private to the kernel", cmpxchg,
+// at |__ARM_NR_BASE+0x00fff0|.
+// See </arch/arm/include/asm/unistd.h> in the Linux kernel.
+
+// __NR_SYSCALL_BASE is 0 in thumb and ARM EABI.
+#define MIN_SYSCALL 0u
+#define MAX_PUBLIC_SYSCALL (MIN_SYSCALL + 1024u)
+// __ARM_NR_BASE is __NR_SYSCALL_BASE + 0xf0000u
+#define MIN_PRIVATE_SYSCALL 0xf0000u
+#define MAX_PRIVATE_SYSCALL (MIN_PRIVATE_SYSCALL + 16u)
+#define MIN_GHOST_SYSCALL (MIN_PRIVATE_SYSCALL + 0xfff0u)
+#define MAX_SYSCALL (MIN_GHOST_SYSCALL + 4u)
+
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)
+
+#include <asm/unistd.h> // for __NR_O32_Linux and __NR_Linux_syscalls
+#define MIN_SYSCALL __NR_O32_Linux
+#define MAX_PUBLIC_SYSCALL (MIN_SYSCALL + __NR_Linux_syscalls)
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+
+#include <asm/unistd.h> // for __NR_64_Linux and __NR_64_Linux_syscalls
+#define MIN_SYSCALL __NR_64_Linux
+#define MAX_PUBLIC_SYSCALL (MIN_SYSCALL + __NR_64_Linux_syscalls)
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+
+#elif defined(__aarch64__)
+
+#include <asm-generic/unistd.h>
+#define MIN_SYSCALL 0u
+#define MAX_PUBLIC_SYSCALL __NR_syscalls
+#define MAX_SYSCALL MAX_PUBLIC_SYSCALL
+
+#else
+#error "Unsupported architecture"
+#endif
+
+#endif // SANDBOX_LINUX_BPF_DSL_LINUX_SYSCALL_RANGES_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.cc b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.cc
new file mode 100644
index 0000000000..c20edc6da8
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.cc
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/policy.h"
+
+#include <errno.h>
+
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+ResultExpr Policy::InvalidSyscall() const {
+ return Error(ENOSYS);
+}
+
+} // namespace bpf_dsl
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.h
new file mode 100644
index 0000000000..6c67589456
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy.h
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_H_
+#define SANDBOX_LINUX_BPF_DSL_POLICY_H_
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+// Interface to implement to define a BPF sandbox policy.
+class SANDBOX_EXPORT Policy {
+ public:
+ Policy() {}
+ virtual ~Policy() {}
+
+ // User extension point for writing custom sandbox policies.
+ // The returned ResultExpr will control how the kernel responds to the
+ // specified system call number.
+ virtual ResultExpr EvaluateSyscall(int sysno) const = 0;
+
+ // Optional overload for specifying alternate behavior for invalid
+ // system calls. The default is to return ENOSYS.
+ virtual ResultExpr InvalidSyscall() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Policy);
+};
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_POLICY_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
new file mode 100644
index 0000000000..b909fc37f6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -0,0 +1,481 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_impl.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+
+namespace {
+
+#if defined(__i386__) || defined(__x86_64__)
+const bool kIsIntel = true;
+#else
+const bool kIsIntel = false;
+#endif
+#if defined(__x86_64__) && defined(__ILP32__)
+const bool kIsX32 = true;
+#else
+const bool kIsX32 = false;
+#endif
+
+const int kSyscallsRequiredForUnsafeTraps[] = {
+ __NR_rt_sigprocmask,
+ __NR_rt_sigreturn,
+#if defined(__NR_sigprocmask)
+ __NR_sigprocmask,
+#endif
+#if defined(__NR_sigreturn)
+ __NR_sigreturn,
+#endif
+};
+
+bool HasExactlyOneBit(uint64_t x) {
+ // Common trick; e.g., see http://stackoverflow.com/a/108329.
+ return x != 0 && (x & (x - 1)) == 0;
+}
+
+ResultExpr DefaultPanic(const char* error) {
+ return Kill();
+}
+
+// A Trap() handler that returns an "errno" value. The value is encoded
+// in the "aux" parameter.
+intptr_t ReturnErrno(const struct arch_seccomp_data&, void* aux) {
+ // TrapFnc functions report error by following the native kernel convention
+ // of returning an exit code in the range of -1..-4096. They do not try to
+ // set errno themselves. The glibc wrapper that triggered the SIGSYS will
+ // ultimately do so for us.
+ int err = reinterpret_cast<intptr_t>(aux) & SECCOMP_RET_DATA;
+ return -err;
+}
+
+bool HasUnsafeTraps(const Policy* policy) {
+ DCHECK(policy);
+ for (uint32_t sysnum : SyscallSet::ValidOnly()) {
+ if (policy->EvaluateSyscall(sysnum)->HasUnsafeTraps()) {
+ return true;
+ }
+ }
+ return policy->InvalidSyscall()->HasUnsafeTraps();
+}
+
+} // namespace
+
+struct PolicyCompiler::Range {
+ uint32_t from;
+ CodeGen::Node node;
+};
+
+PolicyCompiler::PolicyCompiler(const Policy* policy, TrapRegistry* registry)
+ : policy_(policy),
+ registry_(registry),
+ escapepc_(0),
+ panic_func_(DefaultPanic),
+ gen_(),
+ has_unsafe_traps_(HasUnsafeTraps(policy_)) {
+ DCHECK(policy);
+}
+
+PolicyCompiler::~PolicyCompiler() {
+}
+
+CodeGen::Program PolicyCompiler::Compile() {
+ CHECK(policy_->InvalidSyscall()->IsDeny())
+ << "Policies should deny invalid system calls";
+
+ // If our BPF program has unsafe traps, enable support for them.
+ if (has_unsafe_traps_) {
+ CHECK_NE(0U, escapepc_) << "UnsafeTrap() requires a valid escape PC";
+
+ for (int sysnum : kSyscallsRequiredForUnsafeTraps) {
+ CHECK(policy_->EvaluateSyscall(sysnum)->IsAllow())
+ << "Policies that use UnsafeTrap() must unconditionally allow all "
+ "required system calls";
+ }
+
+ CHECK(registry_->EnableUnsafeTraps())
+ << "We'd rather die than enable unsafe traps";
+ }
+
+ // Assemble the BPF filter program.
+ return gen_.Compile(AssemblePolicy());
+}
+
+void PolicyCompiler::DangerousSetEscapePC(uint64_t escapepc) {
+ escapepc_ = escapepc;
+}
+
+void PolicyCompiler::SetPanicFunc(PanicFunc panic_func) {
+ panic_func_ = panic_func;
+}
+
+CodeGen::Node PolicyCompiler::AssemblePolicy() {
+ // A compiled policy consists of three logical parts:
+ // 1. Check that the "arch" field matches the expected architecture.
+ // 2. If the policy involves unsafe traps, check if the syscall was
+ // invoked by Syscall::Call, and then allow it unconditionally.
+ // 3. Check the system call number and jump to the appropriate compiled
+ // system call policy number.
+ return CheckArch(MaybeAddEscapeHatch(DispatchSyscall()));
+}
+
+CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) {
+ // If the architecture doesn't match SECCOMP_ARCH, disallow the
+ // system call.
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS, SECCOMP_ARCH_IDX,
+ gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, SECCOMP_ARCH, passed,
+ CompileResult(panic_func_(
+ "Invalid audit architecture in BPF filter"))));
+}
+
+CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
+ // If no unsafe traps, then simply return |rest|.
+ if (!has_unsafe_traps_) {
+ return rest;
+ }
+
+ // We already enabled unsafe traps in Compile, but enable them again to give
+ // the trap registry a second chance to complain before we add the backdoor.
+ CHECK(registry_->EnableUnsafeTraps());
+
+ // Allow system calls, if they originate from our magic return address.
+ const uint32_t lopc = static_cast<uint32_t>(escapepc_);
+ const uint32_t hipc = static_cast<uint32_t>(escapepc_ >> 32);
+
+ // BPF cannot do native 64-bit comparisons, so we have to compare
+ // both 32-bit halves of the instruction pointer. If they match what
+ // we expect, we return ERR_ALLOWED. If either or both don't match,
+ // we continue evalutating the rest of the sandbox policy.
+ //
+ // For simplicity, we check the full 64-bit instruction pointer even
+ // on 32-bit architectures.
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_LSB_IDX,
+ gen_.MakeInstruction(
+ BPF_JMP + BPF_JEQ + BPF_K, lopc,
+ gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS, SECCOMP_IP_MSB_IDX,
+ gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, hipc,
+ CompileResult(Allow()), rest)),
+ rest));
+}
+
+CodeGen::Node PolicyCompiler::DispatchSyscall() {
+ // Evaluate all possible system calls and group their Nodes into
+ // ranges of identical codes.
+ Ranges ranges;
+ FindRanges(&ranges);
+
+ // Compile the system call ranges to an optimized BPF jumptable
+ CodeGen::Node jumptable = AssembleJumpTable(ranges.begin(), ranges.end());
+
+ // Grab the system call number, so that we can check it and then
+ // execute the jump table.
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable));
+}
+
+CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) {
+ if (kIsIntel) {
+ // On Intel architectures, verify that system call numbers are in the
+ // expected number range.
+ CodeGen::Node invalidX32 =
+ CompileResult(panic_func_("Illegal mixing of system call ABIs"));
+ if (kIsX32) {
+ // The newer x32 API always sets bit 30.
+ return gen_.MakeInstruction(
+ BPF_JMP + BPF_JSET + BPF_K, 0x40000000, passed, invalidX32);
+ } else {
+ // The older i386 and x86-64 APIs clear bit 30 on all system calls.
+ return gen_.MakeInstruction(
+ BPF_JMP + BPF_JSET + BPF_K, 0x40000000, invalidX32, passed);
+ }
+ }
+
+ // TODO(mdempsky): Similar validation for other architectures?
+ return passed;
+}
+
+void PolicyCompiler::FindRanges(Ranges* ranges) {
+ // Please note that "struct seccomp_data" defines system calls as a signed
+ // int32_t, but BPF instructions always operate on unsigned quantities. We
+ // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
+ // and then verifying that the rest of the number range (both positive and
+ // negative) all return the same Node.
+ const CodeGen::Node invalid_node = CompileResult(policy_->InvalidSyscall());
+ uint32_t old_sysnum = 0;
+ CodeGen::Node old_node =
+ SyscallSet::IsValid(old_sysnum)
+ ? CompileResult(policy_->EvaluateSyscall(old_sysnum))
+ : invalid_node;
+
+ for (uint32_t sysnum : SyscallSet::All()) {
+ CodeGen::Node node =
+ SyscallSet::IsValid(sysnum)
+ ? CompileResult(policy_->EvaluateSyscall(static_cast<int>(sysnum)))
+ : invalid_node;
+ // N.B., here we rely on CodeGen folding (i.e., returning the same
+ // node value for) identical code sequences, otherwise our jump
+ // table will blow up in size.
+ if (node != old_node) {
+ ranges->push_back(Range{old_sysnum, old_node});
+ old_sysnum = sysnum;
+ old_node = node;
+ }
+ }
+ ranges->push_back(Range{old_sysnum, old_node});
+}
+
+CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
+ Ranges::const_iterator stop) {
+ // We convert the list of system call ranges into jump table that performs
+ // a binary search over the ranges.
+ // As a sanity check, we need to have at least one distinct ranges for us
+ // to be able to build a jump table.
+ CHECK(start < stop) << "Invalid iterator range";
+ const auto n = stop - start;
+ if (n == 1) {
+ // If we have narrowed things down to a single range object, we can
+ // return from the BPF filter program.
+ return start->node;
+ }
+
+ // Pick the range object that is located at the mid point of our list.
+ // We compare our system call number against the lowest valid system call
+ // number in this range object. If our number is lower, it is outside of
+ // this range object. If it is greater or equal, it might be inside.
+ Ranges::const_iterator mid = start + n / 2;
+
+ // Sub-divide the list of ranges and continue recursively.
+ CodeGen::Node jf = AssembleJumpTable(start, mid);
+ CodeGen::Node jt = AssembleJumpTable(mid, stop);
+ return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf);
+}
+
+CodeGen::Node PolicyCompiler::CompileResult(const ResultExpr& res) {
+ return res->Compile(this);
+}
+
+CodeGen::Node PolicyCompiler::MaskedEqual(int argno,
+ size_t width,
+ uint64_t mask,
+ uint64_t value,
+ CodeGen::Node passed,
+ CodeGen::Node failed) {
+ // Sanity check that arguments make sense.
+ CHECK(argno >= 0 && argno < 6) << "Invalid argument number " << argno;
+ CHECK(width == 4 || width == 8) << "Invalid argument width " << width;
+ CHECK_NE(0U, mask) << "Zero mask is invalid";
+ CHECK_EQ(value, value & mask) << "Value contains masked out bits";
+ if (sizeof(void*) == 4) {
+ CHECK_EQ(4U, width) << "Invalid width on 32-bit platform";
+ }
+ if (width == 4) {
+ CHECK_EQ(0U, mask >> 32) << "Mask exceeds argument size";
+ CHECK_EQ(0U, value >> 32) << "Value exceeds argument size";
+ }
+
+ // We want to emit code to check "(arg & mask) == value" where arg, mask, and
+ // value are 64-bit values, but the BPF machine is only 32-bit. We implement
+ // this by independently testing the upper and lower 32-bits and continuing to
+ // |passed| if both evaluate true, or to |failed| if either evaluate false.
+ return MaskedEqualHalf(argno, width, mask, value, ArgHalf::UPPER,
+ MaskedEqualHalf(argno, width, mask, value,
+ ArgHalf::LOWER, passed, failed),
+ failed);
+}
+
+CodeGen::Node PolicyCompiler::MaskedEqualHalf(int argno,
+ size_t width,
+ uint64_t full_mask,
+ uint64_t full_value,
+ ArgHalf half,
+ CodeGen::Node passed,
+ CodeGen::Node failed) {
+ if (width == 4 && half == ArgHalf::UPPER) {
+ // Special logic for sanity checking the upper 32-bits of 32-bit system
+ // call arguments.
+
+ CodeGen::Node invalid_64bit = Unexpected64bitArgument(argno);
+
+ const uint32_t upper = SECCOMP_ARG_MSB_IDX(argno);
+ const uint32_t lower = SECCOMP_ARG_LSB_IDX(argno);
+
+ if (sizeof(void*) == 4) {
+ // On 32-bit platforms, the upper 32-bits should always be 0:
+ // LDW [upper]
+ // JEQ 0, passed, invalid
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS,
+ upper,
+ gen_.MakeInstruction(
+ BPF_JMP + BPF_JEQ + BPF_K, 0, passed, invalid_64bit));
+ }
+
+ // On 64-bit platforms, the ABI (at least on x86_64) allows any value
+ // for the upper half, but to avoid potential vulnerabilties if an
+ // argument is incorrectly tested as a 32-bit type, we require it to be
+ // either zero-extended or sign-extended. That is, the upper 32-bits
+ // may be 0 or ~0; but we only allow ~0 if the sign bit of the lower
+ // 32-bits is set too:
+ //
+ // LDW [upper]
+ // JEQ 0, passed, (next)
+ // JEQ ~0, (next), invalid
+ // LDW [lower]
+ // JSET (1<<31), passed, invalid
+ //
+ // TODO(mdempsky): The JSET instruction could perhaps jump to passed->next
+ // instead, as the first instruction of passed should be "LDW [lower]".
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS,
+ upper,
+ gen_.MakeInstruction(
+ BPF_JMP + BPF_JEQ + BPF_K,
+ 0,
+ passed,
+ gen_.MakeInstruction(
+ BPF_JMP + BPF_JEQ + BPF_K,
+ std::numeric_limits<uint32_t>::max(),
+ gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS,
+ lower,
+ gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K,
+ 1U << 31,
+ passed,
+ invalid_64bit)),
+ invalid_64bit)));
+ }
+
+ const uint32_t idx = (half == ArgHalf::UPPER) ? SECCOMP_ARG_MSB_IDX(argno)
+ : SECCOMP_ARG_LSB_IDX(argno);
+ const uint32_t mask = (half == ArgHalf::UPPER) ? full_mask >> 32 : full_mask;
+ const uint32_t value =
+ (half == ArgHalf::UPPER) ? full_value >> 32 : full_value;
+
+ // Emit a suitable instruction sequence for (arg & mask) == value.
+
+ // For (arg & 0) == 0, just return passed.
+ if (mask == 0) {
+ CHECK_EQ(0U, value);
+ return passed;
+ }
+
+ // For (arg & ~0) == value, emit:
+ // LDW [idx]
+ // JEQ value, passed, failed
+ if (mask == std::numeric_limits<uint32_t>::max()) {
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS,
+ idx,
+ gen_.MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed));
+ }
+
+ // For (arg & mask) == 0, emit:
+ // LDW [idx]
+ // JSET mask, failed, passed
+ // (Note: failed and passed are intentionally swapped.)
+ if (value == 0) {
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS,
+ idx,
+ gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, failed, passed));
+ }
+
+ // For (arg & x) == x where x is a single-bit value, emit:
+ // LDW [idx]
+ // JSET mask, passed, failed
+ if (mask == value && HasExactlyOneBit(mask)) {
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS,
+ idx,
+ gen_.MakeInstruction(BPF_JMP + BPF_JSET + BPF_K, mask, passed, failed));
+ }
+
+ // Generic fallback:
+ // LDW [idx]
+ // AND mask
+ // JEQ value, passed, failed
+ return gen_.MakeInstruction(
+ BPF_LD + BPF_W + BPF_ABS,
+ idx,
+ gen_.MakeInstruction(
+ BPF_ALU + BPF_AND + BPF_K,
+ mask,
+ gen_.MakeInstruction(
+ BPF_JMP + BPF_JEQ + BPF_K, value, passed, failed)));
+}
+
+CodeGen::Node PolicyCompiler::Unexpected64bitArgument(int argno) {
+ // This situation is unlikely, but possible. Return to userspace,
+ // zero-extend the problematic argument, and re-issue the syscall.
+ return CompileResult(bpf_dsl::Trap(
+ [](const arch_seccomp_data& args_ref, void* aux) -> intptr_t {
+ arch_seccomp_data args = args_ref;
+ int argno = (int)(intptr_t)aux;
+ args.args[argno] &= 0xFFFFFFFF;
+ return Syscall::Call(args.nr, args.args[0], args.args[1], args.args[2],
+ args.args[3], args.args[4], args.args[5]);
+ },
+ (void*)(intptr_t)argno));
+}
+
+CodeGen::Node PolicyCompiler::Return(uint32_t ret) {
+ if (has_unsafe_traps_ && (ret & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
+ // When inside an UnsafeTrap() callback, we want to allow all system calls.
+ // This means, we must conditionally disable the sandbox -- and that's not
+ // something that kernel-side BPF filters can do, as they cannot inspect
+ // any state other than the syscall arguments.
+ // But if we redirect all error handlers to user-space, then we can easily
+ // make this decision.
+ // The performance penalty for this extra round-trip to user-space is not
+ // actually that bad, as we only ever pay it for denied system calls; and a
+ // typical program has very few of these.
+ return Trap(ReturnErrno, reinterpret_cast<void*>(ret & SECCOMP_RET_DATA),
+ true);
+ }
+
+ return gen_.MakeInstruction(BPF_RET + BPF_K, ret);
+}
+
+CodeGen::Node PolicyCompiler::Trap(TrapRegistry::TrapFnc fnc,
+ const void* aux,
+ bool safe) {
+ uint16_t trap_id = registry_->Add(fnc, aux, safe);
+ return gen_.MakeInstruction(BPF_RET + BPF_K, SECCOMP_RET_TRAP + trap_id);
+}
+
+bool PolicyCompiler::IsRequiredForUnsafeTrap(int sysno) {
+ for (size_t i = 0; i < base::size(kSyscallsRequiredForUnsafeTraps); ++i) {
+ if (sysno == kSyscallsRequiredForUnsafeTraps[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace bpf_dsl
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.h
new file mode 100644
index 0000000000..2acf878474
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/policy_compiler.h
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
+#define SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl_forward.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class Policy;
+
+// PolicyCompiler implements the bpf_dsl compiler, allowing users to
+// transform bpf_dsl policies into BPF programs to be executed by the
+// Linux kernel.
+class SANDBOX_EXPORT PolicyCompiler {
+ public:
+ using PanicFunc = bpf_dsl::ResultExpr (*)(const char* error);
+
+ PolicyCompiler(const Policy* policy, TrapRegistry* registry);
+ ~PolicyCompiler();
+
+ // Compile registers any trap handlers needed by the policy and
+ // compiles the policy to a BPF program, which it returns.
+ CodeGen::Program Compile();
+
+ // DangerousSetEscapePC sets the "escape PC" that is allowed to issue any
+ // system calls, regardless of policy.
+ void DangerousSetEscapePC(uint64_t escapepc);
+
+ // SetPanicFunc sets the callback function used for handling faulty
+ // system call conditions. The default behavior is to immediately kill
+ // the process.
+ // TODO(mdempsky): Move this into Policy?
+ void SetPanicFunc(PanicFunc panic_func);
+
+ // UnsafeTraps require some syscalls to always be allowed.
+ // This helper function returns true for these calls.
+ static bool IsRequiredForUnsafeTrap(int sysno);
+
+ // Functions below are meant for use within bpf_dsl itself.
+
+ // Return returns a CodeGen::Node that returns the specified seccomp
+ // return value.
+ CodeGen::Node Return(uint32_t ret);
+
+ // Trap returns a CodeGen::Node to indicate the system call should
+ // instead invoke a trap handler.
+ CodeGen::Node Trap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
+
+ // MaskedEqual returns a CodeGen::Node that represents a conditional branch.
+ // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
+ // to "value"; if equal, then "passed" will be executed, otherwise "failed".
+ // If "width" is 4, the argument must in the range of 0x0..(1u << 32 - 1)
+ // If it is outside this range, the sandbox treats the system call just
+ // the same as any other ABI violation (i.e., it panics).
+ CodeGen::Node MaskedEqual(int argno,
+ size_t width,
+ uint64_t mask,
+ uint64_t value,
+ CodeGen::Node passed,
+ CodeGen::Node failed);
+
+ private:
+ struct Range;
+ typedef std::vector<Range> Ranges;
+
+ // Used by MaskedEqualHalf to track which half of the argument it's
+ // emitting instructions for.
+ enum class ArgHalf {
+ LOWER,
+ UPPER,
+ };
+
+ // Compile the configured policy into a complete instruction sequence.
+ CodeGen::Node AssemblePolicy();
+
+ // Return an instruction sequence that checks the
+ // arch_seccomp_data's "arch" field is valid, and then passes
+ // control to |passed| if so.
+ CodeGen::Node CheckArch(CodeGen::Node passed);
+
+ // If |has_unsafe_traps_| is true, returns an instruction sequence
+ // that allows all system calls from |escapepc_|, and otherwise
+ // passes control to |rest|. Otherwise, simply returns |rest|.
+ CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest);
+
+ // Return an instruction sequence that loads and checks the system
+ // call number, performs a binary search, and then dispatches to an
+ // appropriate instruction sequence compiled from the current
+ // policy.
+ CodeGen::Node DispatchSyscall();
+
+ // Return an instruction sequence that checks the system call number
+ // (expected to be loaded in register A) and if valid, passes
+ // control to |passed| (with register A still valid).
+ CodeGen::Node CheckSyscallNumber(CodeGen::Node passed);
+
+ // Finds all the ranges of system calls that need to be handled. Ranges are
+ // sorted in ascending order of system call numbers. There are no gaps in the
+ // ranges. System calls with identical CodeGen::Nodes are coalesced into a
+ // single
+ // range.
+ void FindRanges(Ranges* ranges);
+
+ // Returns a BPF program snippet that implements a jump table for the
+ // given range of system call numbers. This function runs recursively.
+ CodeGen::Node AssembleJumpTable(Ranges::const_iterator start,
+ Ranges::const_iterator stop);
+
+ // CompileResult compiles an individual result expression into a
+ // CodeGen node.
+ CodeGen::Node CompileResult(const ResultExpr& res);
+
+ // Returns a BPF program that evaluates half of a conditional expression;
+ // it should only ever be called from CondExpression().
+ CodeGen::Node MaskedEqualHalf(int argno,
+ size_t width,
+ uint64_t full_mask,
+ uint64_t full_value,
+ ArgHalf half,
+ CodeGen::Node passed,
+ CodeGen::Node failed);
+
+ // Returns the CodeGen::Node that is used to handle the case where a
+ // system call argument was expected to be a 32-bit type, but the
+ // value in the 64-bit register doesn't correspond to a
+ // zero-extended or sign-extended 32-bit value.
+ CodeGen::Node Unexpected64bitArgument(int argno);
+
+ const Policy* policy_;
+ TrapRegistry* registry_;
+ uint64_t escapepc_;
+ PanicFunc panic_func_;
+
+ CodeGen gen_;
+ bool has_unsafe_traps_;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyCompiler);
+};
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_POLICY_COMPILER_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h
new file mode 100644
index 0000000000..1a407b9523
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
+#define SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
+
+#include <sys/types.h> // For __BIONIC__.
+// Old Bionic versions do not have sys/user.h. The if can be removed once we no
+// longer need to support these old Bionic versions.
+// All x86_64 builds use a new enough bionic to have sys/user.h.
+#if !defined(__BIONIC__) || defined(__x86_64__)
+#if !defined(__native_client_nonsfi__)
+#include <sys/user.h>
+#endif
+#if defined(__mips__)
+// sys/user.h in eglibc misses size_t definition
+#include <stddef.h>
+#endif
+#endif
+
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h" // For AUDIT_ARCH_*
+
+// Impose some reasonable maximum BPF program size. Realistically, the
+// kernel probably has much lower limits. But by limiting to less than
+// 30 bits, we can ease requirements on some of our data types.
+#define SECCOMP_MAX_PROGRAM_SIZE (1<<30)
+
+#if defined(__i386__)
+#define SECCOMP_ARCH AUDIT_ARCH_I386
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, REG_EAX)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, REG_EAX)
+#define SECCOMP_IP(_ctx) SECCOMP_REG(_ctx, REG_EIP)
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, REG_EBX)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, REG_ECX)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, REG_EDX)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, REG_ESI)
+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, REG_EDI)
+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, REG_EBP)
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 0)
+
+
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly. This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
+struct regs_struct {
+ long int ebx;
+ long int ecx;
+ long int edx;
+ long int esi;
+ long int edi;
+ long int ebp;
+ long int eax;
+ long int xds;
+ long int xes;
+ long int xfs;
+ long int xgs;
+ long int orig_eax;
+ long int eip;
+ long int xcs;
+ long int eflags;
+ long int esp;
+ long int xss;
+};
+#else
+typedef user_regs_struct regs_struct;
+#endif
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).eax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_eax
+#define SECCOMP_PT_IP(_regs) (_regs).eip
+#define SECCOMP_PT_PARM1(_regs) (_regs).ebx
+#define SECCOMP_PT_PARM2(_regs) (_regs).ecx
+#define SECCOMP_PT_PARM3(_regs) (_regs).edx
+#define SECCOMP_PT_PARM4(_regs) (_regs).esi
+#define SECCOMP_PT_PARM5(_regs) (_regs).edi
+#define SECCOMP_PT_PARM6(_regs) (_regs).ebp
+
+#elif defined(__x86_64__)
+#define SECCOMP_ARCH AUDIT_ARCH_X86_64
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[(_reg)])
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, REG_RAX)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, REG_RAX)
+#define SECCOMP_IP(_ctx) SECCOMP_REG(_ctx, REG_RIP)
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, REG_RDI)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, REG_RSI)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, REG_RDX)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, REG_R10)
+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, REG_R8)
+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, REG_R9)
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 0)
+
+typedef user_regs_struct regs_struct;
+#define SECCOMP_PT_RESULT(_regs) (_regs).rax
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).orig_rax
+#define SECCOMP_PT_IP(_regs) (_regs).rip
+#define SECCOMP_PT_PARM1(_regs) (_regs).rdi
+#define SECCOMP_PT_PARM2(_regs) (_regs).rsi
+#define SECCOMP_PT_PARM3(_regs) (_regs).rdx
+#define SECCOMP_PT_PARM4(_regs) (_regs).r10
+#define SECCOMP_PT_PARM5(_regs) (_regs).r8
+#define SECCOMP_PT_PARM6(_regs) (_regs).r9
+
+#elif defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))
+#define SECCOMP_ARCH AUDIT_ARCH_ARM
+
+// ARM sigcontext_t is different from i386/x86_64.
+// See </arch/arm/include/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.arm_##_reg)
+// ARM EABI syscall convention.
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, r0)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, r7)
+#define SECCOMP_IP(_ctx) SECCOMP_REG(_ctx, pc)
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, r0)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, r1)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, r2)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, r3)
+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, r4)
+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, r5)
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 0)
+
+#if defined(__BIONIC__) || defined(__native_client_nonsfi__)
+// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just
+// define regs_struct directly. This can be removed once we no longer need to
+// support these old Bionic versions and PNaCl toolchain.
+struct regs_struct {
+ unsigned long uregs[18];
+};
+#else
+typedef user_regs regs_struct;
+#endif
+
+#define REG_cpsr uregs[16]
+#define REG_pc uregs[15]
+#define REG_lr uregs[14]
+#define REG_sp uregs[13]
+#define REG_ip uregs[12]
+#define REG_fp uregs[11]
+#define REG_r10 uregs[10]
+#define REG_r9 uregs[9]
+#define REG_r8 uregs[8]
+#define REG_r7 uregs[7]
+#define REG_r6 uregs[6]
+#define REG_r5 uregs[5]
+#define REG_r4 uregs[4]
+#define REG_r3 uregs[3]
+#define REG_r2 uregs[2]
+#define REG_r1 uregs[1]
+#define REG_r0 uregs[0]
+#define REG_ORIG_r0 uregs[17]
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).REG_r0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_r7
+#define SECCOMP_PT_IP(_regs) (_regs).REG_pc
+#define SECCOMP_PT_PARM1(_regs) (_regs).REG_r0
+#define SECCOMP_PT_PARM2(_regs) (_regs).REG_r1
+#define SECCOMP_PT_PARM3(_regs) (_regs).REG_r2
+#define SECCOMP_PT_PARM4(_regs) (_regs).REG_r3
+#define SECCOMP_PT_PARM5(_regs) (_regs).REG_r4
+#define SECCOMP_PT_PARM6(_regs) (_regs).REG_r5
+
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)
+#define SECCOMP_ARCH AUDIT_ARCH_MIPSEL
+#define SYSCALL_EIGHT_ARGS
+// MIPS sigcontext_t is different from i386/x86_64 and ARM.
+// See </arch/mips/include/uapi/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[_reg])
+// Based on MIPS o32 ABI syscall convention.
+// On MIPS, when indirect syscall is being made (syscall(__NR_foo)),
+// real identificator (__NR_foo) is not in v0, but in a0
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 5)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 6)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 7)
+// Only the first 4 arguments of syscall are in registers.
+// The rest are on the stack.
+#define SECCOMP_STACKPARM(_ctx, n) (((long *)SECCOMP_REG(_ctx, 29))[(n)])
+#define SECCOMP_PARM5(_ctx) SECCOMP_STACKPARM(_ctx, 4)
+#define SECCOMP_PARM6(_ctx) SECCOMP_STACKPARM(_ctx, 5)
+#define SECCOMP_PARM7(_ctx) SECCOMP_STACKPARM(_ctx, 6)
+#define SECCOMP_PARM8(_ctx) SECCOMP_STACKPARM(_ctx, 7)
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 0)
+
+// On MIPS we don't have structures like user_regs or user_regs_struct in
+// sys/user.h that we could use, so we just define regs_struct directly.
+struct regs_struct {
+ unsigned long long regs[32];
+};
+
+#define REG_a3 regs[7]
+#define REG_a2 regs[6]
+#define REG_a1 regs[5]
+#define REG_a0 regs[4]
+#define REG_v1 regs[3]
+#define REG_v0 regs[2]
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).REG_v0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_v0
+#define SECCOMP_PT_PARM1(_regs) (_regs).REG_a0
+#define SECCOMP_PT_PARM2(_regs) (_regs).REG_a1
+#define SECCOMP_PT_PARM3(_regs) (_regs).REG_a2
+#define SECCOMP_PT_PARM4(_regs) (_regs).REG_a3
+
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+#define SECCOMP_ARCH AUDIT_ARCH_MIPSEL64
+#define SYSCALL_EIGHT_ARGS
+// MIPS sigcontext_t is different from i386/x86_64 and ARM.
+// See </arch/mips/include/uapi/asm/sigcontext.h> in the Linux kernel.
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.gregs[_reg])
+// Based on MIPS n64 ABI syscall convention.
+// On MIPS, when an indirect syscall is being made (syscall(__NR_foo)),
+// the real identifier (__NR_foo) is not in v0, but in a0.
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 5)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 6)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 7)
+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, 8)
+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, 9)
+#define SECCOMP_PARM7(_ctx) SECCOMP_REG(_ctx, 10)
+#define SECCOMP_PARM8(_ctx) SECCOMP_REG(_ctx, 11)
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX (offsetof(struct arch_seccomp_data, \
+ instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \
+ 8*(nr) + 0)
+
+// On MIPS we don't have structures like user_regs or user_regs_struct in
+// sys/user.h that we could use, so we just define regs_struct directly.
+struct regs_struct {
+ unsigned long long regs[32];
+};
+
+#define REG_a7 regs[11]
+#define REG_a6 regs[10]
+#define REG_a5 regs[9]
+#define REG_a4 regs[8]
+#define REG_a3 regs[7]
+#define REG_a2 regs[6]
+#define REG_a1 regs[5]
+#define REG_a0 regs[4]
+#define REG_v1 regs[3]
+#define REG_v0 regs[2]
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).REG_v0
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).REG_v0
+#define SECCOMP_PT_PARM1(_regs) (_regs).REG_a0
+#define SECCOMP_PT_PARM2(_regs) (_regs).REG_a1
+#define SECCOMP_PT_PARM3(_regs) (_regs).REG_a2
+#define SECCOMP_PT_PARM4(_regs) (_regs).REG_a3
+#define SECCOMP_PT_PARM5(_regs) (_regs).REG_a4
+#define SECCOMP_PT_PARM6(_regs) (_regs).REG_a5
+#define SECCOMP_PT_PARM7(_regs) (_regs).REG_a6
+#define SECCOMP_PT_PARM8(_regs) (_regs).REG_a7
+
+#elif defined(__aarch64__)
+struct regs_struct {
+ unsigned long long regs[31];
+ unsigned long long sp;
+ unsigned long long pc;
+ unsigned long long pstate;
+};
+
+#define SECCOMP_ARCH AUDIT_ARCH_AARCH64
+
+#define SECCOMP_REG(_ctx, _reg) ((_ctx)->uc_mcontext.regs[_reg])
+
+#define SECCOMP_RESULT(_ctx) SECCOMP_REG(_ctx, 0)
+#define SECCOMP_SYSCALL(_ctx) SECCOMP_REG(_ctx, 8)
+#define SECCOMP_IP(_ctx) (_ctx)->uc_mcontext.pc
+#define SECCOMP_PARM1(_ctx) SECCOMP_REG(_ctx, 0)
+#define SECCOMP_PARM2(_ctx) SECCOMP_REG(_ctx, 1)
+#define SECCOMP_PARM3(_ctx) SECCOMP_REG(_ctx, 2)
+#define SECCOMP_PARM4(_ctx) SECCOMP_REG(_ctx, 3)
+#define SECCOMP_PARM5(_ctx) SECCOMP_REG(_ctx, 4)
+#define SECCOMP_PARM6(_ctx) SECCOMP_REG(_ctx, 5)
+
+#define SECCOMP_NR_IDX (offsetof(struct arch_seccomp_data, nr))
+#define SECCOMP_ARCH_IDX (offsetof(struct arch_seccomp_data, arch))
+#define SECCOMP_IP_MSB_IDX \
+ (offsetof(struct arch_seccomp_data, instruction_pointer) + 4)
+#define SECCOMP_IP_LSB_IDX \
+ (offsetof(struct arch_seccomp_data, instruction_pointer) + 0)
+#define SECCOMP_ARG_MSB_IDX(nr) \
+ (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 4)
+#define SECCOMP_ARG_LSB_IDX(nr) \
+ (offsetof(struct arch_seccomp_data, args) + 8 * (nr) + 0)
+
+#define SECCOMP_PT_RESULT(_regs) (_regs).regs[0]
+#define SECCOMP_PT_SYSCALL(_regs) (_regs).regs[8]
+#define SECCOMP_PT_IP(_regs) (_regs).pc
+#define SECCOMP_PT_PARM1(_regs) (_regs).regs[0]
+#define SECCOMP_PT_PARM2(_regs) (_regs).regs[1]
+#define SECCOMP_PT_PARM3(_regs) (_regs).regs[2]
+#define SECCOMP_PT_PARM4(_regs) (_regs).regs[3]
+#define SECCOMP_PT_PARM5(_regs) (_regs).regs[4]
+#define SECCOMP_PT_PARM6(_regs) (_regs).regs[5]
+#else
+#error Unsupported target platform
+
+#endif
+
+#endif // SANDBOX_LINUX_BPF_DSL_SECCOMP_MACROS_H_
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.cc b/security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.cc
new file mode 100644
index 0000000000..55b2d5a49a
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/linux_syscall_ranges.h"
+
+namespace sandbox {
+
+namespace {
+
+#if defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS)
+// This is true for Mips O32 ABI.
+static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 4000");
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+// This is true for MIPS N64 ABI.
+static_assert(MIN_SYSCALL == __NR_Linux, "min syscall number should be 5000");
+#else
+// This true for supported architectures (Intel and ARM EABI).
+static_assert(MIN_SYSCALL == 0u,
+ "min syscall should always be zero");
+#endif
+
+// SyscallRange represents an inclusive range of system call numbers.
+struct SyscallRange {
+ uint32_t first;
+ uint32_t last;
+};
+
+const SyscallRange kValidSyscallRanges[] = {
+ // First we iterate up to MAX_PUBLIC_SYSCALL, which is equal to MAX_SYSCALL
+ // on Intel architectures, but leaves room for private syscalls on ARM.
+ {MIN_SYSCALL, MAX_PUBLIC_SYSCALL},
+#if defined(__arm__)
+ // ARM EABI includes "ARM private" system calls starting at
+ // MIN_PRIVATE_SYSCALL, and a "ghost syscall private to the kernel" at
+ // MIN_GHOST_SYSCALL.
+ {MIN_PRIVATE_SYSCALL, MAX_PRIVATE_SYSCALL},
+ {MIN_GHOST_SYSCALL, MAX_SYSCALL},
+#endif
+};
+
+} // namespace
+
+SyscallSet::Iterator SyscallSet::begin() const {
+ return Iterator(set_, false);
+}
+
+SyscallSet::Iterator SyscallSet::end() const {
+ return Iterator(set_, true);
+}
+
+bool SyscallSet::IsValid(uint32_t num) {
+ for (const SyscallRange& range : kValidSyscallRanges) {
+ if (num >= range.first && num <= range.last) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool operator==(const SyscallSet& lhs, const SyscallSet& rhs) {
+ return (lhs.set_ == rhs.set_);
+}
+
+SyscallSet::Iterator::Iterator(Set set, bool done)
+ : set_(set), done_(done), num_(0) {
+ // If the set doesn't contain 0, we need to skip to the next element.
+ if (!done && set_ == (IsValid(num_) ? Set::INVALID_ONLY : Set::VALID_ONLY)) {
+ ++*this;
+ }
+}
+
+uint32_t SyscallSet::Iterator::operator*() const {
+ DCHECK(!done_);
+ return num_;
+}
+
+SyscallSet::Iterator& SyscallSet::Iterator::operator++() {
+ DCHECK(!done_);
+
+ num_ = NextSyscall();
+ if (num_ == 0) {
+ done_ = true;
+ }
+
+ return *this;
+}
+
+// NextSyscall returns the next system call in the iterated system
+// call set after |num_|, or 0 if no such system call exists.
+uint32_t SyscallSet::Iterator::NextSyscall() const {
+ const bool want_valid = (set_ != Set::INVALID_ONLY);
+ const bool want_invalid = (set_ != Set::VALID_ONLY);
+
+ for (const SyscallRange& range : kValidSyscallRanges) {
+ if (want_invalid && range.first > 0 && num_ < range.first - 1) {
+ // Even when iterating invalid syscalls, we only include the end points;
+ // so skip directly to just before the next (valid) range.
+ return range.first - 1;
+ }
+ if (want_valid && num_ < range.first) {
+ return range.first;
+ }
+ if (want_valid && num_ < range.last) {
+ return num_ + 1;
+ }
+ if (want_invalid && num_ <= range.last) {
+ return range.last + 1;
+ }
+ }
+
+ if (want_invalid) {
+ // BPF programs only ever operate on unsigned quantities. So,
+ // that's how we iterate; we return values from
+ // 0..0xFFFFFFFFu. But there are places, where the kernel might
+ // interpret system call numbers as signed quantities, so the
+ // boundaries between signed and unsigned values are potential
+ // problem cases. We want to explicitly return these values from
+ // our iterator.
+ if (num_ < 0x7FFFFFFFu)
+ return 0x7FFFFFFFu;
+ if (num_ < 0x80000000u)
+ return 0x80000000u;
+
+ if (num_ < 0xFFFFFFFFu)
+ return 0xFFFFFFFFu;
+ }
+
+ return 0;
+}
+
+bool operator==(const SyscallSet::Iterator& lhs,
+ const SyscallSet::Iterator& rhs) {
+ DCHECK(lhs.set_ == rhs.set_);
+ return (lhs.done_ == rhs.done_) && (lhs.num_ == rhs.num_);
+}
+
+bool operator!=(const SyscallSet::Iterator& lhs,
+ const SyscallSet::Iterator& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.h
new file mode 100644
index 0000000000..b9f076d932
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/syscall_set.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
+#define SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
+
+#include <stdint.h>
+
+#include <iterator>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// Iterates over the entire system call range from 0..0xFFFFFFFFu. This
+// iterator is aware of how system calls look like and will skip quickly
+// over ranges that can't contain system calls. It iterates more slowly
+// whenever it reaches a range that is potentially problematic, returning
+// the last invalid value before a valid range of system calls, and the
+// first invalid value after a valid range of syscalls. It iterates over
+// individual values whenever it is in the normal range for system calls
+// (typically MIN_SYSCALL..MAX_SYSCALL).
+//
+// Example usage:
+// for (uint32_t sysnum : SyscallSet::All()) {
+// // Do something with sysnum.
+// }
+class SANDBOX_EXPORT SyscallSet {
+ public:
+ class Iterator;
+
+ SyscallSet(const SyscallSet& ss) : set_(ss.set_) {}
+ ~SyscallSet() {}
+
+ Iterator begin() const;
+ Iterator end() const;
+
+ // All returns a SyscallSet that contains both valid and invalid
+ // system call numbers.
+ static SyscallSet All() { return SyscallSet(Set::ALL); }
+
+ // ValidOnly returns a SyscallSet that contains only valid system
+ // call numbers.
+ static SyscallSet ValidOnly() { return SyscallSet(Set::VALID_ONLY); }
+
+ // InvalidOnly returns a SyscallSet that contains only invalid
+ // system call numbers, but still omits numbers in the middle of a
+ // range of invalid system call numbers.
+ static SyscallSet InvalidOnly() { return SyscallSet(Set::INVALID_ONLY); }
+
+ // IsValid returns whether |num| specifies a valid system call
+ // number.
+ static bool IsValid(uint32_t num);
+
+ private:
+ enum class Set { ALL, VALID_ONLY, INVALID_ONLY };
+
+ explicit SyscallSet(Set set) : set_(set) {}
+
+ Set set_;
+
+ friend bool operator==(const SyscallSet&, const SyscallSet&);
+ DISALLOW_ASSIGN(SyscallSet);
+};
+
+SANDBOX_EXPORT bool operator==(const SyscallSet& lhs, const SyscallSet& rhs);
+
+// Iterator provides C++ input iterator semantics for traversing a
+// SyscallSet.
+class SyscallSet::Iterator
+ : public std::iterator<std::input_iterator_tag, uint32_t> {
+ public:
+ Iterator(const Iterator& it)
+ : set_(it.set_), done_(it.done_), num_(it.num_) {}
+ ~Iterator() {}
+
+ uint32_t operator*() const;
+ Iterator& operator++();
+
+ private:
+ Iterator(Set set, bool done);
+
+ uint32_t NextSyscall() const;
+
+ Set set_;
+ bool done_;
+ uint32_t num_;
+
+ friend SyscallSet;
+ friend bool operator==(const Iterator&, const Iterator&);
+ DISALLOW_ASSIGN(Iterator);
+};
+
+SANDBOX_EXPORT bool operator==(const SyscallSet::Iterator& lhs,
+ const SyscallSet::Iterator& rhs);
+SANDBOX_EXPORT bool operator!=(const SyscallSet::Iterator& lhs,
+ const SyscallSet::Iterator& rhs);
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_SYSCALL_SET_H__
diff --git a/security/sandbox/chromium/sandbox/linux/bpf_dsl/trap_registry.h b/security/sandbox/chromium/sandbox/linux/bpf_dsl/trap_registry.h
new file mode 100644
index 0000000000..0a5d2f14cc
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/bpf_dsl/trap_registry.h
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
+#define SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This must match the kernel's seccomp_data structure.
+struct arch_seccomp_data {
+ int nr;
+ uint32_t arch;
+ uint64_t instruction_pointer;
+ uint64_t args[6];
+};
+
+namespace bpf_dsl {
+
+// TrapRegistry provides an interface for registering "trap handlers"
+// by associating them with non-zero 16-bit trap IDs. Trap IDs should
+// remain valid for the lifetime of the trap registry.
+class SANDBOX_EXPORT TrapRegistry {
+ public:
+ // TrapFnc is a pointer to a function that fulfills the trap handler
+ // function signature.
+ //
+ // Trap handlers follow the calling convention of native system
+ // calls; e.g., to report an error, they return an exit code in the
+ // range -1..-4096 instead of directly modifying errno. However,
+ // modifying errno is harmless, as the original value will be
+ // restored afterwards.
+ //
+ // Trap handlers are executed from signal context and possibly an
+ // async-signal context, so they must be async-signal safe:
+ // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
+ typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void* aux);
+
+ // Add registers the specified trap handler tuple and returns a
+ // non-zero trap ID that uniquely identifies the tuple for the life
+ // time of the trap registry. If the same tuple is registered
+ // multiple times, the same value will be returned each time.
+ virtual uint16_t Add(TrapFnc fnc, const void* aux, bool safe) = 0;
+
+ // EnableUnsafeTraps tries to enable unsafe traps and returns
+ // whether it was successful. This is a one-way operation.
+ //
+ // CAUTION: Enabling unsafe traps effectively defeats the security
+ // guarantees provided by the sandbox policy. TrapRegistry
+ // implementations should ensure unsafe traps are only enabled
+ // during testing.
+ virtual bool EnableUnsafeTraps() = 0;
+
+ protected:
+ TrapRegistry() {}
+
+ // TrapRegistry's destructor is intentionally non-virtual so that
+ // implementations can omit their destructor. Instead we protect against
+ // misuse by marking it protected.
+ ~TrapRegistry() {}
+
+ DISALLOW_COPY_AND_ASSIGN(TrapRegistry);
+};
+
+} // namespace bpf_dsl
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_BPF_DSL_TRAP_REGISTRY_H_
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
new file mode 100644
index 0000000000..a4315ba3c2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h
@@ -0,0 +1,56 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h"
+
+namespace sandbox {
+
+// This templated class allows building a BPFTesterDelegate from a
+// deprecated-style BPF policy (that is a SyscallEvaluator function pointer,
+// instead of a SandboxBPFPolicy class), specified in |policy_function| and a
+// function pointer to a test in |test_function|.
+// This allows both the policy and the test function to take a pointer to an
+// object of type "Aux" as a parameter. This is used to implement the BPF_TEST
+// macro and should generally not be used directly.
+template <class Policy, class Aux>
+class BPFTesterCompatibilityDelegate : public BPFTesterDelegate {
+ public:
+ typedef void (*TestFunction)(Aux*);
+
+ explicit BPFTesterCompatibilityDelegate(TestFunction test_function)
+ : aux_(), test_function_(test_function) {}
+
+ ~BPFTesterCompatibilityDelegate() override {}
+
+ std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+ // The current method is guaranteed to only run in the child process
+ // running the test. In this process, the current object is guaranteed
+ // to live forever. So it's ok to pass aux_pointer_for_policy_ to
+ // the policy, which could in turn pass it to the kernel via Trap().
+ return std::unique_ptr<bpf_dsl::Policy>(new Policy(&aux_));
+ }
+
+ void RunTestFunction() override {
+ // Run the actual test.
+ // The current object is guaranteed to live forever in the child process
+ // where this will run.
+ test_function_(&aux_);
+ }
+
+ private:
+ Aux aux_;
+ TestFunction test_function_;
+
+ DISALLOW_COPY_AND_ASSIGN(BPFTesterCompatibilityDelegate);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTER_COMPATIBILITY_DELEGATE_H_
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h
new file mode 100644
index 0000000000..8b2b12afd8
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tester_compatibility_delegate.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+// BPF_TEST_C() is a special version of SANDBOX_TEST(). It runs a test function
+// in a sub-process, under a seccomp-bpf policy specified in
+// |bpf_policy_class_name| without failing on configurations that are allowed
+// to not support seccomp-bpf in their kernels.
+// This is the preferred format for new BPF tests. |bpf_policy_class_name| is a
+// class name (which will be default-constructed) that implements the
+// Policy interface.
+// The test function's body can simply follow. Test functions should use
+// the BPF_ASSERT macros defined below, not GTEST's macros. The use of
+// CHECK* macros is supported but less robust.
+#define BPF_TEST_C(test_case_name, test_name, bpf_policy_class_name) \
+ BPF_DEATH_TEST_C( \
+ test_case_name, test_name, DEATH_SUCCESS(), bpf_policy_class_name)
+
+// Identical to BPF_TEST_C but allows to specify the nature of death.
+#define BPF_DEATH_TEST_C( \
+ test_case_name, test_name, death, bpf_policy_class_name) \
+ void BPF_TEST_C_##test_name(); \
+ TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \
+ sandbox::SandboxBPFTestRunner bpf_test_runner( \
+ new sandbox::BPFTesterSimpleDelegate<bpf_policy_class_name>( \
+ BPF_TEST_C_##test_name)); \
+ sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
+ } \
+ void BPF_TEST_C_##test_name()
+
+// This form of BPF_TEST is a little verbose and should be reserved for complex
+// tests where a lot of control is required.
+// |bpf_tester_delegate_class| must be a classname implementing the
+// BPFTesterDelegate interface.
+#define BPF_TEST_D(test_case_name, test_name, bpf_tester_delegate_class) \
+ BPF_DEATH_TEST_D( \
+ test_case_name, test_name, DEATH_SUCCESS(), bpf_tester_delegate_class)
+
+// Identical to BPF_TEST_D but allows to specify the nature of death.
+#define BPF_DEATH_TEST_D( \
+ test_case_name, test_name, death, bpf_tester_delegate_class) \
+ TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \
+ sandbox::SandboxBPFTestRunner bpf_test_runner( \
+ new bpf_tester_delegate_class()); \
+ sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
+ }
+
+// Assertions are handled exactly the same as with a normal SANDBOX_TEST()
+#define BPF_ASSERT SANDBOX_ASSERT
+#define BPF_ASSERT_EQ(x, y) BPF_ASSERT((x) == (y))
+#define BPF_ASSERT_NE(x, y) BPF_ASSERT((x) != (y))
+#define BPF_ASSERT_LT(x, y) BPF_ASSERT((x) < (y))
+#define BPF_ASSERT_GT(x, y) BPF_ASSERT((x) > (y))
+#define BPF_ASSERT_LE(x, y) BPF_ASSERT((x) <= (y))
+#define BPF_ASSERT_GE(x, y) BPF_ASSERT((x) >= (y))
+
+// This form of BPF_TEST is now discouraged (but still allowed) in favor of
+// BPF_TEST_D and BPF_TEST_C.
+// The |policy| parameter should be a Policy subclass.
+// BPF_TEST() takes a C++ data type as an fourth parameter. A variable
+// of this type will be allocated and a pointer to it will be
+// available within the test function as "BPF_AUX". The pointer will
+// also be passed as an argument to the policy's constructor. Policies
+// would typically use it as an argument to SandboxBPF::Trap(), if
+// they want to communicate data between the BPF_TEST() and a Trap()
+// function. The life-time of this object is the same as the life-time
+// of the process running under the seccomp-bpf policy.
+// |aux| must not be void.
+#define BPF_TEST(test_case_name, test_name, policy, aux) \
+ BPF_DEATH_TEST(test_case_name, test_name, DEATH_SUCCESS(), policy, aux)
+
+// A BPF_DEATH_TEST is just the same as a BPF_TEST, but it assumes that the
+// test will fail with a particular known error condition. Use the DEATH_XXX()
+// macros from unit_tests.h to specify the expected error condition.
+#define BPF_DEATH_TEST(test_case_name, test_name, death, policy, aux) \
+ void BPF_TEST_##test_name(aux* BPF_AUX); \
+ TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \
+ sandbox::SandboxBPFTestRunner bpf_test_runner( \
+ new sandbox::BPFTesterCompatibilityDelegate<policy, aux>( \
+ BPF_TEST_##test_name)); \
+ sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \
+ } \
+ void BPF_TEST_##test_name(aux* BPF_AUX)
+
+// This class takes a simple function pointer as a constructor parameter and a
+// class name as a template parameter to implement the BPFTesterDelegate
+// interface which can be used to build BPF unittests with
+// the SandboxBPFTestRunner class.
+template <class PolicyClass>
+class BPFTesterSimpleDelegate : public BPFTesterDelegate {
+ public:
+ explicit BPFTesterSimpleDelegate(void (*test_function)(void))
+ : test_function_(test_function) {}
+ ~BPFTesterSimpleDelegate() override {}
+
+ std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+ return std::unique_ptr<bpf_dsl::Policy>(new PolicyClass());
+ }
+ void RunTestFunction() override {
+ DCHECK(test_function_);
+ test_function_();
+ }
+
+ private:
+ void (*test_function_)(void);
+ DISALLOW_COPY_AND_ASSIGN(BPFTesterSimpleDelegate);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SECCOMP_BPF_BPF_TESTS_H__
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
new file mode 100644
index 0000000000..d45bc87292
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+
+#include <errno.h>
+#include <sys/ptrace.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::Error;
+using sandbox::bpf_dsl::ResultExpr;
+
+namespace sandbox {
+
+namespace {
+
+class FourtyTwo {
+ public:
+ static const int kMagicValue = 42;
+ FourtyTwo() : value_(kMagicValue) {}
+ int value() { return value_; }
+
+ private:
+ int value_;
+ DISALLOW_COPY_AND_ASSIGN(FourtyTwo);
+};
+
+class EmptyClassTakingPolicy : public bpf_dsl::Policy {
+ public:
+ explicit EmptyClassTakingPolicy(FourtyTwo* fourty_two) {
+ BPF_ASSERT(fourty_two);
+ BPF_ASSERT(FourtyTwo::kMagicValue == fourty_two->value());
+ }
+ ~EmptyClassTakingPolicy() override {}
+
+ ResultExpr EvaluateSyscall(int sysno) const override {
+ DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+ return Allow();
+ }
+};
+
+BPF_TEST(BPFTest,
+ BPFAUXPointsToClass,
+ EmptyClassTakingPolicy,
+ FourtyTwo /* *BPF_AUX */) {
+ // BPF_AUX should point to an instance of FourtyTwo.
+ BPF_ASSERT(BPF_AUX);
+ BPF_ASSERT(FourtyTwo::kMagicValue == BPF_AUX->value());
+}
+
+void DummyTestFunction(FourtyTwo *fourty_two) {
+}
+
+TEST(BPFTest, BPFTesterCompatibilityDelegateLeakTest) {
+ // Don't do anything, simply gives dynamic tools an opportunity to detect
+ // leaks.
+ {
+ BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>
+ simple_delegate(DummyTestFunction);
+ }
+ {
+ // Test polymorphism.
+ std::unique_ptr<BPFTesterDelegate> simple_delegate(
+ new BPFTesterCompatibilityDelegate<EmptyClassTakingPolicy, FourtyTwo>(
+ DummyTestFunction));
+ }
+}
+
+class EnosysPtracePolicy : public bpf_dsl::Policy {
+ public:
+ EnosysPtracePolicy() { my_pid_ = sys_getpid(); }
+ ~EnosysPtracePolicy() override {
+ // Policies should be able to bind with the process on which they are
+ // created. They should never be created in a parent process.
+ BPF_ASSERT_EQ(my_pid_, sys_getpid());
+ }
+
+ ResultExpr EvaluateSyscall(int system_call_number) const override {
+ CHECK(SandboxBPF::IsValidSyscallNumber(system_call_number));
+ if (system_call_number == __NR_ptrace) {
+ // The EvaluateSyscall function should run in the process that created
+ // the current object.
+ BPF_ASSERT_EQ(my_pid_, sys_getpid());
+ return Error(ENOSYS);
+ } else {
+ return Allow();
+ }
+ }
+
+ private:
+ pid_t my_pid_;
+ DISALLOW_COPY_AND_ASSIGN(EnosysPtracePolicy);
+};
+
+class BasicBPFTesterDelegate : public BPFTesterDelegate {
+ public:
+ BasicBPFTesterDelegate() {}
+ ~BasicBPFTesterDelegate() override {}
+
+ std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() override {
+ return std::unique_ptr<bpf_dsl::Policy>(new EnosysPtracePolicy());
+ }
+ void RunTestFunction() override {
+ errno = 0;
+ int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
+ BPF_ASSERT(-1 == ret);
+ BPF_ASSERT(ENOSYS == errno);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BasicBPFTesterDelegate);
+};
+
+// This is the most powerful and complex way to create a BPF test, but it
+// requires a full class definition (BasicBPFTesterDelegate).
+BPF_TEST_D(BPFTest, BPFTestWithDelegateClass, BasicBPFTesterDelegate)
+
+// This is the simplest form of BPF tests.
+BPF_TEST_C(BPFTest, BPFTestWithInlineTest, EnosysPtracePolicy) {
+ errno = 0;
+ int ret = ptrace(PTRACE_TRACEME, -1, NULL, NULL);
+ BPF_ASSERT(-1 == ret);
+ BPF_ASSERT(ENOSYS == errno);
+}
+
+const char kHelloMessage[] = "Hello";
+
+BPF_DEATH_TEST_C(BPFTest,
+ BPFDeathTestWithInlineTest,
+ DEATH_MESSAGE(kHelloMessage),
+ EnosysPtracePolicy) {
+ LOG(ERROR) << kHelloMessage;
+ _exit(1);
+}
+
+} // namespace
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.cc
new file mode 100644
index 0000000000..3baf1f13d9
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/die.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace sandbox {
+
+void Die::ExitGroup() {
+ // exit_group() should exit our program. After all, it is defined as a
+ // function that doesn't return. But things can theoretically go wrong.
+ // Especially, since we are dealing with system call filters. Continuing
+ // execution would be very bad in most cases where ExitGroup() gets called.
+ // So, we'll try a few other strategies too.
+ Syscall::Call(__NR_exit_group, 1);
+
+ // We have no idea what our run-time environment looks like. So, signal
+ // handlers might or might not do the right thing. Try to reset settings
+ // to a defined state; but we have not way to verify whether we actually
+ // succeeded in doing so. Nonetheless, triggering a fatal signal could help
+ // us terminate.
+ struct sigaction sa = {};
+ sa.sa_handler = LINUX_SIG_DFL;
+ sa.sa_flags = LINUX_SA_RESTART;
+ sys_sigaction(LINUX_SIGSEGV, &sa, nullptr);
+ Syscall::Call(__NR_prctl, PR_SET_DUMPABLE, (void*)0, (void*)0, (void*)0);
+ if (*(volatile char*)0) {
+ }
+
+ // If there is no way for us to ask for the program to exit, the next
+ // best thing we can do is to loop indefinitely. Maybe, somebody will notice
+ // and file a bug...
+ // We in fact retry the system call inside of our loop so that it will
+ // stand out when somebody tries to diagnose the problem by using "strace".
+ for (;;) {
+ Syscall::Call(__NR_exit_group, 1);
+ }
+}
+
+void Die::SandboxDie(const char* msg, const char* file, int line) {
+ if (simple_exit_) {
+ LogToStderr(msg, file, line);
+ } else {
+ logging::LogMessage(file, line, logging::LOG_FATAL).stream() << msg;
+ }
+ ExitGroup();
+}
+
+void Die::RawSandboxDie(const char* msg) {
+ if (!msg)
+ msg = "";
+ RAW_LOG(FATAL, msg);
+ ExitGroup();
+}
+
+void Die::SandboxInfo(const char* msg, const char* file, int line) {
+ if (!suppress_info_) {
+ logging::LogMessage(file, line, logging::LOG_INFO).stream() << msg;
+ }
+}
+
+void Die::LogToStderr(const char* msg, const char* file, int line) {
+ if (msg) {
+ char buf[40];
+ snprintf(buf, sizeof(buf), "%d", line);
+ std::string s = std::string(file) + ":" + buf + ":" + msg + "\n";
+
+ // No need to loop. Short write()s are unlikely and if they happen we
+ // probably prefer them over a loop that blocks.
+ ignore_result(
+ HANDLE_EINTR(Syscall::Call(__NR_write, 2, s.c_str(), s.length())));
+ }
+}
+
+bool Die::simple_exit_ = false;
+bool Die::suppress_info_ = false;
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.h b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.h
new file mode 100644
index 0000000000..b3f3f72c2f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/die.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
+
+#include "base/macros.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This is the main API for using this file. Prints a error message and
+// exits with a fatal error. This is not async-signal safe.
+#define SANDBOX_DIE(m) sandbox::Die::SandboxDie(m, __FILE__, __LINE__)
+
+// An async signal safe version of the same API. Won't print the filename
+// and line numbers.
+#define RAW_SANDBOX_DIE(m) sandbox::Die::RawSandboxDie(m)
+
+// Adds an informational message to the log file or stderr as appropriate.
+#define SANDBOX_INFO(m) sandbox::Die::SandboxInfo(m, __FILE__, __LINE__)
+
+class SANDBOX_EXPORT Die {
+ public:
+ // Terminate the program, even if the current sandbox policy prevents some
+ // of the more commonly used functions used for exiting.
+ // Most users would want to call SANDBOX_DIE() instead, as it logs extra
+ // information. But calling ExitGroup() is correct and in some rare cases
+ // preferable. So, we make it part of the public API.
+ static void ExitGroup() __attribute__((noreturn));
+
+ // This method gets called by SANDBOX_DIE(). There is normally no reason
+ // to call it directly unless you are defining your own exiting macro.
+ static void SandboxDie(const char* msg, const char* file, int line)
+ __attribute__((noreturn));
+
+ static void RawSandboxDie(const char* msg) __attribute__((noreturn));
+
+ // This method gets called by SANDBOX_INFO(). There is normally no reason
+ // to call it directly unless you are defining your own logging macro.
+ static void SandboxInfo(const char* msg, const char* file, int line);
+
+ // Writes a message to stderr. Used as a fall-back choice, if we don't have
+ // any other way to report an error.
+ static void LogToStderr(const char* msg, const char* file, int line);
+
+ // We generally want to run all exit handlers. This means, on SANDBOX_DIE()
+ // we should be calling LOG(FATAL). But there are some situations where
+ // we just need to print a message and then terminate. This would typically
+ // happen in cases where we consume the error message internally (e.g. in
+ // unit tests or in the supportsSeccompSandbox() method).
+ static void EnableSimpleExit() { simple_exit_ = true; }
+
+ // Sometimes we need to disable all informational messages (e.g. from within
+ // unittests).
+ static void SuppressInfoMessages(bool flag) { suppress_info_ = flag; }
+
+ private:
+ static bool simple_exit_;
+ static bool suppress_info_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Die);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SECCOMP_BPF_DIE_H__
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
new file mode 100644
index 0000000000..72a79670d3
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -0,0 +1,259 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/bpf_dsl/policy_compiler.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/bpf_dsl/syscall_set.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
+#include "sandbox/linux/services/proc_util.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/services/thread_helpers.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+namespace {
+
+// Check if the kernel supports seccomp-filter (a.k.a. seccomp mode 2) via
+// prctl().
+bool KernelSupportsSeccompBPF() {
+ errno = 0;
+ const int rv = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, nullptr);
+
+ if (rv == -1 && EFAULT == errno) {
+ return true;
+ }
+ return false;
+}
+
+// LG introduced a buggy syscall, sys_set_media_ext, with the same number as
+// seccomp. Return true if the current kernel has this buggy syscall.
+//
+// We want this to work with upcoming versions of seccomp, so we pass bogus
+// flags that are unlikely to ever be used by the kernel. A normal kernel would
+// return -EINVAL, but a buggy LG kernel would return 1.
+bool KernelHasLGBug() {
+#if defined(OS_ANDROID)
+ // sys_set_media will see this as NULL, which should be a safe (non-crashing)
+ // way to invoke it. A genuine seccomp syscall will see it as
+ // SECCOMP_SET_MODE_STRICT.
+ const unsigned int operation = 0;
+ // Chosen by fair dice roll. Guaranteed to be random.
+ const unsigned int flags = 0xf7a46a5c;
+ const int rv = sys_seccomp(operation, flags, nullptr);
+ // A genuine kernel would return -EINVAL (which would set rv to -1 and errno
+ // to EINVAL), or at the very least return some kind of error (which would
+ // set rv to -1). Any other behavior indicates that whatever code received
+ // our syscall was not the real seccomp.
+ if (rv != -1) {
+ return true;
+ }
+#endif // defined(OS_ANDROID)
+
+ return false;
+}
+
+// Check if the kernel supports seccomp-filter via the seccomp system call
+// and the TSYNC feature to enable seccomp on all threads.
+bool KernelSupportsSeccompTsync() {
+ if (KernelHasLGBug()) {
+ return false;
+ }
+
+ errno = 0;
+ const int rv =
+ sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, nullptr);
+
+ if (rv == -1 && errno == EFAULT) {
+ return true;
+ }
+
+ DCHECK_EQ(-1, rv);
+ DCHECK(ENOSYS == errno || EINVAL == errno);
+ return false;
+}
+
+uint64_t EscapePC() {
+ intptr_t rv = Syscall::Call(-1);
+ if (rv == -1 && errno == ENOSYS) {
+ return 0;
+ }
+ return static_cast<uint64_t>(static_cast<uintptr_t>(rv));
+}
+
+intptr_t SandboxPanicTrap(const struct arch_seccomp_data&, void* aux) {
+ SANDBOX_DIE(static_cast<const char*>(aux));
+}
+
+bpf_dsl::ResultExpr SandboxPanic(const char* error) {
+ return bpf_dsl::Trap(SandboxPanicTrap, error);
+}
+
+} // namespace
+
+SandboxBPF::SandboxBPF(std::unique_ptr<bpf_dsl::Policy> policy)
+ : proc_fd_(), sandbox_has_started_(false), policy_(std::move(policy)) {}
+
+SandboxBPF::~SandboxBPF() {
+}
+
+// static
+bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
+ switch (level) {
+ case SeccompLevel::SINGLE_THREADED:
+ return KernelSupportsSeccompBPF();
+ case SeccompLevel::MULTI_THREADED:
+ return KernelSupportsSeccompTsync();
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool SandboxBPF::StartSandbox(SeccompLevel seccomp_level) {
+ DCHECK(policy_);
+ CHECK(seccomp_level == SeccompLevel::SINGLE_THREADED ||
+ seccomp_level == SeccompLevel::MULTI_THREADED);
+
+ if (sandbox_has_started_) {
+ SANDBOX_DIE(
+ "Cannot repeatedly start sandbox. Create a separate Sandbox "
+ "object instead.");
+ return false;
+ }
+
+ if (!proc_fd_.is_valid()) {
+ SetProcFd(ProcUtil::OpenProc());
+ }
+
+ const bool supports_tsync = KernelSupportsSeccompTsync();
+
+ if (seccomp_level == SeccompLevel::SINGLE_THREADED) {
+ // Wait for /proc/self/task/ to update if needed and assert the
+ // process is single threaded.
+ ThreadHelpers::AssertSingleThreaded(proc_fd_.get());
+ } else if (seccomp_level == SeccompLevel::MULTI_THREADED) {
+ if (!supports_tsync) {
+ SANDBOX_DIE("Cannot start sandbox; kernel does not support synchronizing "
+ "filters for a threadgroup");
+ return false;
+ }
+ }
+
+ // We no longer need access to any files in /proc. We want to do this
+ // before installing the filters, just in case that our policy denies
+ // close().
+ if (proc_fd_.is_valid()) {
+ proc_fd_.reset();
+ }
+
+ // Install the filters.
+ InstallFilter(supports_tsync ||
+ seccomp_level == SeccompLevel::MULTI_THREADED);
+
+ return true;
+}
+
+void SandboxBPF::SetProcFd(base::ScopedFD proc_fd) {
+ proc_fd_.swap(proc_fd);
+}
+
+// static
+bool SandboxBPF::IsValidSyscallNumber(int sysnum) {
+ return SyscallSet::IsValid(sysnum);
+}
+
+// static
+bool SandboxBPF::IsRequiredForUnsafeTrap(int sysno) {
+ return bpf_dsl::PolicyCompiler::IsRequiredForUnsafeTrap(sysno);
+}
+
+// static
+intptr_t SandboxBPF::ForwardSyscall(const struct arch_seccomp_data& args) {
+ return Syscall::Call(
+ args.nr, static_cast<intptr_t>(args.args[0]),
+ static_cast<intptr_t>(args.args[1]), static_cast<intptr_t>(args.args[2]),
+ static_cast<intptr_t>(args.args[3]), static_cast<intptr_t>(args.args[4]),
+ static_cast<intptr_t>(args.args[5]));
+}
+
+CodeGen::Program SandboxBPF::AssembleFilter() {
+ DCHECK(policy_);
+
+ bpf_dsl::PolicyCompiler compiler(policy_.get(), Trap::Registry());
+ if (Trap::SandboxDebuggingAllowedByUser()) {
+ compiler.DangerousSetEscapePC(EscapePC());
+ }
+ compiler.SetPanicFunc(SandboxPanic);
+ return compiler.Compile();
+}
+
+void SandboxBPF::InstallFilter(bool must_sync_threads) {
+ // We want to be very careful in not imposing any requirements on the
+ // policies that are set with SetSandboxPolicy(). This means, as soon as
+ // the sandbox is active, we shouldn't be relying on libraries that could
+ // be making system calls. This, for example, means we should avoid
+ // using the heap and we should avoid using STL functions.
+ // Temporarily copy the contents of the "program" vector into a
+ // stack-allocated array; and then explicitly destroy that object.
+ // This makes sure we don't ex- or implicitly call new/delete after we
+ // installed the BPF filter program in the kernel. Depending on the
+ // system memory allocator that is in effect, these operators can result
+ // in system calls to things like munmap() or brk().
+ CodeGen::Program program = AssembleFilter();
+
+ struct sock_filter bpf[program.size()];
+ const struct sock_fprog prog = {static_cast<unsigned short>(program.size()),
+ bpf};
+ memcpy(bpf, &program[0], sizeof(bpf));
+ CodeGen::Program().swap(program); // vector swap trick
+
+ // Make an attempt to release memory that is no longer needed here, rather
+ // than in the destructor. Try to avoid as much as possible to presume of
+ // what will be possible to do in the new (sandboxed) execution environment.
+ policy_.reset();
+
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+ SANDBOX_DIE("Kernel refuses to enable no-new-privs");
+ }
+
+ // Install BPF filter program. If the thread state indicates multi-threading
+ // support, then the kernel hass the seccomp system call. Otherwise, fall
+ // back on prctl, which requires the process to be single-threaded.
+ if (must_sync_threads) {
+ int rv =
+ sys_seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
+ if (rv) {
+ SANDBOX_DIE(
+ "Kernel refuses to turn on and synchronize threads for BPF filters");
+ }
+ } else {
+ if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) {
+ SANDBOX_DIE("Kernel refuses to turn on BPF filters");
+ }
+ }
+
+ sandbox_has_started_ = true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h
new file mode 100644
index 0000000000..282852992b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/codegen.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+struct arch_seccomp_data;
+
+// This class can be used to apply a syscall sandboxing policy expressed in a
+// bpf_dsl::Policy object to the current process.
+// Syscall sandboxing policies get inherited by subprocesses and, once applied,
+// can never be removed for the lifetime of the process.
+class SANDBOX_EXPORT SandboxBPF {
+ public:
+ enum class SeccompLevel {
+ SINGLE_THREADED,
+ MULTI_THREADED,
+ };
+
+ // Ownership of |policy| is transfered here to the sandbox object.
+ // nullptr is allowed for unit tests.
+ explicit SandboxBPF(std::unique_ptr<bpf_dsl::Policy> policy);
+ // NOTE: Setting a policy and starting the sandbox is a one-way operation.
+ // The kernel does not provide any option for unloading a loaded sandbox. The
+ // sandbox remains engaged even when the object is destructed.
+ ~SandboxBPF();
+
+ // Detect if the kernel supports the specified seccomp level.
+ // See StartSandbox() for a description of these.
+ static bool SupportsSeccompSandbox(SeccompLevel level);
+
+ // This is the main public entry point. It sets up the resources needed by
+ // the sandbox, and enters Seccomp mode.
+ // The calling process must provide a |level| to tell the sandbox which type
+ // of kernel support it should engage.
+ // SINGLE_THREADED will only sandbox the calling thread. Since it would be a
+ // security risk, the sandbox will also check that the current process is
+ // single threaded and crash if it isn't the case.
+ // MULTI_THREADED requires more recent kernel support and allows to sandbox
+ // all the threads of the current process. Be mindful of potential races,
+ // with other threads using disallowed system calls either before or after
+ // the sandbox is engaged.
+ //
+ // It is possible to stack multiple sandboxes by creating separate "Sandbox"
+ // objects and calling "StartSandbox()" on each of them. Please note, that
+ // this requires special care, though, as newly stacked sandboxes can never
+ // relax restrictions imposed by earlier sandboxes. Furthermore, installing
+ // a new policy requires making system calls, that might already be
+ // disallowed.
+ // Finally, stacking does add more kernel overhead than having a single
+ // combined policy. So, it should only be used if there are no alternatives.
+ bool StartSandbox(SeccompLevel level) WARN_UNUSED_RESULT;
+
+ // The sandbox needs to be able to access files in "/proc/self/". If
+ // this directory is not accessible when "StartSandbox()" gets called, the
+ // caller must provide an already opened file descriptor by calling
+ // "SetProcFd()".
+ // The sandbox becomes the new owner of this file descriptor and will
+ // close it when "StartSandbox()" executes or when the sandbox object
+ // disappears.
+ void SetProcFd(base::ScopedFD proc_fd);
+
+ // Checks whether a particular system call number is valid on the current
+ // architecture.
+ static bool IsValidSyscallNumber(int sysnum);
+
+ // UnsafeTraps require some syscalls to always be allowed.
+ // This helper function returns true for these calls.
+ static bool IsRequiredForUnsafeTrap(int sysno);
+
+ // From within an UnsafeTrap() it is often useful to be able to execute
+ // the system call that triggered the trap. The ForwardSyscall() method
+ // makes this easy. It is more efficient than calling glibc's syscall()
+ // function, as it avoid the extra round-trip to the signal handler. And
+ // it automatically does the correct thing to report kernel-style error
+ // conditions, rather than setting errno. See the comments for TrapFnc for
+ // details. In other words, the return value from ForwardSyscall() is
+ // directly suitable as a return value for a trap handler.
+ static intptr_t ForwardSyscall(const struct arch_seccomp_data& args);
+
+ private:
+ friend class SandboxBPFTestRunner;
+
+ // Assembles a BPF filter program from the current policy. After calling this
+ // function, you must not call any other sandboxing function.
+ CodeGen::Program AssembleFilter();
+
+ // Assembles and installs a filter based on the policy that has previously
+ // been configured with SetSandboxPolicy().
+ void InstallFilter(bool must_sync_threads);
+
+ base::ScopedFD proc_fd_;
+ bool sandbox_has_started_;
+ std::unique_ptr<bpf_dsl::Policy> policy_;
+
+ DISALLOW_COPY_AND_ASSIGN(SandboxBPF);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H_
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
new file mode 100644
index 0000000000..36f3744b76
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
@@ -0,0 +1,66 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h"
+
+#include <fcntl.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/system_headers/linux_filter.h"
+#include "sandbox/linux/tests/unit_tests.h"
+
+namespace sandbox {
+
+SandboxBPFTestRunner::SandboxBPFTestRunner(
+ BPFTesterDelegate* bpf_tester_delegate)
+ : bpf_tester_delegate_(bpf_tester_delegate) {
+}
+
+SandboxBPFTestRunner::~SandboxBPFTestRunner() {
+}
+
+void SandboxBPFTestRunner::Run() {
+ DCHECK(bpf_tester_delegate_);
+ sandbox::Die::EnableSimpleExit();
+
+ std::unique_ptr<bpf_dsl::Policy> policy =
+ bpf_tester_delegate_->GetSandboxBPFPolicy();
+
+ if (sandbox::SandboxBPF::SupportsSeccompSandbox(
+ SandboxBPF::SeccompLevel::SINGLE_THREADED)) {
+ // Initialize and then start the sandbox with our custom policy
+ sandbox::SandboxBPF sandbox(std::move(policy));
+ SANDBOX_ASSERT(sandbox.StartSandbox(
+ sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED));
+
+ // Run the actual test.
+ bpf_tester_delegate_->RunTestFunction();
+ } else {
+ printf("This BPF test is not fully running in this configuration!\n");
+ // Android is the only configuration where we accept not having kernel
+ // BPF support.
+ if (!IsAndroid()) {
+ const bool seccomp_bpf_is_supported = false;
+ SANDBOX_ASSERT(seccomp_bpf_is_supported);
+ }
+ // Call the compiler and verify the policy. That's the least we can do,
+ // if we don't have kernel support.
+ sandbox::SandboxBPF sandbox(std::move(policy));
+ sandbox.AssembleFilter();
+ sandbox::UnitTests::IgnoreThisTest();
+ }
+}
+
+bool SandboxBPFTestRunner::ShouldCheckForLeaks() const {
+ // LSAN requires being able to use ptrace() and other system calls that could
+ // be denied.
+ return false;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h
new file mode 100644
index 0000000000..4fc3c5d169
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_
+#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/linux/tests/sandbox_test_runner.h"
+
+namespace sandbox {
+namespace bpf_dsl {
+class Policy;
+}
+
+// To create a SandboxBPFTestRunner object, one needs to implement this
+// interface and pass an instance to the SandboxBPFTestRunner constructor.
+// In the child process running the test, the BPFTesterDelegate object is
+// guaranteed to not be destroyed until the child process terminates.
+class BPFTesterDelegate {
+ public:
+ BPFTesterDelegate() {}
+ virtual ~BPFTesterDelegate() {}
+
+ // This will instanciate a policy suitable for the test we want to run. It is
+ // guaranteed to only be called from the child process that will run the
+ // test.
+ virtual std::unique_ptr<bpf_dsl::Policy> GetSandboxBPFPolicy() = 0;
+ // This will be called from a child process with the BPF sandbox turned on.
+ virtual void RunTestFunction() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BPFTesterDelegate);
+};
+
+// This class implements the SandboxTestRunner interface and Run() will
+// initialize a seccomp-bpf sandbox (specified by |bpf_tester_delegate|) and
+// run a test function (via |bpf_tester_delegate|) if the current kernel
+// configuration allows it. If it can not run the test under seccomp-bpf,
+// Run() will still compile the policy which should allow to get some coverage
+// under tools that behave like Valgrind.
+class SandboxBPFTestRunner : public SandboxTestRunner {
+ public:
+ // This constructor takes ownership of the |bpf_tester_delegate| object.
+ // (It doesn't take a std::unique_ptr since they make polymorphism verbose).
+ explicit SandboxBPFTestRunner(BPFTesterDelegate* bpf_tester_delegate);
+ ~SandboxBPFTestRunner() override;
+
+ void Run() override;
+
+ bool ShouldCheckForLeaks() const override;
+
+ private:
+ std::unique_ptr<BPFTesterDelegate> bpf_tester_delegate_;
+ DISALLOW_COPY_AND_ASSIGN(SandboxBPFTestRunner);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.cc
new file mode 100644
index 0000000000..34edabd2b8
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.cc
@@ -0,0 +1,481 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+
+#include <errno.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+
+namespace sandbox {
+
+namespace {
+
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \
+ defined(ARCH_CPU_MIPS_FAMILY)
+// Number that's not currently used by any Linux kernel ABIs.
+const int kInvalidSyscallNumber = 0x351d3;
+#else
+#error Unrecognized architecture
+#endif
+
+asm(// We need to be able to tell the kernel exactly where we made a
+ // system call. The C++ compiler likes to sometimes clone or
+ // inline code, which would inadvertently end up duplicating
+ // the entry point.
+ // "gcc" can suppress code duplication with suitable function
+ // attributes, but "clang" doesn't have this ability.
+ // The "clang" developer mailing list suggested that the correct
+ // and portable solution is a file-scope assembly block.
+ // N.B. We do mark our code as a proper function so that backtraces
+ // work correctly. But we make absolutely no attempt to use the
+ // ABI's calling conventions for passing arguments. We will only
+ // ever be called from assembly code and thus can pick more
+ // suitable calling conventions.
+#if defined(__i386__)
+ ".text\n"
+ ".align 16, 0x90\n"
+ ".type SyscallAsm, @function\n"
+ "SyscallAsm:.cfi_startproc\n"
+ // Check if "%eax" is negative. If so, do not attempt to make a
+ // system call. Instead, compute the return address that is visible
+ // to the kernel after we execute "int $0x80". This address can be
+ // used as a marker that BPF code inspects.
+ "test %eax, %eax\n"
+ "jge 1f\n"
+ // Always, make sure that our code is position-independent, or
+ // address space randomization might not work on i386. This means,
+ // we can't use "lea", but instead have to rely on "call/pop".
+ "call 0f; .cfi_adjust_cfa_offset 4\n"
+ "0:pop %eax; .cfi_adjust_cfa_offset -4\n"
+ "addl $2f-0b, %eax\n"
+ "ret\n"
+ // Save register that we don't want to clobber. On i386, we need to
+ // save relatively aggressively, as there are a couple or registers
+ // that are used internally (e.g. %ebx for position-independent
+ // code, and %ebp for the frame pointer), and as we need to keep at
+ // least a few registers available for the register allocator.
+ "1:push %esi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset esi, 0\n"
+ "push %edi; .cfi_adjust_cfa_offset 4; .cfi_rel_offset edi, 0\n"
+ "push %ebx; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebx, 0\n"
+ "push %ebp; .cfi_adjust_cfa_offset 4; .cfi_rel_offset ebp, 0\n"
+ // Copy entries from the array holding the arguments into the
+ // correct CPU registers.
+ "movl 0(%edi), %ebx\n"
+ "movl 4(%edi), %ecx\n"
+ "movl 8(%edi), %edx\n"
+ "movl 12(%edi), %esi\n"
+ "movl 20(%edi), %ebp\n"
+ "movl 16(%edi), %edi\n"
+ // Enter the kernel.
+ "int $0x80\n"
+ // This is our "magic" return address that the BPF filter sees.
+ "2:"
+ // Restore any clobbered registers that we didn't declare to the
+ // compiler.
+ "pop %ebp; .cfi_restore ebp; .cfi_adjust_cfa_offset -4\n"
+ "pop %ebx; .cfi_restore ebx; .cfi_adjust_cfa_offset -4\n"
+ "pop %edi; .cfi_restore edi; .cfi_adjust_cfa_offset -4\n"
+ "pop %esi; .cfi_restore esi; .cfi_adjust_cfa_offset -4\n"
+ "ret\n"
+ ".cfi_endproc\n"
+ "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__x86_64__)
+ ".text\n"
+ ".align 16, 0x90\n"
+ ".type SyscallAsm, @function\n"
+ "SyscallAsm:.cfi_startproc\n"
+ // Check if "%rdi" is negative. If so, do not attempt to make a
+ // system call. Instead, compute the return address that is visible
+ // to the kernel after we execute "syscall". This address can be
+ // used as a marker that BPF code inspects.
+ "test %rdi, %rdi\n"
+ "jge 1f\n"
+ // Always make sure that our code is position-independent, or the
+ // linker will throw a hissy fit on x86-64.
+ "lea 2f(%rip), %rax\n"
+ "ret\n"
+ // Now we load the registers used to pass arguments to the system
+ // call: system call number in %rax, and arguments in %rdi, %rsi,
+ // %rdx, %r10, %r8, %r9. Note: These are all caller-save registers
+ // (only %rbx, %rbp, %rsp, and %r12-%r15 are callee-save), so no
+ // need to worry here about spilling registers or CFI directives.
+ "1:movq %rdi, %rax\n"
+ "movq 0(%rsi), %rdi\n"
+ "movq 16(%rsi), %rdx\n"
+ "movq 24(%rsi), %r10\n"
+ "movq 32(%rsi), %r8\n"
+ "movq 40(%rsi), %r9\n"
+ "movq 8(%rsi), %rsi\n"
+ // Enter the kernel.
+ "syscall\n"
+ // This is our "magic" return address that the BPF filter sees.
+ "2:ret\n"
+ ".cfi_endproc\n"
+ "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif defined(__arm__)
+ // Throughout this file, we use the same mode (ARM vs. thumb)
+ // that the C++ compiler uses. This means, when transfering control
+ // from C++ to assembly code, we do not need to switch modes (e.g.
+ // by using the "bx" instruction). It also means that our assembly
+ // code should not be invoked directly from code that lives in
+ // other compilation units, as we don't bother implementing thumb
+ // interworking. That's OK, as we don't make any of the assembly
+ // symbols public. They are all local to this file.
+ ".text\n"
+ ".align 2\n"
+ ".type SyscallAsm, %function\n"
+#if defined(__thumb__)
+ ".thumb_func\n"
+#else
+ ".arm\n"
+#endif
+ "SyscallAsm:\n"
+#if !defined(__native_client_nonsfi__)
+ // .fnstart and .fnend pseudo operations creates unwind table.
+ // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which
+ // is not provided by PNaCl toolchain. Disable it.
+ ".fnstart\n"
+#endif
+ "@ args = 0, pretend = 0, frame = 8\n"
+ "@ frame_needed = 1, uses_anonymous_args = 0\n"
+#if defined(__thumb__)
+ ".cfi_startproc\n"
+ "push {r7, lr}\n"
+ ".save {r7, lr}\n"
+ ".cfi_offset 14, -4\n"
+ ".cfi_offset 7, -8\n"
+ ".cfi_def_cfa_offset 8\n"
+#else
+ "stmfd sp!, {fp, lr}\n"
+ "add fp, sp, #4\n"
+#endif
+ // Check if "r0" is negative. If so, do not attempt to make a
+ // system call. Instead, compute the return address that is visible
+ // to the kernel after we execute "swi 0". This address can be
+ // used as a marker that BPF code inspects.
+ "cmp r0, #0\n"
+ "bge 1f\n"
+ "adr r0, 2f\n"
+ "b 2f\n"
+ // We declared (almost) all clobbered registers to the compiler. On
+ // ARM there is no particular register pressure. So, we can go
+ // ahead and directly copy the entries from the arguments array
+ // into the appropriate CPU registers.
+ "1:ldr r5, [r6, #20]\n"
+ "ldr r4, [r6, #16]\n"
+ "ldr r3, [r6, #12]\n"
+ "ldr r2, [r6, #8]\n"
+ "ldr r1, [r6, #4]\n"
+ "mov r7, r0\n"
+ "ldr r0, [r6, #0]\n"
+ // Enter the kernel
+ "swi 0\n"
+// Restore the frame pointer. Also restore the program counter from
+// the link register; this makes us return to the caller.
+#if defined(__thumb__)
+ "2:pop {r7, pc}\n"
+ ".cfi_endproc\n"
+#else
+ "2:ldmfd sp!, {fp, pc}\n"
+#endif
+#if !defined(__native_client_nonsfi__)
+ // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment,
+ // for more details.
+ ".fnend\n"
+#endif
+ "9:.size SyscallAsm, 9b-SyscallAsm\n"
+#elif (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
+ ".text\n"
+ ".option pic2\n"
+ ".align 4\n"
+ ".global SyscallAsm\n"
+ ".type SyscallAsm, @function\n"
+ "SyscallAsm:.ent SyscallAsm\n"
+ ".frame $sp, 40, $ra\n"
+ ".set push\n"
+ ".set noreorder\n"
+ ".cpload $t9\n"
+ "addiu $sp, $sp, -40\n"
+ "sw $ra, 36($sp)\n"
+ // Check if "v0" is negative. If so, do not attempt to make a
+ // system call. Instead, compute the return address that is visible
+ // to the kernel after we execute "syscall". This address can be
+ // used as a marker that BPF code inspects.
+ "bgez $v0, 1f\n"
+ " nop\n"
+ // This is equivalent to "la $v0, 2f".
+ // LA macro has to be avoided since LLVM-AS has issue with LA in PIC mode
+ // https://llvm.org/bugs/show_bug.cgi?id=27644
+ "lw $v0, %got(2f)($gp)\n"
+ "addiu $v0, $v0, %lo(2f)\n"
+ "b 2f\n"
+ " nop\n"
+ // On MIPS first four arguments go to registers a0 - a3 and any
+ // argument after that goes to stack. We can go ahead and directly
+ // copy the entries from the arguments array into the appropriate
+ // CPU registers and on the stack.
+ "1:lw $a3, 28($a0)\n"
+ "lw $a2, 24($a0)\n"
+ "lw $a1, 20($a0)\n"
+ "lw $t0, 16($a0)\n"
+ "sw $a3, 28($sp)\n"
+ "sw $a2, 24($sp)\n"
+ "sw $a1, 20($sp)\n"
+ "sw $t0, 16($sp)\n"
+ "lw $a3, 12($a0)\n"
+ "lw $a2, 8($a0)\n"
+ "lw $a1, 4($a0)\n"
+ "lw $a0, 0($a0)\n"
+ // Enter the kernel
+ "syscall\n"
+ // This is our "magic" return address that the BPF filter sees.
+ // Restore the return address from the stack.
+ "2:lw $ra, 36($sp)\n"
+ "jr $ra\n"
+ " addiu $sp, $sp, 40\n"
+ ".set pop\n"
+ ".end SyscallAsm\n"
+ ".size SyscallAsm,.-SyscallAsm\n"
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+ ".text\n"
+ ".option pic2\n"
+ ".global SyscallAsm\n"
+ ".type SyscallAsm, @function\n"
+ "SyscallAsm:.ent SyscallAsm\n"
+ ".frame $sp, 16, $ra\n"
+ ".set push\n"
+ ".set noreorder\n"
+ "daddiu $sp, $sp, -16\n"
+ ".cpsetup $25, 0, SyscallAsm\n"
+ "sd $ra, 8($sp)\n"
+ // Check if "v0" is negative. If so, do not attempt to make a
+ // system call. Instead, compute the return address that is visible
+ // to the kernel after we execute "syscall". This address can be
+ // used as a marker that BPF code inspects.
+ "bgez $v0, 1f\n"
+ " nop\n"
+ // This is equivalent to "la $v0, 2f".
+ // LA macro has to be avoided since LLVM-AS has issue with LA in PIC mode
+ // https://llvm.org/bugs/show_bug.cgi?id=27644
+ "ld $v0, %got(2f)($gp)\n"
+ "daddiu $v0, $v0, %lo(2f)\n"
+ "b 2f\n"
+ " nop\n"
+ // On MIPS N64 all eight arguments go to registers a0 - a7
+ // We can go ahead and directly copy the entries from the arguments array
+ // into the appropriate CPU registers.
+ "1:ld $a7, 56($a0)\n"
+ "ld $a6, 48($a0)\n"
+ "ld $a5, 40($a0)\n"
+ "ld $a4, 32($a0)\n"
+ "ld $a3, 24($a0)\n"
+ "ld $a2, 16($a0)\n"
+ "ld $a1, 8($a0)\n"
+ "ld $a0, 0($a0)\n"
+ // Enter the kernel
+ "syscall\n"
+ // This is our "magic" return address that the BPF filter sees.
+ // Restore the return address from the stack.
+ "2:ld $ra, 8($sp)\n"
+ ".cpreturn\n"
+ "jr $ra\n"
+ "daddiu $sp, $sp, 16\n"
+ ".set pop\n"
+ ".end SyscallAsm\n"
+ ".size SyscallAsm,.-SyscallAsm\n"
+#elif defined(__aarch64__)
+ ".text\n"
+ ".align 2\n"
+ ".type SyscallAsm, %function\n"
+ "SyscallAsm:\n"
+ ".cfi_startproc\n"
+ "cmp x0, #0\n"
+ "b.ge 1f\n"
+ "adr x0,2f\n"
+ "b 2f\n"
+ "1:ldr x5, [x6, #40]\n"
+ "ldr x4, [x6, #32]\n"
+ "ldr x3, [x6, #24]\n"
+ "ldr x2, [x6, #16]\n"
+ "ldr x1, [x6, #8]\n"
+ "mov x8, x0\n"
+ "ldr x0, [x6, #0]\n"
+ // Enter the kernel
+ "svc 0\n"
+ "2:ret\n"
+ ".cfi_endproc\n"
+ ".size SyscallAsm, .-SyscallAsm\n"
+#endif
+ ); // asm
+
+#if defined(__x86_64__)
+extern "C" {
+intptr_t SyscallAsm(intptr_t nr, const intptr_t args[6]);
+}
+#elif defined(__mips__)
+extern "C" {
+intptr_t SyscallAsm(intptr_t nr, const intptr_t args[8]);
+}
+#endif
+
+} // namespace
+
+intptr_t Syscall::InvalidCall() {
+ // Explicitly pass eight zero arguments just in case.
+ return Call(kInvalidSyscallNumber, 0, 0, 0, 0, 0, 0, 0, 0);
+}
+
+intptr_t Syscall::Call(int nr,
+ intptr_t p0,
+ intptr_t p1,
+ intptr_t p2,
+ intptr_t p3,
+ intptr_t p4,
+ intptr_t p5,
+ intptr_t p6,
+ intptr_t p7) {
+ // We rely on "intptr_t" to be the exact size as a "void *". This is
+ // typically true, but just in case, we add a check. The language
+ // specification allows platforms some leeway in cases, where
+ // "sizeof(void *)" is not the same as "sizeof(void (*)())". We expect
+ // that this would only be an issue for IA64, which we are currently not
+ // planning on supporting. And it is even possible that this would work
+ // on IA64, but for lack of actual hardware, I cannot test.
+ static_assert(sizeof(void*) == sizeof(intptr_t),
+ "pointer types and intptr_t must be exactly the same size");
+
+ // TODO(nedeljko): Enable use of more than six parameters on architectures
+ // where that makes sense.
+#if defined(__mips__)
+ const intptr_t args[8] = {p0, p1, p2, p3, p4, p5, p6, p7};
+#else
+ DCHECK_EQ(p6, 0) << " Support for syscalls with more than six arguments not "
+ "added for this architecture";
+ DCHECK_EQ(p7, 0) << " Support for syscalls with more than six arguments not "
+ "added for this architecture";
+ const intptr_t args[6] = {p0, p1, p2, p3, p4, p5};
+#endif // defined(__mips__)
+
+// Invoke our file-scope assembly code. The constraints have been picked
+// carefully to match what the rest of the assembly code expects in input,
+// output, and clobbered registers.
+#if defined(__i386__)
+ intptr_t ret = nr;
+ asm volatile(
+ "call SyscallAsm\n"
+ // N.B. These are not the calling conventions normally used by the ABI.
+ : "=a"(ret)
+ : "0"(ret), "D"(args)
+ : "cc", "esp", "memory", "ecx", "edx");
+#elif defined(__x86_64__)
+ intptr_t ret = SyscallAsm(nr, args);
+#elif defined(__arm__)
+ intptr_t ret;
+ {
+ register intptr_t inout __asm__("r0") = nr;
+ register const intptr_t* data __asm__("r6") = args;
+ asm volatile(
+ "bl SyscallAsm\n"
+ // N.B. These are not the calling conventions normally used by the ABI.
+ : "=r"(inout)
+ : "0"(inout), "r"(data)
+ : "cc",
+ "lr",
+ "memory",
+ "r1",
+ "r2",
+ "r3",
+ "r4",
+ "r5"
+#if !defined(__thumb__)
+ // In thumb mode, we cannot use "r7" as a general purpose register, as
+ // it is our frame pointer. We have to manually manage and preserve
+ // it.
+ // In ARM mode, we have a dedicated frame pointer register and "r7" is
+ // thus available as a general purpose register. We don't preserve it,
+ // but instead mark it as clobbered.
+ ,
+ "r7"
+#endif // !defined(__thumb__)
+ );
+ ret = inout;
+ }
+#elif defined(__mips__)
+ intptr_t err_status;
+ intptr_t ret = Syscall::SandboxSyscallRaw(nr, args, &err_status);
+
+ if (err_status) {
+ // On error, MIPS returns errno from syscall instead of -errno.
+ // The purpose of this negation is for SandboxSyscall() to behave
+ // more like it would on other architectures.
+ ret = -ret;
+ }
+#elif defined(__aarch64__)
+ intptr_t ret;
+ {
+ register intptr_t inout __asm__("x0") = nr;
+ register const intptr_t* data __asm__("x6") = args;
+ asm volatile("bl SyscallAsm\n"
+ : "=r"(inout)
+ : "0"(inout), "r"(data)
+ : "memory", "x1", "x2", "x3", "x4", "x5", "x8", "x30");
+ ret = inout;
+ }
+
+#else
+#error "Unimplemented architecture"
+#endif
+ return ret;
+}
+
+void Syscall::PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx) {
+#if defined(__mips__)
+ // Mips ABI states that on error a3 CPU register has non zero value and if
+ // there is no error, it should be zero.
+ if (ret_val <= -1 && ret_val >= -4095) {
+ // |ret_val| followes the Syscall::Call() convention of being -errno on
+ // errors. In order to write correct value to return register this sign
+ // needs to be changed back.
+ ret_val = -ret_val;
+ SECCOMP_PARM4(ctx) = 1;
+ } else
+ SECCOMP_PARM4(ctx) = 0;
+#endif
+ SECCOMP_RESULT(ctx) = static_cast<greg_t>(ret_val);
+}
+
+#if defined(__mips__)
+intptr_t Syscall::SandboxSyscallRaw(int nr,
+ const intptr_t* args,
+ intptr_t* err_ret) {
+ register intptr_t ret __asm__("v0") = nr;
+ register intptr_t syscallasm __asm__("t9") = (intptr_t) &SyscallAsm;
+ // a3 register becomes non zero on error.
+ register intptr_t err_stat __asm__("a3") = 0;
+ {
+ register const intptr_t* data __asm__("a0") = args;
+ asm volatile(
+ "jalr $t9\n"
+ " nop\n"
+ : "=r"(ret), "=r"(err_stat)
+ : "0"(ret),
+ "r"(data),
+ "r"(syscallasm)
+ // a2 is in the clober list so inline assembly can not change its
+ // value.
+ : "memory", "ra", "a2");
+ }
+
+ // Set an error status so it can be used outside of this function
+ *err_ret = err_stat;
+
+ return ret;
+}
+#endif // defined(__mips__)
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.h b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.h
new file mode 100644
index 0000000000..3b02a6723f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall.h
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
+
+#include <signal.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// This purely static class can be used to perform system calls with some
+// low-level control.
+class SANDBOX_EXPORT Syscall {
+ public:
+ // InvalidCall() invokes Call() with a platform-appropriate syscall
+ // number that is guaranteed to not be implemented (i.e., normally
+ // returns -ENOSYS).
+ // This is primarily meant to be useful for writing sandbox policy
+ // unit tests.
+ static intptr_t InvalidCall();
+
+ // System calls can take up to six parameters (up to eight on some
+ // architectures). Traditionally, glibc
+ // implements this property by using variadic argument lists. This works, but
+ // confuses tools that behave like Valgrind, because we are nominally passing
+ // uninitialized data whenever we call through this function and pass less
+ // than the full six arguments.
+ // So, instead, we use C++'s template system to achieve a very similar
+ // effect. C++ automatically sets the unused parameters to zero for us, and
+ // it also does the correct type expansion (e.g. from 32bit to 64bit) where
+ // necessary.
+ // We have to use C-style cast operators as we want to be able to accept both
+ // integer and pointer types.
+ template <class T0,
+ class T1,
+ class T2,
+ class T3,
+ class T4,
+ class T5,
+ class T6,
+ class T7>
+ static inline intptr_t
+ Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) {
+ return Call(nr,
+ (intptr_t)p0,
+ (intptr_t)p1,
+ (intptr_t)p2,
+ (intptr_t)p3,
+ (intptr_t)p4,
+ (intptr_t)p5,
+ (intptr_t)p6,
+ (intptr_t)p7);
+ }
+
+ template <class T0,
+ class T1,
+ class T2,
+ class T3,
+ class T4,
+ class T5,
+ class T6>
+ static inline intptr_t
+ Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6) {
+ return Call(nr,
+ (intptr_t)p0,
+ (intptr_t)p1,
+ (intptr_t)p2,
+ (intptr_t)p3,
+ (intptr_t)p4,
+ (intptr_t)p5,
+ (intptr_t)p6,
+ 0);
+ }
+
+ template <class T0, class T1, class T2, class T3, class T4, class T5>
+ static inline intptr_t
+ Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) {
+ return Call(nr,
+ (intptr_t)p0,
+ (intptr_t)p1,
+ (intptr_t)p2,
+ (intptr_t)p3,
+ (intptr_t)p4,
+ (intptr_t)p5,
+ 0,
+ 0);
+ }
+
+ template <class T0, class T1, class T2, class T3, class T4>
+ static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) {
+ return Call(nr, p0, p1, p2, p3, p4, 0, 0, 0);
+ }
+
+ template <class T0, class T1, class T2, class T3>
+ static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3) {
+ return Call(nr, p0, p1, p2, p3, 0, 0, 0, 0);
+ }
+
+ template <class T0, class T1, class T2>
+ static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2) {
+ return Call(nr, p0, p1, p2, 0, 0, 0, 0, 0);
+ }
+
+ template <class T0, class T1>
+ static inline intptr_t Call(int nr, T0 p0, T1 p1) {
+ return Call(nr, p0, p1, 0, 0, 0, 0, 0, 0);
+ }
+
+ template <class T0>
+ static inline intptr_t Call(int nr, T0 p0) {
+ return Call(nr, p0, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ static inline intptr_t Call(int nr) {
+ return Call(nr, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ // Set the registers in |ctx| to match what they would be after a system call
+ // returning |ret_val|. |ret_val| must follow the Syscall::Call() convention
+ // of being -errno on errors.
+ static void PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx);
+
+ private:
+ // This performs system call |nr| with the arguments p0 to p7 from a constant
+ // userland address, which is for instance observable by seccomp-bpf filters.
+ // The constant userland address from which these system calls are made will
+ // be returned if |nr| is passed as -1.
+ // On error, this function will return a value between -1 and -4095 which
+ // should be interpreted as -errno.
+ static intptr_t Call(int nr,
+ intptr_t p0,
+ intptr_t p1,
+ intptr_t p2,
+ intptr_t p3,
+ intptr_t p4,
+ intptr_t p5,
+ intptr_t p6,
+ intptr_t p7);
+
+#if defined(__mips__)
+ // This function basically does on MIPS what SandboxSyscall() is doing on
+ // other architectures. However, because of specificity of MIPS regarding
+ // handling syscall errors, SandboxSyscall() is made as a wrapper for this
+ // function in order for SandboxSyscall() to behave more like on other
+ // architectures on places where return value from SandboxSyscall() is used
+ // directly (like in most tests).
+ // The syscall "nr" is called with arguments that are set in an array on which
+ // pointer "args" points to and an information weather there is an error or no
+ // is returned to SandboxSyscall() by err_stat.
+ static intptr_t SandboxSyscallRaw(int nr,
+ const intptr_t* args,
+ intptr_t* err_stat);
+#endif // defined(__mips__)
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Syscall);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc
new file mode 100644
index 0000000000..2b776d287b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/syscall_unittest.cc
@@ -0,0 +1,249 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "base/stl_util.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
+#include "sandbox/linux/bpf_dsl/policy.h"
+#include "sandbox/linux/seccomp-bpf/bpf_tests.h"
+#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
+#include "sandbox/linux/tests/unit_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using sandbox::bpf_dsl::Allow;
+using sandbox::bpf_dsl::ResultExpr;
+using sandbox::bpf_dsl::Trap;
+
+namespace sandbox {
+
+namespace {
+
+TEST(Syscall, InvalidCallReturnsENOSYS) {
+ EXPECT_EQ(-ENOSYS, Syscall::InvalidCall());
+}
+
+TEST(Syscall, WellKnownEntryPoint) {
+// Test that Syscall::Call(-1) is handled specially. Don't do this on ARM,
+// where syscall(-1) crashes with SIGILL. Not running the test is fine, as we
+// are still testing ARM code in the next set of tests.
+#if !defined(__arm__) && !defined(__aarch64__)
+ EXPECT_NE(Syscall::Call(-1), syscall(-1));
+#endif
+
+// If possible, test that Syscall::Call(-1) returns the address right
+// after
+// a kernel entry point.
+#if defined(__i386__)
+ EXPECT_EQ(0x80CDu, ((uint16_t*)Syscall::Call(-1))[-1]); // INT 0x80
+#elif defined(__x86_64__)
+ EXPECT_EQ(0x050Fu, ((uint16_t*)Syscall::Call(-1))[-1]); // SYSCALL
+#elif defined(__arm__)
+#if defined(__thumb__)
+ EXPECT_EQ(0xDF00u, ((uint16_t*)Syscall::Call(-1))[-1]); // SWI 0
+#else
+ EXPECT_EQ(0xEF000000u, ((uint32_t*)Syscall::Call(-1))[-1]); // SVC 0
+#endif
+#elif defined(__mips__)
+ // Opcode for MIPS sycall is in the lower 16-bits
+ EXPECT_EQ(0x0cu, (((uint32_t*)Syscall::Call(-1))[-1]) & 0x0000FFFF);
+#elif defined(__aarch64__)
+ EXPECT_EQ(0xD4000001u, ((uint32_t*)Syscall::Call(-1))[-1]); // SVC 0
+#else
+#warning Incomplete test case; need port for target platform
+#endif
+}
+
+TEST(Syscall, TrivialSyscallNoArgs) {
+ // Test that we can do basic system calls
+ EXPECT_EQ(Syscall::Call(__NR_getpid), syscall(__NR_getpid));
+}
+
+TEST(Syscall, TrivialSyscallOneArg) {
+ int new_fd;
+ // Duplicate standard error and close it.
+ ASSERT_GE(new_fd = Syscall::Call(__NR_dup, 2), 0);
+ int close_return_value = IGNORE_EINTR(Syscall::Call(__NR_close, new_fd));
+ ASSERT_EQ(close_return_value, 0);
+}
+
+TEST(Syscall, TrivialFailingSyscall) {
+ errno = -42;
+ int ret = Syscall::Call(__NR_dup, -1);
+ ASSERT_EQ(-EBADF, ret);
+ // Verify that Syscall::Call does not touch errno.
+ ASSERT_EQ(-42, errno);
+}
+
+// SIGSYS trap handler that will be called on __NR_uname.
+intptr_t CopySyscallArgsToAux(const struct arch_seccomp_data& args, void* aux) {
+ // |aux| is our BPF_AUX pointer.
+ std::vector<uint64_t>* const seen_syscall_args =
+ static_cast<std::vector<uint64_t>*>(aux);
+ BPF_ASSERT(base::size(args.args) == 6);
+ seen_syscall_args->assign(args.args, args.args + base::size(args.args));
+ return -ENOMEM;
+}
+
+class CopyAllArgsOnUnamePolicy : public bpf_dsl::Policy {
+ public:
+ explicit CopyAllArgsOnUnamePolicy(std::vector<uint64_t>* aux) : aux_(aux) {}
+ ~CopyAllArgsOnUnamePolicy() override {}
+
+ ResultExpr EvaluateSyscall(int sysno) const override {
+ DCHECK(SandboxBPF::IsValidSyscallNumber(sysno));
+ if (sysno == __NR_uname) {
+ return Trap(CopySyscallArgsToAux, aux_);
+ } else {
+ return Allow();
+ }
+ }
+
+ private:
+ std::vector<uint64_t>* aux_;
+
+ DISALLOW_COPY_AND_ASSIGN(CopyAllArgsOnUnamePolicy);
+};
+
+// We are testing Syscall::Call() by making use of a BPF filter that
+// allows us
+// to inspect the system call arguments that the kernel saw.
+BPF_TEST(Syscall,
+ SyntheticSixArgs,
+ CopyAllArgsOnUnamePolicy,
+ std::vector<uint64_t> /* (*BPF_AUX) */) {
+ const int kExpectedValue = 42;
+ // In this test we only pass integers to the kernel. We might want to make
+ // additional tests to try other types. What we will see depends on
+ // implementation details of kernel BPF filters and we will need to document
+ // the expected behavior very clearly.
+ int syscall_args[6];
+ for (size_t i = 0; i < base::size(syscall_args); ++i) {
+ syscall_args[i] = kExpectedValue + i;
+ }
+
+ // We could use pretty much any system call we don't need here. uname() is
+ // nice because it doesn't have any dangerous side effects.
+ BPF_ASSERT(Syscall::Call(__NR_uname,
+ syscall_args[0],
+ syscall_args[1],
+ syscall_args[2],
+ syscall_args[3],
+ syscall_args[4],
+ syscall_args[5]) == -ENOMEM);
+
+ // We expect the trap handler to have copied the 6 arguments.
+ BPF_ASSERT(BPF_AUX->size() == 6);
+
+ // Don't loop here so that we can see which argument does cause the failure
+ // easily from the failing line.
+ // uint64_t is the type passed to our SIGSYS handler.
+ BPF_ASSERT((*BPF_AUX)[0] == static_cast<uint64_t>(syscall_args[0]));
+ BPF_ASSERT((*BPF_AUX)[1] == static_cast<uint64_t>(syscall_args[1]));
+ BPF_ASSERT((*BPF_AUX)[2] == static_cast<uint64_t>(syscall_args[2]));
+ BPF_ASSERT((*BPF_AUX)[3] == static_cast<uint64_t>(syscall_args[3]));
+ BPF_ASSERT((*BPF_AUX)[4] == static_cast<uint64_t>(syscall_args[4]));
+ BPF_ASSERT((*BPF_AUX)[5] == static_cast<uint64_t>(syscall_args[5]));
+}
+
+TEST(Syscall, ComplexSyscallSixArgs) {
+ int fd;
+ const size_t kPageSize = base::GetPageSize();
+
+ ASSERT_LE(0,
+ fd = Syscall::Call(__NR_openat, AT_FDCWD, "/dev/null", O_RDWR, 0L));
+
+ // Use mmap() to allocate some read-only memory
+ char* addr0;
+ ASSERT_NE(
+ (char*)NULL,
+ addr0 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+ (void*)NULL,
+ kPageSize,
+ PROT_READ,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ fd,
+ 0L)));
+
+ // Try to replace the existing mapping with a read-write mapping
+ char* addr1;
+ ASSERT_EQ(addr0,
+ addr1 = reinterpret_cast<char*>(
+ Syscall::Call(kMMapNr,
+ addr0,
+ kPageSize,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
+ fd,
+ 0L)));
+ ++*addr1; // This should not seg fault
+
+ // Clean up
+ EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr1, kPageSize));
+ EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
+
+ // Check that the offset argument (i.e. the sixth argument) is processed
+ // correctly.
+ ASSERT_GE(
+ fd = Syscall::Call(__NR_openat, AT_FDCWD, "/proc/self/exe", O_RDONLY, 0L),
+ 0);
+ char* addr2, *addr3;
+ ASSERT_NE((char*)NULL,
+ addr2 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+ (void*)NULL,
+ 2 * kPageSize,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+ 0L
+ )));
+ ASSERT_NE((char*)NULL,
+ addr3 = reinterpret_cast<char*>(Syscall::Call(kMMapNr,
+ (void*)NULL,
+ kPageSize,
+ PROT_READ,
+ MAP_PRIVATE,
+ fd,
+#if defined(__NR_mmap2)
+ 1L
+#else
+ kPageSize
+#endif
+ )));
+ EXPECT_EQ(0, memcmp(addr2 + kPageSize, addr3, kPageSize));
+
+ // Just to be absolutely on the safe side, also verify that the file
+ // contents matches what we are getting from a read() operation.
+ char buf[2 * kPageSize];
+ EXPECT_EQ(2 * kPageSize, static_cast<size_t>(Syscall::Call(__NR_read,
+ fd,
+ buf,
+ 2 * kPageSize
+ )));
+ EXPECT_EQ(0, memcmp(addr2, buf, 2 * kPageSize));
+
+ // Clean up
+ EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr2, 2 * kPageSize));
+ EXPECT_EQ(0, Syscall::Call(__NR_munmap, addr3, kPageSize));
+ EXPECT_EQ(0, IGNORE_EINTR(Syscall::Call(__NR_close, fd)));
+}
+
+} // namespace
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc
new file mode 100644
index 0000000000..9884be8bb2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc
@@ -0,0 +1,394 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/seccomp-bpf/trap.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/syscall.h>
+
+#include <algorithm>
+#include <limits>
+#include <tuple>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
+#include "sandbox/linux/seccomp-bpf/die.h"
+#include "sandbox/linux/seccomp-bpf/syscall.h"
+#include "sandbox/linux/services/syscall_wrappers.h"
+#include "sandbox/linux/system_headers/linux_seccomp.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+
+namespace {
+
+struct arch_sigsys {
+ void* ip;
+ int nr;
+ unsigned int arch;
+};
+
+const int kCapacityIncrement = 20;
+
+// Unsafe traps can only be turned on, if the user explicitly allowed them
+// by setting the CHROME_SANDBOX_DEBUGGING environment variable.
+const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
+
+// We need to tell whether we are performing a "normal" callback, or
+// whether we were called recursively from within a UnsafeTrap() callback.
+// This is a little tricky to do, because we need to somehow get access to
+// per-thread data from within a signal context. Normal TLS storage is not
+// safely accessible at this time. We could roll our own, but that involves
+// a lot of complexity. Instead, we co-opt one bit in the signal mask.
+// If BUS is blocked, we assume that we have been called recursively.
+// There is a possibility for collision with other code that needs to do
+// this, but in practice the risks are low.
+// If SIGBUS turns out to be a problem, we could instead co-opt one of the
+// realtime signals. There are plenty of them. Unfortunately, there is no
+// way to mark a signal as allocated. So, the potential for collision is
+// possibly even worse.
+bool GetIsInSigHandler(const ucontext_t* ctx) {
+ // Note: on Android, sigismember does not take a pointer to const.
+ return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), LINUX_SIGBUS);
+}
+
+void SetIsInSigHandler() {
+ sigset_t mask;
+ if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGBUS) ||
+ sandbox::sys_sigprocmask(LINUX_SIG_BLOCK, &mask, NULL)) {
+ SANDBOX_DIE("Failed to block SIGBUS");
+ }
+}
+
+bool IsDefaultSignalAction(const struct sigaction& sa) {
+ if (sa.sa_flags & SA_SIGINFO || sa.sa_handler != SIG_DFL) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+namespace sandbox {
+
+Trap::Trap()
+ : trap_array_(NULL),
+ trap_array_size_(0),
+ trap_array_capacity_(0),
+ has_unsafe_traps_(false) {
+ // Set new SIGSYS handler
+ struct sigaction sa = {};
+ // In some toolchain, sa_sigaction is not declared in struct sigaction.
+ // So, here cast the pointer to the sa_handler's type. This works because
+ // |sa_handler| and |sa_sigaction| shares the same memory.
+ sa.sa_handler = reinterpret_cast<void (*)(int)>(SigSysAction);
+ sa.sa_flags = LINUX_SA_SIGINFO | LINUX_SA_NODEFER;
+ struct sigaction old_sa = {};
+ if (sys_sigaction(LINUX_SIGSYS, &sa, &old_sa) < 0) {
+ SANDBOX_DIE("Failed to configure SIGSYS handler");
+ }
+
+ if (!IsDefaultSignalAction(old_sa)) {
+ static const char kExistingSIGSYSMsg[] =
+ "Existing signal handler when trying to install SIGSYS. SIGSYS needs "
+ "to be reserved for seccomp-bpf.";
+ DLOG(FATAL) << kExistingSIGSYSMsg;
+ LOG(ERROR) << kExistingSIGSYSMsg;
+ }
+
+ // Unmask SIGSYS
+ sigset_t mask;
+ if (sigemptyset(&mask) || sigaddset(&mask, LINUX_SIGSYS) ||
+ sys_sigprocmask(LINUX_SIG_UNBLOCK, &mask, NULL)) {
+ SANDBOX_DIE("Failed to configure SIGSYS handler");
+ }
+}
+
+bpf_dsl::TrapRegistry* Trap::Registry() {
+ // Note: This class is not thread safe. It is the caller's responsibility
+ // to avoid race conditions. Normally, this is a non-issue as the sandbox
+ // can only be initialized if there are no other threads present.
+ // Also, this is not a normal singleton. Once created, the global trap
+ // object must never be destroyed again.
+ if (!global_trap_) {
+ global_trap_ = new Trap();
+ if (!global_trap_) {
+ SANDBOX_DIE("Failed to allocate global trap handler");
+ }
+ }
+ return global_trap_;
+}
+
+void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) {
+ if (info) {
+ MSAN_UNPOISON(info, sizeof(*info));
+ }
+
+ // Obtain the signal context. This, most notably, gives us access to
+ // all CPU registers at the time of the signal.
+ ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context);
+ if (ctx) {
+ MSAN_UNPOISON(ctx, sizeof(*ctx));
+ }
+
+ if (!global_trap_) {
+ RAW_SANDBOX_DIE(
+ "This can't happen. Found no global singleton instance "
+ "for Trap() handling.");
+ }
+ global_trap_->SigSys(nr, info, ctx);
+}
+
+void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) {
+ // Signal handlers should always preserve "errno". Otherwise, we could
+ // trigger really subtle bugs.
+ const int old_errno = errno;
+
+ // Various sanity checks to make sure we actually received a signal
+ // triggered by a BPF filter. If something else triggered SIGSYS
+ // (e.g. kill()), there is really nothing we can do with this signal.
+ if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !ctx ||
+ info->si_errno <= 0 ||
+ static_cast<size_t>(info->si_errno) > trap_array_size_) {
+ // ATI drivers seem to send SIGSYS, so this cannot be FATAL.
+ // See crbug.com/178166.
+ // TODO(jln): add a DCHECK or move back to FATAL.
+ RAW_LOG(ERROR, "Unexpected SIGSYS received.");
+ errno = old_errno;
+ return;
+ }
+
+
+ // Obtain the siginfo information that is specific to SIGSYS.
+ struct arch_sigsys sigsys;
+#if defined(si_call_addr) && !defined(__native_client_nonsfi__)
+ sigsys.ip = info->si_call_addr;
+ sigsys.nr = info->si_syscall;
+ sigsys.arch = info->si_arch;
+#else
+ // If the version of glibc doesn't include this information in
+ // siginfo_t (older than 2.17), we need to explicitly copy it
+ // into an arch_sigsys structure.
+ memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
+#endif
+
+#if defined(__mips__)
+ // When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the
+ // number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the
+ // real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx)
+ bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) &&
+ sigsys.nr != static_cast<int>(SECCOMP_PARM1(ctx));
+#else
+ bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx));
+#endif
+
+ // Some more sanity checks.
+ if (sigsys.ip != reinterpret_cast<void*>(SECCOMP_IP(ctx)) ||
+ sigsys_nr_is_bad || sigsys.arch != SECCOMP_ARCH) {
+ // TODO(markus):
+ // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
+ // safe and can lead to bugs. We should eventually implement a different
+ // logging and reporting mechanism that is safe to be called from
+ // the sigSys() handler.
+ RAW_SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.");
+ }
+
+ intptr_t rc;
+ if (has_unsafe_traps_ && GetIsInSigHandler(ctx)) {
+ errno = old_errno;
+ if (sigsys.nr == __NR_clone) {
+ RAW_SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
+ }
+#if defined(__mips__)
+ // Mips supports up to eight arguments for syscall.
+ // However, seccomp bpf can filter only up to six arguments, so using eight
+ // arguments has sense only when using UnsafeTrap() handler.
+ rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
+ SECCOMP_PARM1(ctx),
+ SECCOMP_PARM2(ctx),
+ SECCOMP_PARM3(ctx),
+ SECCOMP_PARM4(ctx),
+ SECCOMP_PARM5(ctx),
+ SECCOMP_PARM6(ctx),
+ SECCOMP_PARM7(ctx),
+ SECCOMP_PARM8(ctx));
+#else
+ rc = Syscall::Call(SECCOMP_SYSCALL(ctx),
+ SECCOMP_PARM1(ctx),
+ SECCOMP_PARM2(ctx),
+ SECCOMP_PARM3(ctx),
+ SECCOMP_PARM4(ctx),
+ SECCOMP_PARM5(ctx),
+ SECCOMP_PARM6(ctx));
+#endif // defined(__mips__)
+ } else {
+ const TrapKey& trap = trap_array_[info->si_errno - 1];
+ if (!trap.safe) {
+ SetIsInSigHandler();
+ }
+
+ // Copy the seccomp-specific data into a arch_seccomp_data structure. This
+ // is what we are showing to TrapFnc callbacks that the system call
+ // evaluator registered with the sandbox.
+ struct arch_seccomp_data data = {
+ static_cast<int>(SECCOMP_SYSCALL(ctx)),
+ SECCOMP_ARCH,
+ reinterpret_cast<uint64_t>(sigsys.ip),
+ {static_cast<uint64_t>(SECCOMP_PARM1(ctx)),
+ static_cast<uint64_t>(SECCOMP_PARM2(ctx)),
+ static_cast<uint64_t>(SECCOMP_PARM3(ctx)),
+ static_cast<uint64_t>(SECCOMP_PARM4(ctx)),
+ static_cast<uint64_t>(SECCOMP_PARM5(ctx)),
+ static_cast<uint64_t>(SECCOMP_PARM6(ctx))}};
+
+ // Now call the TrapFnc callback associated with this particular instance
+ // of SECCOMP_RET_TRAP.
+ rc = trap.fnc(data, const_cast<void*>(trap.aux));
+ }
+
+ // Update the CPU register that stores the return code of the system call
+ // that we just handled, and restore "errno" to the value that it had
+ // before entering the signal handler.
+ Syscall::PutValueInUcontext(rc, ctx);
+ errno = old_errno;
+
+ return;
+}
+
+bool Trap::TrapKey::operator<(const TrapKey& o) const {
+ return std::tie(fnc, aux, safe) < std::tie(o.fnc, o.aux, o.safe);
+}
+
+uint16_t Trap::Add(TrapFnc fnc, const void* aux, bool safe) {
+ if (!safe && !SandboxDebuggingAllowedByUser()) {
+ // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable,
+ // we never return an ErrorCode that is marked as "unsafe". This also
+ // means, the BPF compiler will never emit code that allow unsafe system
+ // calls to by-pass the filter (because they use the magic return address
+ // from Syscall::Call(-1)).
+
+ // This SANDBOX_DIE() can optionally be removed. It won't break security,
+ // but it might make error messages from the BPF compiler a little harder
+ // to understand. Removing the SANDBOX_DIE() allows callers to easily check
+ // whether unsafe traps are supported (by checking whether the returned
+ // ErrorCode is ET_INVALID).
+ SANDBOX_DIE(
+ "Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
+ "is enabled");
+
+ return 0;
+ }
+
+ // Each unique pair of TrapFnc and auxiliary data make up a distinct instance
+ // of a SECCOMP_RET_TRAP.
+ TrapKey key(fnc, aux, safe);
+
+ // We return unique identifiers together with SECCOMP_RET_TRAP. This allows
+ // us to associate trap with the appropriate handler. The kernel allows us
+ // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to
+ // avoid 0, as it could be confused for a trap without any specific id.
+ // The nice thing about sequentially numbered identifiers is that we can also
+ // trivially look them up from our signal handler without making any system
+ // calls that might be async-signal-unsafe.
+ // In order to do so, we store all of our traps in a C-style trap_array_.
+
+ TrapIds::const_iterator iter = trap_ids_.find(key);
+ if (iter != trap_ids_.end()) {
+ // We have seen this pair before. Return the same id that we assigned
+ // earlier.
+ return iter->second;
+ }
+
+ // This is a new pair. Remember it and assign a new id.
+ if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ ||
+ trap_array_size_ >= std::numeric_limits<uint16_t>::max()) {
+ // In practice, this is pretty much impossible to trigger, as there
+ // are other kernel limitations that restrict overall BPF program sizes.
+ SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances");
+ }
+
+ // Our callers ensure that there are no other threads accessing trap_array_
+ // concurrently (typically this is done by ensuring that we are single-
+ // threaded while the sandbox is being set up). But we nonetheless are
+ // modifying a live data structure that could be accessed any time a
+ // system call is made; as system calls could be triggering SIGSYS.
+ // So, we have to be extra careful that we update trap_array_ atomically.
+ // In particular, this means we shouldn't be using realloc() to resize it.
+ // Instead, we allocate a new array, copy the values, and then switch the
+ // pointer. We only really care about the pointer being updated atomically
+ // and the data that is pointed to being valid, as these are the only
+ // values accessed from the signal handler. It is OK if trap_array_size_
+ // is inconsistent with the pointer, as it is monotonously increasing.
+ // Also, we only care about compiler barriers, as the signal handler is
+ // triggered synchronously from a system call. We don't have to protect
+ // against issues with the memory model or with completely asynchronous
+ // events.
+ if (trap_array_size_ >= trap_array_capacity_) {
+ trap_array_capacity_ += kCapacityIncrement;
+ TrapKey* old_trap_array = trap_array_;
+ TrapKey* new_trap_array = new TrapKey[trap_array_capacity_];
+ std::copy_n(old_trap_array, trap_array_size_, new_trap_array);
+
+ // Language specs are unclear on whether the compiler is allowed to move
+ // the "delete[]" above our preceding assignments and/or memory moves,
+ // iff the compiler believes that "delete[]" doesn't have any other
+ // global side-effects.
+ // We insert optimization barriers to prevent this from happening.
+ // The first barrier is probably not needed, but better be explicit in
+ // what we want to tell the compiler.
+ // The clang developer mailing list couldn't answer whether this is a
+ // legitimate worry; but they at least thought that the barrier is
+ // sufficient to prevent the (so far hypothetical) problem of re-ordering
+ // of instructions by the compiler.
+ //
+ // TODO(mdempsky): Try to clean this up using base/atomicops or C++11
+ // atomics; see crbug.com/414363.
+ asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory");
+ trap_array_ = new_trap_array;
+ asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory");
+
+ delete[] old_trap_array;
+ }
+
+ uint16_t id = trap_array_size_ + 1;
+ trap_ids_[key] = id;
+ trap_array_[trap_array_size_] = key;
+ trap_array_size_++;
+ return id;
+}
+
+bool Trap::SandboxDebuggingAllowedByUser() {
+ const char* debug_flag = getenv(kSandboxDebuggingEnv);
+ return debug_flag && *debug_flag;
+}
+
+bool Trap::EnableUnsafeTraps() {
+ if (!has_unsafe_traps_) {
+ // Unsafe traps are a one-way fuse. Once enabled, they can never be turned
+ // off again.
+ // We only allow enabling unsafe traps, if the user explicitly set an
+ // appropriate environment variable. This prevents bugs that accidentally
+ // disable all sandboxing for all users.
+ if (SandboxDebuggingAllowedByUser()) {
+ // We only ever print this message once, when we enable unsafe traps the
+ // first time.
+ SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes");
+ has_unsafe_traps_ = true;
+ } else {
+ SANDBOX_INFO(
+ "Cannot disable sandbox and use unsafe traps unless "
+ "CHROME_SANDBOX_DEBUGGING is turned on first");
+ }
+ }
+ // Returns the, possibly updated, value of has_unsafe_traps_.
+ return has_unsafe_traps_;
+}
+
+Trap* Trap::global_trap_;
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.h b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.h
new file mode 100644
index 0000000000..a73d2064b4
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
+#define SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+
+#include "base/macros.h"
+#include "sandbox/linux/bpf_dsl/trap_registry.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/sandbox_export.h"
+
+namespace sandbox {
+
+// The Trap class allows a BPF filter program to branch out to user space by
+// raising a SIGSYS signal.
+// N.B.: This class does not perform any synchronization operations. If
+// modifications are made to any of the traps, it is the caller's
+// responsibility to ensure that this happens in a thread-safe fashion.
+// Preferably, that means that no other threads should be running at that
+// time. For the purposes of our sandbox, this assertion should always be
+// true. Threads are incompatible with the seccomp sandbox anyway.
+class SANDBOX_EXPORT Trap : public bpf_dsl::TrapRegistry {
+ public:
+ uint16_t Add(TrapFnc fnc, const void* aux, bool safe) override;
+
+ bool EnableUnsafeTraps() override;
+
+ // Registry returns the trap registry used by Trap's SIGSYS handler,
+ // creating it if necessary.
+ static bpf_dsl::TrapRegistry* Registry();
+
+ // SandboxDebuggingAllowedByUser returns whether the
+ // "CHROME_SANDBOX_DEBUGGING" environment variable is set.
+ static bool SandboxDebuggingAllowedByUser();
+
+ private:
+ struct TrapKey {
+ TrapKey() : fnc(NULL), aux(NULL), safe(false) {}
+ TrapKey(TrapFnc f, const void* a, bool s) : fnc(f), aux(a), safe(s) {}
+ TrapFnc fnc;
+ const void* aux;
+ bool safe;
+ bool operator<(const TrapKey&) const;
+ };
+ typedef std::map<TrapKey, uint16_t> TrapIds;
+
+ // Our constructor is private. A shared global instance is created
+ // automatically as needed.
+ Trap();
+
+ // The destructor is unimplemented as destroying this object would
+ // break subsequent system calls that trigger a SIGSYS.
+ ~Trap() = delete;
+
+ static void SigSysAction(int nr, LinuxSigInfo* info, void* void_context);
+
+ // Make sure that SigSys is not inlined in order to get slightly better crash
+ // dumps.
+ void SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx)
+ __attribute__((noinline));
+ // We have a global singleton that handles all of our SIGSYS traps. This
+ // variable must never be deallocated after it has been set up initially, as
+ // there is no way to reset in-kernel BPF filters that generate SIGSYS
+ // events.
+ static Trap* global_trap_;
+
+ TrapIds trap_ids_; // Maps from TrapKeys to numeric ids
+ TrapKey* trap_array_; // Array of TrapKeys indexed by ids
+ size_t trap_array_size_; // Currently used size of array
+ size_t trap_array_capacity_; // Currently allocated capacity of array
+ bool has_unsafe_traps_; // Whether unsafe traps have been enabled
+
+ // Copying and assigning is unimplemented. It doesn't make sense for a
+ // singleton.
+ DISALLOW_COPY_AND_ASSIGN(Trap);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__
diff --git a/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.cc b/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.cc
new file mode 100644
index 0000000000..fcfd2aa129
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.cc
@@ -0,0 +1,264 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/linux/services/syscall_wrappers.h"
+
+#include <pthread.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cstring>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "sandbox/linux/system_headers/capability.h"
+#include "sandbox/linux/system_headers/linux_signal.h"
+#include "sandbox/linux/system_headers/linux_syscalls.h"
+
+namespace sandbox {
+
+pid_t sys_getpid(void) {
+ return syscall(__NR_getpid);
+}
+
+pid_t sys_gettid(void) {
+ return syscall(__NR_gettid);
+}
+
+ssize_t sys_write(int fd, const char* buffer, size_t buffer_size) {
+ return syscall(__NR_write, fd, buffer, buffer_size);
+}
+
+long sys_clone(unsigned long flags,
+ std::nullptr_t child_stack,
+ pid_t* ptid,
+ pid_t* ctid,
+ std::nullptr_t tls) {
+ const bool clone_tls_used = flags & CLONE_SETTLS;
+ const bool invalid_ctid =
+ (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid;
+ const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid;
+
+ // We do not support CLONE_VM.
+ const bool clone_vm_used = flags & CLONE_VM;
+ if (clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used) {
+ RAW_LOG(FATAL, "Invalid usage of sys_clone");
+ }
+
+ if (ptid) MSAN_UNPOISON(ptid, sizeof(*ptid));
+ if (ctid) MSAN_UNPOISON(ctid, sizeof(*ctid));
+ // See kernel/fork.c in Linux. There is different ordering of sys_clone
+ // parameters depending on CONFIG_CLONE_BACKWARDS* configuration options.
+#if defined(ARCH_CPU_X86_64)
+ return syscall(__NR_clone, flags, child_stack, ptid, ctid, tls);
+#elif defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARM_FAMILY) || \
+ defined(ARCH_CPU_MIPS_FAMILY)
+ // CONFIG_CLONE_BACKWARDS defined.
+ return syscall(__NR_clone, flags, child_stack, ptid, tls, ctid);
+#endif
+}
+
+long sys_clone(unsigned long flags) {
+ return sys_clone(flags, nullptr, nullptr, nullptr, nullptr);
+}
+
+void sys_exit_group(int status) {
+ syscall(__NR_exit_group, status);
+}
+
+int sys_seccomp(unsigned int operation,
+ unsigned int flags,
+ const struct sock_fprog* args) {
+ return syscall(__NR_seccomp, operation, flags, args);
+}
+
+int sys_prlimit64(pid_t pid,
+ int resource,
+ const struct rlimit64* new_limit,
+ struct rlimit64* old_limit) {
+ int res = syscall(__NR_prlimit64, pid, resource, new_limit, old_limit);
+ if (res == 0 && old_limit) MSAN_UNPOISON(old_limit, sizeof(*old_limit));
+ return res;
+}
+
+int sys_capget(cap_hdr* hdrp, cap_data* datap) {
+ int res = syscall(__NR_capget, hdrp, datap);
+ if (res == 0) {
+ if (hdrp) MSAN_UNPOISON(hdrp, sizeof(*hdrp));
+ if (datap) MSAN_UNPOISON(datap, sizeof(*datap));
+ }
+ return res;
+}
+
+int sys_capset(cap_hdr* hdrp, const cap_data* datap) {
+ return syscall(__NR_capset, hdrp, datap);
+}
+
+int sys_getresuid(uid_t* ruid, uid_t* euid, uid_t* suid) {
+ int res;
+#if defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARMEL)
+ // On 32-bit x86 or 32-bit arm, getresuid supports 16bit values only.
+ // Use getresuid32 instead.
+ res = syscall(__NR_getresuid32, ruid, euid, suid);
+#else
+ res = syscall(__NR_getresuid, ruid, euid, suid);
+#endif
+ if (res == 0) {
+ if (ruid) MSAN_UNPOISON(ruid, sizeof(*ruid));
+ if (euid) MSAN_UNPOISON(euid, sizeof(*euid));
+ if (suid) MSAN_UNPOISON(suid, sizeof(*suid));
+ }
+ return res;
+}
+
+int sys_getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid) {
+ int res;
+#if defined(ARCH_CPU_X86) || defined(ARCH_CPU_ARMEL)
+ // On 32-bit x86 or 32-bit arm, getresgid supports 16bit values only.
+ // Use getresgid32 instead.
+ res = syscall(__NR_getresgid32, rgid, egid, sgid);
+#else
+ res = syscall(__NR_getresgid, rgid, egid, sgid);
+#endif
+ if (res == 0) {
+ if (rgid) MSAN_UNPOISON(rgid, sizeof(*rgid));
+ if (egid) MSAN_UNPOISON(egid, sizeof(*egid));
+ if (sgid) MSAN_UNPOISON(sgid, sizeof(*sgid));
+ }
+ return res;
+}
+
+int sys_chroot(const char* path) {
+ return syscall(__NR_chroot, path);
+}
+
+int sys_unshare(int flags) {
+ return syscall(__NR_unshare, flags);
+}
+
+int sys_sigprocmask(int how, const sigset_t* set, std::nullptr_t oldset) {
+ // In some toolchain (in particular Android and PNaCl toolchain),
+ // sigset_t is 32 bits, but the Linux ABI uses more.
+ LinuxSigSet linux_value;
+ std::memset(&linux_value, 0, sizeof(LinuxSigSet));
+ std::memcpy(&linux_value, set, std::min(sizeof(sigset_t),
+ sizeof(LinuxSigSet)));
+
+ return syscall(__NR_rt_sigprocmask, how, &linux_value, nullptr,
+ sizeof(linux_value));
+}
+
+// When this is built with PNaCl toolchain, we should always use sys_sigaction
+// below, because sigaction() provided by the toolchain is incompatible with
+// Linux's ABI.
+#if !defined(OS_NACL_NONSFI)
+int sys_sigaction(int signum,
+ const struct sigaction* act,
+ struct sigaction* oldact) {
+ return sigaction(signum, act, oldact);
+}
+#else
+#if defined(ARCH_CPU_X86_FAMILY)
+
+// On x86_64, sa_restorer is required. We specify it on x86 as well in order to
+// support kernels with VDSO disabled.
+#if !defined(SA_RESTORER)
+#define SA_RESTORER 0x04000000
+#endif
+
+// XSTR(__NR_foo) expands to a string literal containing the value value of
+// __NR_foo.
+#define STR(x) #x
+#define XSTR(x) STR(x)
+
+// rt_sigreturn is a special system call that interacts with the user land
+// stack. Thus, here prologue must not be created, which implies syscall()
+// does not work properly, too. Note that rt_sigreturn does not return.
+// TODO(rickyz): These assembly functions may still break stack unwinding on
+// nonsfi NaCl builds.
+#if defined(ARCH_CPU_X86_64)
+
+extern "C" {
+ void sys_rt_sigreturn();
+}
+
+asm(
+ ".text\n"
+ "sys_rt_sigreturn:\n"
+ "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
+ "syscall\n");
+
+#elif defined(ARCH_CPU_X86)
+extern "C" {
+ void sys_sigreturn();
+ void sys_rt_sigreturn();
+}
+
+asm(
+ ".text\n"
+ "sys_rt_sigreturn:\n"
+ "mov $" XSTR(__NR_rt_sigreturn) ", %eax\n"
+ "int $0x80\n"
+
+ "sys_sigreturn:\n"
+ "pop %eax\n"
+ "mov $" XSTR(__NR_sigreturn) ", %eax\n"
+ "int $0x80\n");
+#else
+#error "Unsupported architecture."
+#endif
+
+#undef STR
+#undef XSTR
+
+#endif
+
+int sys_sigaction(int signum,
+ const struct sigaction* act,
+ struct sigaction* oldact) {
+ LinuxSigAction linux_act = {};
+ if (act) {
+ linux_act.kernel_handler = act->sa_handler;
+ std::memcpy(&linux_act.sa_mask, &act->sa_mask,
+ std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
+ linux_act.sa_flags = act->sa_flags;
+
+#if defined(ARCH_CPU_X86_FAMILY)
+ if (!(linux_act.sa_flags & SA_RESTORER)) {
+ linux_act.sa_flags |= SA_RESTORER;
+#if defined(ARCH_CPU_X86_64)
+ linux_act.sa_restorer = sys_rt_sigreturn;
+#elif defined(ARCH_CPU_X86)
+ linux_act.sa_restorer =
+ linux_act.sa_flags & SA_SIGINFO ? sys_rt_sigreturn : sys_sigreturn;
+#else
+#error "Unsupported architecture."
+#endif
+ }
+#endif
+ }
+
+ LinuxSigAction linux_oldact = {};
+ int result = syscall(__NR_rt_sigaction, signum, act ? &linux_act : nullptr,
+ oldact ? &linux_oldact : nullptr,
+ sizeof(LinuxSigSet));
+
+ if (result == 0 && oldact) {
+ oldact->sa_handler = linux_oldact.kernel_handler;
+ sigemptyset(&oldact->sa_mask);
+ std::memcpy(&oldact->sa_mask, &linux_oldact.sa_mask,
+ std::min(sizeof(linux_act.sa_mask), sizeof(act->sa_mask)));
+ oldact->sa_flags = linux_oldact.sa_flags;
+ }
+ return result;
+}
+
+#endif // defined(MEMORY_SANITIZER)
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.h b/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.h
new file mode 100644
index 0000000000..1975bfbd88
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/services/syscall_wrappers.h
@@ -0,0 +1,89 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
+#define SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
+
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cstddef>
+
+#include "sandbox/sandbox_export.h"
+
+struct sock_fprog;
+struct rlimit64;
+struct cap_hdr;
+struct cap_data;
+
+namespace sandbox {
+
+// Provide direct system call wrappers for a few common system calls.
+// These are guaranteed to perform a system call and do not rely on things such
+// as caching the current pid (c.f. getpid()) unless otherwise specified.
+
+SANDBOX_EXPORT pid_t sys_getpid(void);
+
+SANDBOX_EXPORT pid_t sys_gettid(void);
+
+SANDBOX_EXPORT ssize_t sys_write(int fd,
+ const char* buffer,
+ size_t buffer_size);
+
+SANDBOX_EXPORT long sys_clone(unsigned long flags);
+
+// |regs| is not supported and must be passed as nullptr. |child_stack| must be
+// nullptr, since otherwise this function cannot safely return. As a
+// consequence, this function does not support CLONE_VM.
+SANDBOX_EXPORT long sys_clone(unsigned long flags,
+ std::nullptr_t child_stack,
+ pid_t* ptid,
+ pid_t* ctid,
+ std::nullptr_t regs);
+
+SANDBOX_EXPORT void sys_exit_group(int status);
+
+// The official system call takes |args| as void* (in order to be extensible),
+// but add more typing for the cases that are currently used.
+SANDBOX_EXPORT int sys_seccomp(unsigned int operation,
+ unsigned int flags,
+ const struct sock_fprog* args);
+
+// Some libcs do not expose a prlimit64 wrapper.
+SANDBOX_EXPORT int sys_prlimit64(pid_t pid,
+ int resource,
+ const struct rlimit64* new_limit,
+ struct rlimit64* old_limit);
+
+// Some libcs do not expose capget/capset wrappers. We want to use these
+// directly in order to avoid pulling in libcap2.
+SANDBOX_EXPORT int sys_capget(struct cap_hdr* hdrp, struct cap_data* datap);
+SANDBOX_EXPORT int sys_capset(struct cap_hdr* hdrp,
+ const struct cap_data* datap);
+
+// Some libcs do not expose getresuid/getresgid wrappers.
+SANDBOX_EXPORT int sys_getresuid(uid_t* ruid, uid_t* euid, uid_t* suid);
+SANDBOX_EXPORT int sys_getresgid(gid_t* rgid, gid_t* egid, gid_t* sgid);
+
+// Some libcs do not expose a chroot wrapper.
+SANDBOX_EXPORT int sys_chroot(const char* path);
+
+// Some libcs do not expose a unshare wrapper.
+SANDBOX_EXPORT int sys_unshare(int flags);
+
+// Some libcs do not expose a sigprocmask. Note that oldset must be a nullptr,
+// because of some ABI gap between toolchain's and Linux's.
+SANDBOX_EXPORT int sys_sigprocmask(int how,
+ const sigset_t* set,
+ std::nullptr_t oldset);
+
+// Some libcs do not expose a sigaction().
+SANDBOX_EXPORT int sys_sigaction(int signum,
+ const struct sigaction* act,
+ struct sigaction* oldact);
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SERVICES_SYSCALL_WRAPPERS_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h
new file mode 100644
index 0000000000..2224d32438
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/arm64_linux_syscalls.h
@@ -0,0 +1,1197 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* Constructed by running:
+ * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/include/uapi/asm-generic/unistd.h?h=v5.8
+ * | gcc -D__BITS_PER_LONG=64 -D__ARCH_WANT_STAT64 -D__ARCH_WANT_SET_GET_RLIMIT -D__ARCH_WANT_SYS_CLONE3 -D__ARCH_WANT_RENAMEAT -E -dD -
+ * | grep __NR | grep -vE '__NR_arch_specific_syscall|__NR_syscalls' | sort -n -k 3 | sed -e 's/__NR3264/__NR/g'
+ * | awk '{ if ($2 != $3) { print "#if !defined(" $2 ")\n#define " $2 " " $3 "\n#endif\n"; } }
+ * */
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
+
+#include <asm-generic/unistd.h>
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 0
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat __NR_fstatat
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 1
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 2
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 3
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 4
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 5
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 6
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 7
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 8
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 9
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 10
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 11
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 12
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 13
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 14
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 15
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 16
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 17
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 18
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 19
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 20
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 21
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 22
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 23
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 24
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 25
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 26
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 27
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 28
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 29
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 30
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 31
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 32
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 33
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 34
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 35
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 36
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 37
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 38
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 39
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 40
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 41
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 42
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 43
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 44
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 45
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 46
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 47
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 48
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 49
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 50
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 51
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 52
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 53
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 54
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 55
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 56
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 57
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 58
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 59
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 60
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 61
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 62
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 63
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 64
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 65
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 66
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 67
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 68
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 69
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 70
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 71
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 72
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 73
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 74
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 75
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 76
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 77
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 78
+#endif
+
+#if !defined(__NR_fstatat)
+#define __NR_fstatat 79
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 80
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 81
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 82
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 83
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 84
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 85
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 86
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 87
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 88
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 89
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 90
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 91
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 92
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 93
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 94
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 95
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 96
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 97
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 98
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 99
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 100
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 101
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 102
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 103
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 104
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 105
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 106
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 107
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 108
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 109
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 110
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 111
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 112
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 113
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 114
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 115
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 116
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 117
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 118
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 119
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 120
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 121
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 122
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 123
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 124
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 125
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 126
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 127
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 128
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 129
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 130
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 131
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 132
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 133
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 134
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 135
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 136
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 137
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 138
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 139
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 140
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 141
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 142
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 143
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 144
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 145
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 146
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 147
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 148
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 149
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 150
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 151
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 152
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 153
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 154
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 155
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 156
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 157
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 158
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 159
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 160
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 161
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 162
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 163
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 164
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 165
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 166
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 167
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 168
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 169
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 170
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 171
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 172
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 173
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 174
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 175
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 176
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 177
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 178
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 179
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 180
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 181
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 182
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 183
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 184
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 185
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 186
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 187
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 188
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 189
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 190
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 191
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop 192
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop 193
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 194
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 195
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 196
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 197
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 198
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 199
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 200
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 201
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept 202
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 203
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 204
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 205
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 206
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 207
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 208
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 209
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 210
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 211
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 212
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 213
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 214
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 215
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 216
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 217
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 218
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 219
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 220
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 221
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 222
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 223
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 224
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 225
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 226
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 227
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 228
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 229
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 230
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 231
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 232
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 233
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 234
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 235
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 236
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 237
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 238
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 239
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 240
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 241
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 242
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 243
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 260
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 261
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 262
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 263
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 264
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 265
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 266
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 267
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 268
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 269
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 270
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 271
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 272
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 273
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 274
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 275
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 276
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 277
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 278
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create 279
+#endif
+
+#if !defined(__NR_bpf)
+#define __NR_bpf 280
+#endif
+
+#if !defined(__NR_execveat)
+#define __NR_execveat 281
+#endif
+
+#if !defined(__NR_userfaultfd)
+#define __NR_userfaultfd 282
+#endif
+
+#if !defined(__NR_membarrier)
+#define __NR_membarrier 283
+#endif
+
+#if !defined(__NR_mlock2)
+#define __NR_mlock2 284
+#endif
+
+#if !defined(__NR_copy_file_range)
+#define __NR_copy_file_range 285
+#endif
+
+#if !defined(__NR_preadv2)
+#define __NR_preadv2 286
+#endif
+
+#if !defined(__NR_pwritev2)
+#define __NR_pwritev2 287
+#endif
+
+#if !defined(__NR_pkey_mprotect)
+#define __NR_pkey_mprotect 288
+#endif
+
+#if !defined(__NR_pkey_alloc)
+#define __NR_pkey_alloc 289
+#endif
+
+#if !defined(__NR_pkey_free)
+#define __NR_pkey_free 290
+#endif
+
+#if !defined(__NR_statx)
+#define __NR_statx 291
+#endif
+
+#if !defined(__NR_io_pgetevents)
+#define __NR_io_pgetevents 292
+#endif
+
+#if !defined(__NR_rseq)
+#define __NR_rseq 293
+#endif
+
+#if !defined(__NR_kexec_file_load)
+#define __NR_kexec_file_load 294
+#endif
+
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal 424
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup 425
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter 426
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register 427
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree 428
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount 429
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen 430
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig 431
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount 432
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick 433
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open 434
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 435
+#endif
+
+#if !defined(__NR_openat2)
+#define __NR_openat2 437
+#endif
+
+#if !defined(__NR_pidfd_getfd)
+#define __NR_pidfd_getfd 438
+#endif
+
+#if !defined(__NR_faccessat2)
+#define __NR_faccessat2 439
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_ARM64_LINUX_SYSCALLS_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h
new file mode 100644
index 0000000000..5b7f4e511a
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_syscalls.h
@@ -0,0 +1,1623 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* Constructed by running:
+ * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/arm/tools/syscall.tbl?h=v5.8
+ * | grep -vE '^#|^$'
+ * | awk '{ if ($2 != "oabi") { print "#if !defined(__NR_" $3 ")\n#define __NR_" $3 " (__NR_SYSCALL_BASE+" $1 ")\n#endif\n"; } }'
+ * */
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
+
+#if !defined(__arm__) || !defined(__ARM_EABI__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_SYSCALL_BASE)
+// On ARM EABI arch, __NR_SYSCALL_BASE is 0.
+#define __NR_SYSCALL_BASE 0
+#endif
+
+// This syscall list has holes, because ARM EABI makes some syscalls obsolete.
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall (__NR_SYSCALL_BASE+0)
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit (__NR_SYSCALL_BASE+1)
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork (__NR_SYSCALL_BASE+2)
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read (__NR_SYSCALL_BASE+3)
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write (__NR_SYSCALL_BASE+4)
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open (__NR_SYSCALL_BASE+5)
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close (__NR_SYSCALL_BASE+6)
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat (__NR_SYSCALL_BASE+8)
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link (__NR_SYSCALL_BASE+9)
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink (__NR_SYSCALL_BASE+10)
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve (__NR_SYSCALL_BASE+11)
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir (__NR_SYSCALL_BASE+12)
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod (__NR_SYSCALL_BASE+14)
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod (__NR_SYSCALL_BASE+15)
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown (__NR_SYSCALL_BASE+16)
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek (__NR_SYSCALL_BASE+19)
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid (__NR_SYSCALL_BASE+20)
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount (__NR_SYSCALL_BASE+21)
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid (__NR_SYSCALL_BASE+23)
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid (__NR_SYSCALL_BASE+24)
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace (__NR_SYSCALL_BASE+26)
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause (__NR_SYSCALL_BASE+29)
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access (__NR_SYSCALL_BASE+33)
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice (__NR_SYSCALL_BASE+34)
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync (__NR_SYSCALL_BASE+36)
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill (__NR_SYSCALL_BASE+37)
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename (__NR_SYSCALL_BASE+38)
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir (__NR_SYSCALL_BASE+39)
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir (__NR_SYSCALL_BASE+40)
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup (__NR_SYSCALL_BASE+41)
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe (__NR_SYSCALL_BASE+42)
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times (__NR_SYSCALL_BASE+43)
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk (__NR_SYSCALL_BASE+45)
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid (__NR_SYSCALL_BASE+46)
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid (__NR_SYSCALL_BASE+47)
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid (__NR_SYSCALL_BASE+49)
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid (__NR_SYSCALL_BASE+50)
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct (__NR_SYSCALL_BASE+51)
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 (__NR_SYSCALL_BASE+52)
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl (__NR_SYSCALL_BASE+54)
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl (__NR_SYSCALL_BASE+55)
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid (__NR_SYSCALL_BASE+57)
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask (__NR_SYSCALL_BASE+60)
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot (__NR_SYSCALL_BASE+61)
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat (__NR_SYSCALL_BASE+62)
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 (__NR_SYSCALL_BASE+63)
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid (__NR_SYSCALL_BASE+64)
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp (__NR_SYSCALL_BASE+65)
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid (__NR_SYSCALL_BASE+66)
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction (__NR_SYSCALL_BASE+67)
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid (__NR_SYSCALL_BASE+70)
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid (__NR_SYSCALL_BASE+71)
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend (__NR_SYSCALL_BASE+72)
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending (__NR_SYSCALL_BASE+73)
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname (__NR_SYSCALL_BASE+74)
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit (__NR_SYSCALL_BASE+75)
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage (__NR_SYSCALL_BASE+77)
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday (__NR_SYSCALL_BASE+78)
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday (__NR_SYSCALL_BASE+79)
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups (__NR_SYSCALL_BASE+80)
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups (__NR_SYSCALL_BASE+81)
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink (__NR_SYSCALL_BASE+83)
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink (__NR_SYSCALL_BASE+85)
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib (__NR_SYSCALL_BASE+86)
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon (__NR_SYSCALL_BASE+87)
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot (__NR_SYSCALL_BASE+88)
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap (__NR_SYSCALL_BASE+91)
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate (__NR_SYSCALL_BASE+92)
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate (__NR_SYSCALL_BASE+93)
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod (__NR_SYSCALL_BASE+94)
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown (__NR_SYSCALL_BASE+95)
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority (__NR_SYSCALL_BASE+96)
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority (__NR_SYSCALL_BASE+97)
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs (__NR_SYSCALL_BASE+99)
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs (__NR_SYSCALL_BASE+100)
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog (__NR_SYSCALL_BASE+103)
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer (__NR_SYSCALL_BASE+104)
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer (__NR_SYSCALL_BASE+105)
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat (__NR_SYSCALL_BASE+106)
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat (__NR_SYSCALL_BASE+107)
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat (__NR_SYSCALL_BASE+108)
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup (__NR_SYSCALL_BASE+111)
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 (__NR_SYSCALL_BASE+114)
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff (__NR_SYSCALL_BASE+115)
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo (__NR_SYSCALL_BASE+116)
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync (__NR_SYSCALL_BASE+118)
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn (__NR_SYSCALL_BASE+119)
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone (__NR_SYSCALL_BASE+120)
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname (__NR_SYSCALL_BASE+121)
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname (__NR_SYSCALL_BASE+122)
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex (__NR_SYSCALL_BASE+124)
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect (__NR_SYSCALL_BASE+125)
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask (__NR_SYSCALL_BASE+126)
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module (__NR_SYSCALL_BASE+128)
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module (__NR_SYSCALL_BASE+129)
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl (__NR_SYSCALL_BASE+131)
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid (__NR_SYSCALL_BASE+132)
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir (__NR_SYSCALL_BASE+133)
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush (__NR_SYSCALL_BASE+134)
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs (__NR_SYSCALL_BASE+135)
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality (__NR_SYSCALL_BASE+136)
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid (__NR_SYSCALL_BASE+138)
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid (__NR_SYSCALL_BASE+139)
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek (__NR_SYSCALL_BASE+140)
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents (__NR_SYSCALL_BASE+141)
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect (__NR_SYSCALL_BASE+142)
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock (__NR_SYSCALL_BASE+143)
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync (__NR_SYSCALL_BASE+144)
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv (__NR_SYSCALL_BASE+145)
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev (__NR_SYSCALL_BASE+146)
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid (__NR_SYSCALL_BASE+147)
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync (__NR_SYSCALL_BASE+148)
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl (__NR_SYSCALL_BASE+149)
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock (__NR_SYSCALL_BASE+150)
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock (__NR_SYSCALL_BASE+151)
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall (__NR_SYSCALL_BASE+152)
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall (__NR_SYSCALL_BASE+153)
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam (__NR_SYSCALL_BASE+154)
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam (__NR_SYSCALL_BASE+155)
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler (__NR_SYSCALL_BASE+156)
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler (__NR_SYSCALL_BASE+157)
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield (__NR_SYSCALL_BASE+158)
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max (__NR_SYSCALL_BASE+159)
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min (__NR_SYSCALL_BASE+160)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval (__NR_SYSCALL_BASE+161)
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep (__NR_SYSCALL_BASE+162)
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap (__NR_SYSCALL_BASE+163)
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid (__NR_SYSCALL_BASE+164)
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid (__NR_SYSCALL_BASE+165)
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll (__NR_SYSCALL_BASE+168)
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl (__NR_SYSCALL_BASE+169)
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid (__NR_SYSCALL_BASE+170)
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid (__NR_SYSCALL_BASE+171)
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl (__NR_SYSCALL_BASE+172)
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn (__NR_SYSCALL_BASE+173)
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction (__NR_SYSCALL_BASE+174)
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE+175)
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending (__NR_SYSCALL_BASE+176)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait (__NR_SYSCALL_BASE+177)
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo (__NR_SYSCALL_BASE+178)
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE+179)
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 (__NR_SYSCALL_BASE+180)
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 (__NR_SYSCALL_BASE+181)
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown (__NR_SYSCALL_BASE+182)
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd (__NR_SYSCALL_BASE+183)
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget (__NR_SYSCALL_BASE+184)
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset (__NR_SYSCALL_BASE+185)
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack (__NR_SYSCALL_BASE+186)
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile (__NR_SYSCALL_BASE+187)
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork (__NR_SYSCALL_BASE+190)
+#endif
+
+#if !defined(__NR_ugetrlimit)
+#define __NR_ugetrlimit (__NR_SYSCALL_BASE+191)
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 (__NR_SYSCALL_BASE+192)
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 (__NR_SYSCALL_BASE+193)
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 (__NR_SYSCALL_BASE+194)
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 (__NR_SYSCALL_BASE+195)
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 (__NR_SYSCALL_BASE+196)
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 (__NR_SYSCALL_BASE+197)
+#endif
+
+#if !defined(__NR_lchown32)
+#define __NR_lchown32 (__NR_SYSCALL_BASE+198)
+#endif
+
+#if !defined(__NR_getuid32)
+#define __NR_getuid32 (__NR_SYSCALL_BASE+199)
+#endif
+
+#if !defined(__NR_getgid32)
+#define __NR_getgid32 (__NR_SYSCALL_BASE+200)
+#endif
+
+#if !defined(__NR_geteuid32)
+#define __NR_geteuid32 (__NR_SYSCALL_BASE+201)
+#endif
+
+#if !defined(__NR_getegid32)
+#define __NR_getegid32 (__NR_SYSCALL_BASE+202)
+#endif
+
+#if !defined(__NR_setreuid32)
+#define __NR_setreuid32 (__NR_SYSCALL_BASE+203)
+#endif
+
+#if !defined(__NR_setregid32)
+#define __NR_setregid32 (__NR_SYSCALL_BASE+204)
+#endif
+
+#if !defined(__NR_getgroups32)
+#define __NR_getgroups32 (__NR_SYSCALL_BASE+205)
+#endif
+
+#if !defined(__NR_setgroups32)
+#define __NR_setgroups32 (__NR_SYSCALL_BASE+206)
+#endif
+
+#if !defined(__NR_fchown32)
+#define __NR_fchown32 (__NR_SYSCALL_BASE+207)
+#endif
+
+#if !defined(__NR_setresuid32)
+#define __NR_setresuid32 (__NR_SYSCALL_BASE+208)
+#endif
+
+#if !defined(__NR_getresuid32)
+#define __NR_getresuid32 (__NR_SYSCALL_BASE+209)
+#endif
+
+#if !defined(__NR_setresgid32)
+#define __NR_setresgid32 (__NR_SYSCALL_BASE+210)
+#endif
+
+#if !defined(__NR_getresgid32)
+#define __NR_getresgid32 (__NR_SYSCALL_BASE+211)
+#endif
+
+#if !defined(__NR_chown32)
+#define __NR_chown32 (__NR_SYSCALL_BASE+212)
+#endif
+
+#if !defined(__NR_setuid32)
+#define __NR_setuid32 (__NR_SYSCALL_BASE+213)
+#endif
+
+#if !defined(__NR_setgid32)
+#define __NR_setgid32 (__NR_SYSCALL_BASE+214)
+#endif
+
+#if !defined(__NR_setfsuid32)
+#define __NR_setfsuid32 (__NR_SYSCALL_BASE+215)
+#endif
+
+#if !defined(__NR_setfsgid32)
+#define __NR_setfsgid32 (__NR_SYSCALL_BASE+216)
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 (__NR_SYSCALL_BASE+217)
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root (__NR_SYSCALL_BASE+218)
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore (__NR_SYSCALL_BASE+219)
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise (__NR_SYSCALL_BASE+220)
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 (__NR_SYSCALL_BASE+221)
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid (__NR_SYSCALL_BASE+224)
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead (__NR_SYSCALL_BASE+225)
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr (__NR_SYSCALL_BASE+226)
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr (__NR_SYSCALL_BASE+227)
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr (__NR_SYSCALL_BASE+228)
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr (__NR_SYSCALL_BASE+229)
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr (__NR_SYSCALL_BASE+230)
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr (__NR_SYSCALL_BASE+231)
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr (__NR_SYSCALL_BASE+232)
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr (__NR_SYSCALL_BASE+233)
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr (__NR_SYSCALL_BASE+234)
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr (__NR_SYSCALL_BASE+235)
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr (__NR_SYSCALL_BASE+236)
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr (__NR_SYSCALL_BASE+237)
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill (__NR_SYSCALL_BASE+238)
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 (__NR_SYSCALL_BASE+239)
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex (__NR_SYSCALL_BASE+240)
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity (__NR_SYSCALL_BASE+241)
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity (__NR_SYSCALL_BASE+242)
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup (__NR_SYSCALL_BASE+243)
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy (__NR_SYSCALL_BASE+244)
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents (__NR_SYSCALL_BASE+245)
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit (__NR_SYSCALL_BASE+246)
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel (__NR_SYSCALL_BASE+247)
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group (__NR_SYSCALL_BASE+248)
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie (__NR_SYSCALL_BASE+249)
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create (__NR_SYSCALL_BASE+250)
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl (__NR_SYSCALL_BASE+251)
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait (__NR_SYSCALL_BASE+252)
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages (__NR_SYSCALL_BASE+253)
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address (__NR_SYSCALL_BASE+256)
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create (__NR_SYSCALL_BASE+257)
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime (__NR_SYSCALL_BASE+258)
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime (__NR_SYSCALL_BASE+259)
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun (__NR_SYSCALL_BASE+260)
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete (__NR_SYSCALL_BASE+261)
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime (__NR_SYSCALL_BASE+262)
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime (__NR_SYSCALL_BASE+263)
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres (__NR_SYSCALL_BASE+264)
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep (__NR_SYSCALL_BASE+265)
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 (__NR_SYSCALL_BASE+266)
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 (__NR_SYSCALL_BASE+267)
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill (__NR_SYSCALL_BASE+268)
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes (__NR_SYSCALL_BASE+269)
+#endif
+
+#if !defined(__NR_arm_fadvise64_64)
+#define __NR_arm_fadvise64_64 (__NR_SYSCALL_BASE+270)
+#endif
+
+#if !defined(__NR_pciconfig_iobase)
+#define __NR_pciconfig_iobase (__NR_SYSCALL_BASE+271)
+#endif
+
+#if !defined(__NR_pciconfig_read)
+#define __NR_pciconfig_read (__NR_SYSCALL_BASE+272)
+#endif
+
+#if !defined(__NR_pciconfig_write)
+#define __NR_pciconfig_write (__NR_SYSCALL_BASE+273)
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open (__NR_SYSCALL_BASE+274)
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink (__NR_SYSCALL_BASE+275)
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend (__NR_SYSCALL_BASE+276)
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive (__NR_SYSCALL_BASE+277)
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify (__NR_SYSCALL_BASE+278)
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr (__NR_SYSCALL_BASE+279)
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid (__NR_SYSCALL_BASE+280)
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket (__NR_SYSCALL_BASE+281)
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind (__NR_SYSCALL_BASE+282)
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect (__NR_SYSCALL_BASE+283)
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen (__NR_SYSCALL_BASE+284)
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept (__NR_SYSCALL_BASE+285)
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname (__NR_SYSCALL_BASE+286)
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername (__NR_SYSCALL_BASE+287)
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair (__NR_SYSCALL_BASE+288)
+#endif
+
+#if !defined(__NR_send)
+#define __NR_send (__NR_SYSCALL_BASE+289)
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto (__NR_SYSCALL_BASE+290)
+#endif
+
+#if !defined(__NR_recv)
+#define __NR_recv (__NR_SYSCALL_BASE+291)
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom (__NR_SYSCALL_BASE+292)
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown (__NR_SYSCALL_BASE+293)
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt (__NR_SYSCALL_BASE+294)
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt (__NR_SYSCALL_BASE+295)
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg (__NR_SYSCALL_BASE+296)
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg (__NR_SYSCALL_BASE+297)
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop (__NR_SYSCALL_BASE+298)
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget (__NR_SYSCALL_BASE+299)
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl (__NR_SYSCALL_BASE+300)
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd (__NR_SYSCALL_BASE+301)
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv (__NR_SYSCALL_BASE+302)
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget (__NR_SYSCALL_BASE+303)
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl (__NR_SYSCALL_BASE+304)
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat (__NR_SYSCALL_BASE+305)
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt (__NR_SYSCALL_BASE+306)
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget (__NR_SYSCALL_BASE+307)
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl (__NR_SYSCALL_BASE+308)
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key (__NR_SYSCALL_BASE+309)
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key (__NR_SYSCALL_BASE+310)
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl (__NR_SYSCALL_BASE+311)
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop (__NR_SYSCALL_BASE+312)
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver (__NR_SYSCALL_BASE+313)
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set (__NR_SYSCALL_BASE+314)
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get (__NR_SYSCALL_BASE+315)
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init (__NR_SYSCALL_BASE+316)
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch (__NR_SYSCALL_BASE+317)
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch (__NR_SYSCALL_BASE+318)
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind (__NR_SYSCALL_BASE+319)
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy (__NR_SYSCALL_BASE+320)
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy (__NR_SYSCALL_BASE+321)
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat (__NR_SYSCALL_BASE+322)
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat (__NR_SYSCALL_BASE+323)
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat (__NR_SYSCALL_BASE+324)
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat (__NR_SYSCALL_BASE+325)
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat (__NR_SYSCALL_BASE+326)
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 (__NR_SYSCALL_BASE+327)
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat (__NR_SYSCALL_BASE+328)
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat (__NR_SYSCALL_BASE+329)
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat (__NR_SYSCALL_BASE+330)
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat (__NR_SYSCALL_BASE+331)
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat (__NR_SYSCALL_BASE+332)
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat (__NR_SYSCALL_BASE+333)
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat (__NR_SYSCALL_BASE+334)
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 (__NR_SYSCALL_BASE+335)
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll (__NR_SYSCALL_BASE+336)
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare (__NR_SYSCALL_BASE+337)
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list (__NR_SYSCALL_BASE+338)
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list (__NR_SYSCALL_BASE+339)
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice (__NR_SYSCALL_BASE+340)
+#endif
+
+#if !defined(__NR_arm_sync_file_range)
+#define __NR_arm_sync_file_range (__NR_SYSCALL_BASE+341)
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee (__NR_SYSCALL_BASE+342)
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice (__NR_SYSCALL_BASE+343)
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages (__NR_SYSCALL_BASE+344)
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu (__NR_SYSCALL_BASE+345)
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait (__NR_SYSCALL_BASE+346)
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load (__NR_SYSCALL_BASE+347)
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat (__NR_SYSCALL_BASE+348)
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd (__NR_SYSCALL_BASE+349)
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create (__NR_SYSCALL_BASE+350)
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd (__NR_SYSCALL_BASE+351)
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate (__NR_SYSCALL_BASE+352)
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime (__NR_SYSCALL_BASE+353)
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime (__NR_SYSCALL_BASE+354)
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 (__NR_SYSCALL_BASE+355)
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 (__NR_SYSCALL_BASE+356)
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 (__NR_SYSCALL_BASE+357)
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 (__NR_SYSCALL_BASE+358)
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 (__NR_SYSCALL_BASE+359)
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 (__NR_SYSCALL_BASE+360)
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv (__NR_SYSCALL_BASE+361)
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev (__NR_SYSCALL_BASE+362)
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo (__NR_SYSCALL_BASE+363)
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open (__NR_SYSCALL_BASE+364)
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg (__NR_SYSCALL_BASE+365)
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 (__NR_SYSCALL_BASE+366)
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init (__NR_SYSCALL_BASE+367)
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark (__NR_SYSCALL_BASE+368)
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 (__NR_SYSCALL_BASE+369)
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at (__NR_SYSCALL_BASE+370)
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at (__NR_SYSCALL_BASE+371)
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime (__NR_SYSCALL_BASE+372)
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs (__NR_SYSCALL_BASE+373)
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg (__NR_SYSCALL_BASE+374)
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns (__NR_SYSCALL_BASE+375)
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv (__NR_SYSCALL_BASE+376)
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev (__NR_SYSCALL_BASE+377)
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp (__NR_SYSCALL_BASE+378)
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module (__NR_SYSCALL_BASE+379)
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 (__NR_SYSCALL_BASE+382)
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp (__NR_SYSCALL_BASE+383)
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom (__NR_SYSCALL_BASE+384)
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create (__NR_SYSCALL_BASE+385)
+#endif
+
+#if !defined(__NR_bpf)
+#define __NR_bpf (__NR_SYSCALL_BASE+386)
+#endif
+
+#if !defined(__NR_execveat)
+#define __NR_execveat (__NR_SYSCALL_BASE+387)
+#endif
+
+#if !defined(__NR_userfaultfd)
+#define __NR_userfaultfd (__NR_SYSCALL_BASE+388)
+#endif
+
+#if !defined(__NR_membarrier)
+#define __NR_membarrier (__NR_SYSCALL_BASE+389)
+#endif
+
+#if !defined(__NR_mlock2)
+#define __NR_mlock2 (__NR_SYSCALL_BASE+390)
+#endif
+
+#if !defined(__NR_copy_file_range)
+#define __NR_copy_file_range (__NR_SYSCALL_BASE+391)
+#endif
+
+#if !defined(__NR_preadv2)
+#define __NR_preadv2 (__NR_SYSCALL_BASE+392)
+#endif
+
+#if !defined(__NR_pwritev2)
+#define __NR_pwritev2 (__NR_SYSCALL_BASE+393)
+#endif
+
+#if !defined(__NR_pkey_mprotect)
+#define __NR_pkey_mprotect (__NR_SYSCALL_BASE+394)
+#endif
+
+#if !defined(__NR_pkey_alloc)
+#define __NR_pkey_alloc (__NR_SYSCALL_BASE+395)
+#endif
+
+#if !defined(__NR_pkey_free)
+#define __NR_pkey_free (__NR_SYSCALL_BASE+396)
+#endif
+
+#if !defined(__NR_statx)
+#define __NR_statx (__NR_SYSCALL_BASE+397)
+#endif
+
+#if !defined(__NR_rseq)
+#define __NR_rseq (__NR_SYSCALL_BASE+398)
+#endif
+
+#if !defined(__NR_io_pgetevents)
+#define __NR_io_pgetevents (__NR_SYSCALL_BASE+399)
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages (__NR_SYSCALL_BASE+400)
+#endif
+
+#if !defined(__NR_kexec_file_load)
+#define __NR_kexec_file_load (__NR_SYSCALL_BASE+401)
+#endif
+
+#if !defined(__NR_clock_gettime64)
+#define __NR_clock_gettime64 (__NR_SYSCALL_BASE+403)
+#endif
+
+#if !defined(__NR_clock_settime64)
+#define __NR_clock_settime64 (__NR_SYSCALL_BASE+404)
+#endif
+
+#if !defined(__NR_clock_adjtime64)
+#define __NR_clock_adjtime64 (__NR_SYSCALL_BASE+405)
+#endif
+
+#if !defined(__NR_clock_getres_time64)
+#define __NR_clock_getres_time64 (__NR_SYSCALL_BASE+406)
+#endif
+
+#if !defined(__NR_clock_nanosleep_time64)
+#define __NR_clock_nanosleep_time64 (__NR_SYSCALL_BASE+407)
+#endif
+
+#if !defined(__NR_timer_gettime64)
+#define __NR_timer_gettime64 (__NR_SYSCALL_BASE+408)
+#endif
+
+#if !defined(__NR_timer_settime64)
+#define __NR_timer_settime64 (__NR_SYSCALL_BASE+409)
+#endif
+
+#if !defined(__NR_timerfd_gettime64)
+#define __NR_timerfd_gettime64 (__NR_SYSCALL_BASE+410)
+#endif
+
+#if !defined(__NR_timerfd_settime64)
+#define __NR_timerfd_settime64 (__NR_SYSCALL_BASE+411)
+#endif
+
+#if !defined(__NR_utimensat_time64)
+#define __NR_utimensat_time64 (__NR_SYSCALL_BASE+412)
+#endif
+
+#if !defined(__NR_pselect6_time64)
+#define __NR_pselect6_time64 (__NR_SYSCALL_BASE+413)
+#endif
+
+#if !defined(__NR_ppoll_time64)
+#define __NR_ppoll_time64 (__NR_SYSCALL_BASE+414)
+#endif
+
+#if !defined(__NR_io_pgetevents_time64)
+#define __NR_io_pgetevents_time64 (__NR_SYSCALL_BASE+416)
+#endif
+
+#if !defined(__NR_recvmmsg_time64)
+#define __NR_recvmmsg_time64 (__NR_SYSCALL_BASE+417)
+#endif
+
+#if !defined(__NR_mq_timedsend_time64)
+#define __NR_mq_timedsend_time64 (__NR_SYSCALL_BASE+418)
+#endif
+
+#if !defined(__NR_mq_timedreceive_time64)
+#define __NR_mq_timedreceive_time64 (__NR_SYSCALL_BASE+419)
+#endif
+
+#if !defined(__NR_semtimedop_time64)
+#define __NR_semtimedop_time64 (__NR_SYSCALL_BASE+420)
+#endif
+
+#if !defined(__NR_rt_sigtimedwait_time64)
+#define __NR_rt_sigtimedwait_time64 (__NR_SYSCALL_BASE+421)
+#endif
+
+#if !defined(__NR_futex_time64)
+#define __NR_futex_time64 (__NR_SYSCALL_BASE+422)
+#endif
+
+#if !defined(__NR_sched_rr_get_interval_time64)
+#define __NR_sched_rr_get_interval_time64 (__NR_SYSCALL_BASE+423)
+#endif
+
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal (__NR_SYSCALL_BASE+424)
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup (__NR_SYSCALL_BASE+425)
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter (__NR_SYSCALL_BASE+426)
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register (__NR_SYSCALL_BASE+427)
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree (__NR_SYSCALL_BASE+428)
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount (__NR_SYSCALL_BASE+429)
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen (__NR_SYSCALL_BASE+430)
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig (__NR_SYSCALL_BASE+431)
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount (__NR_SYSCALL_BASE+432)
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick (__NR_SYSCALL_BASE+433)
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open (__NR_SYSCALL_BASE+434)
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 (__NR_SYSCALL_BASE+435)
+#endif
+
+#if !defined(__NR_openat2)
+#define __NR_openat2 (__NR_SYSCALL_BASE+437)
+#endif
+
+#if !defined(__NR_pidfd_getfd)
+#define __NR_pidfd_getfd (__NR_SYSCALL_BASE+438)
+#endif
+
+#if !defined(__NR_faccessat2)
+#define __NR_faccessat2 (__NR_SYSCALL_BASE+439)
+#endif
+
+// ARM private syscalls.
+#if !defined(__ARM_NR_BASE)
+#define __ARM_NR_BASE (__NR_SYSCALL_BASE + 0xF0000)
+#endif
+
+#if !defined(__ARM_NR_breakpoint)
+#define __ARM_NR_breakpoint (__ARM_NR_BASE+1)
+#endif
+
+#if !defined(__ARM_NR_cacheflush)
+#define __ARM_NR_cacheflush (__ARM_NR_BASE+2)
+#endif
+
+#if !defined(__ARM_NR_usr26)
+#define __ARM_NR_usr26 (__ARM_NR_BASE+3)
+#endif
+
+#if !defined(__ARM_NR_usr32)
+#define __ARM_NR_usr32 (__ARM_NR_BASE+4)
+#endif
+
+#if !defined(__ARM_NR_set_tls)
+#define __ARM_NR_set_tls (__ARM_NR_BASE+5)
+#endif
+
+// ARM kernel private syscall.
+#if !defined(__ARM_NR_cmpxchg)
+#define __ARM_NR_cmpxchg (__ARM_NR_BASE+0x00fff0)
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_SYSCALLS_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_ucontext.h b/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_ucontext.h
new file mode 100644
index 0000000000..2b2090e392
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/arm_linux_ucontext.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
+
+#include <stddef.h>
+
+// In PNaCl toolchain, sigcontext and stack_t is not defined. So here declare
+// them.
+struct sigcontext {
+ unsigned long trap_no;
+ unsigned long error_code;
+ unsigned long oldmask;
+ unsigned long arm_r0;
+ unsigned long arm_r1;
+ unsigned long arm_r2;
+ unsigned long arm_r3;
+ unsigned long arm_r4;
+ unsigned long arm_r5;
+ unsigned long arm_r6;
+ unsigned long arm_r7;
+ unsigned long arm_r8;
+ unsigned long arm_r9;
+ unsigned long arm_r10;
+ unsigned long arm_fp;
+ unsigned long arm_ip;
+ unsigned long arm_sp;
+ unsigned long arm_lr;
+ unsigned long arm_pc;
+ unsigned long arm_cpsr;
+ unsigned long fault_address;
+};
+
+typedef struct sigaltstack {
+ void* ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
+
+// We also need greg_t for the sandbox, include it in this header as well.
+typedef unsigned long greg_t;
+
+// typedef unsigned long sigset_t;
+typedef struct ucontext {
+ unsigned long uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask;
+ /* Allow for uc_sigmask growth. Glibc uses a 1024-bit sigset_t. */
+ int __not_used[32 - (sizeof(sigset_t) / sizeof(int))];
+ /* Last for extensibility. Eight byte aligned because some
+ coprocessors require eight byte alignment. */
+ unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
+} ucontext_t;
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_ARM_LINUX_UCONTEXT_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/capability.h b/security/sandbox/chromium/sandbox/linux/system_headers/capability.h
new file mode 100644
index 0000000000..f91fcf78ac
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/capability.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
+
+#include <stdint.h>
+
+// The following macros are taken from linux/capability.h.
+// We only support capability version 3, which was introduced in Linux 2.6.26.
+#ifndef _LINUX_CAPABILITY_VERSION_3
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#endif
+#ifndef _LINUX_CAPABILITY_U32S_3
+#define _LINUX_CAPABILITY_U32S_3 2
+#endif
+#ifndef CAP_TO_INDEX
+#define CAP_TO_INDEX(x) ((x) >> 5) // 1 << 5 == bits in __u32
+#endif
+#ifndef CAP_TO_MASK
+#define CAP_TO_MASK(x) (1 << ((x) & 31)) // mask for indexed __u32
+#endif
+#ifndef CAP_SYS_CHROOT
+#define CAP_SYS_CHROOT 18
+#endif
+#ifndef CAP_SYS_ADMIN
+#define CAP_SYS_ADMIN 21
+#endif
+
+struct cap_hdr {
+ uint32_t version;
+ int pid;
+};
+
+struct cap_data {
+ uint32_t effective;
+ uint32_t permitted;
+ uint32_t inheritable;
+};
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_CAPABILITY_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/i386_linux_ucontext.h b/security/sandbox/chromium/sandbox/linux/system_headers/i386_linux_ucontext.h
new file mode 100644
index 0000000000..1a7b975de8
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/i386_linux_ucontext.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+// This is mostly copied from breakpad (common/android/include/sys/ucontext.h),
+// except we do use sigset_t for uc_sigmask instead of a custom type.
+
+// In PNaCl toolchain, sigcontext is not defined. So here declare it.
+typedef struct sigaltstack {
+ void* ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
+/* 80-bit floating-point register */
+struct _libc_fpreg {
+ unsigned short significand[4];
+ unsigned short exponent;
+};
+
+/* Simple floating-point state, see FNSTENV instruction */
+struct _libc_fpstate {
+ unsigned long cw;
+ unsigned long sw;
+ unsigned long tag;
+ unsigned long ipoff;
+ unsigned long cssel;
+ unsigned long dataoff;
+ unsigned long datasel;
+ struct _libc_fpreg _st[8];
+ unsigned long status;
+};
+
+typedef uint32_t greg_t;
+
+typedef struct {
+ uint32_t gregs[19];
+ struct _libc_fpstate* fpregs;
+ uint32_t oldmask;
+ uint32_t cr2;
+} mcontext_t;
+
+enum {
+ REG_GS = 0,
+ REG_FS,
+ REG_ES,
+ REG_DS,
+ REG_EDI,
+ REG_ESI,
+ REG_EBP,
+ REG_ESP,
+ REG_EBX,
+ REG_EDX,
+ REG_ECX,
+ REG_EAX,
+ REG_TRAPNO,
+ REG_ERR,
+ REG_EIP,
+ REG_CS,
+ REG_EFL,
+ REG_UESP,
+ REG_SS,
+};
+
+typedef struct ucontext {
+ uint32_t uc_flags;
+ struct ucontext* uc_link;
+ stack_t uc_stack;
+ mcontext_t uc_mcontext;
+ // Android and PNaCl toolchain's sigset_t has only 32 bits, though Linux
+ // ABI requires 64 bits.
+ union {
+ sigset_t uc_sigmask;
+ uint32_t kernel_sigmask[2];
+ };
+ struct _libc_fpstate __fpregs_mem;
+} ucontext_t;
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_ANDROID_I386_UCONTEXT_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/linux_filter.h b/security/sandbox/chromium/sandbox/linux/system_headers/linux_filter.h
new file mode 100644
index 0000000000..b23b6eb0c1
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/linux_filter.h
@@ -0,0 +1,140 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
+
+#include <stdint.h>
+
+// The following structs and macros are taken from linux/filter.h,
+// as some toolchain does not expose them.
+struct sock_filter {
+ uint16_t code;
+ uint8_t jt;
+ uint8_t jf;
+ uint32_t k;
+};
+
+struct sock_fprog {
+ uint16_t len;
+ struct sock_filter *filter;
+};
+
+#ifndef BPF_CLASS
+#define BPF_CLASS(code) ((code) & 0x07)
+#endif
+
+#ifndef BPF_LD
+#define BPF_LD 0x00
+#endif
+
+#ifndef BPF_ALU
+#define BPF_ALU 0x04
+#endif
+
+#ifndef BPF_JMP
+#define BPF_JMP 0x05
+#endif
+
+#ifndef BPF_RET
+#define BPF_RET 0x06
+#endif
+
+#ifndef BPF_SIZE
+#define BPF_SIZE(code) ((code) & 0x18)
+#endif
+
+#ifndef BPF_W
+#define BPF_W 0x00
+#endif
+
+#ifndef BPF_MODE
+#define BPF_MODE(code) ((code) & 0xe0)
+#endif
+
+#ifndef BPF_ABS
+#define BPF_ABS 0x20
+#endif
+
+#ifndef BPF_OP
+#define BPF_OP(code) ((code) & 0xf0)
+#endif
+
+#ifndef BPF_ADD
+#define BPF_ADD 0x00
+#endif
+
+#ifndef BPF_SUB
+#define BPF_SUB 0x10
+#endif
+
+#ifndef BPF_MUL
+#define BPF_MUL 0x20
+#endif
+
+#ifndef BPF_DIV
+#define BPF_DIV 0x30
+#endif
+
+#ifndef BPF_OR
+#define BPF_OR 0x40
+#endif
+
+#ifndef BPF_AND
+#define BPF_AND 0x50
+#endif
+
+#ifndef BPF_LSH
+#define BPF_LSH 0x60
+#endif
+
+#ifndef BPF_RSH
+#define BPF_RSH 0x70
+#endif
+
+#ifndef BPF_NEG
+#define BPF_NEG 0x80
+#endif
+
+#ifndef BPF_MOD
+#define BPF_MOD 0x90
+#endif
+
+#ifndef BPF_XOR
+#define BPF_XOR 0xA0
+#endif
+
+#ifndef BPF_JA
+#define BPF_JA 0x00
+#endif
+
+#ifndef BPF_JEQ
+#define BPF_JEQ 0x10
+#endif
+
+#ifndef BPF_JGT
+#define BPF_JGT 0x20
+#endif
+
+#ifndef BPF_JGE
+#define BPF_JGE 0x30
+#endif
+
+#ifndef BPF_JSET
+#define BPF_JSET 0x40
+#endif
+
+#ifndef BPF_SRC
+#define BPF_SRC(code) ((code) & 0x08)
+#endif
+
+#ifndef BPF_K
+#define BPF_K 0x00
+#endif
+
+#ifndef BPF_MAXINSNS
+#define BPF_MAXINSNS 4096
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FILTER_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/linux_futex.h b/security/sandbox/chromium/sandbox/linux/system_headers/linux_futex.h
new file mode 100644
index 0000000000..4e28403336
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/linux_futex.h
@@ -0,0 +1,84 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
+
+#if !defined(__native_client_nonsfi__)
+#include <linux/futex.h>
+#endif // !defined(__native_client_nonsfi__)
+
+#if !defined(FUTEX_WAIT)
+#define FUTEX_WAIT 0
+#endif
+
+#if !defined(FUTEX_WAKE)
+#define FUTEX_WAKE 1
+#endif
+
+#if !defined(FUTEX_FD)
+#define FUTEX_FD 2
+#endif
+
+#if !defined(FUTEX_REQUEUE)
+#define FUTEX_REQUEUE 3
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE)
+#define FUTEX_CMP_REQUEUE 4
+#endif
+
+#if !defined(FUTEX_WAKE_OP)
+#define FUTEX_WAKE_OP 5
+#endif
+
+#if !defined(FUTEX_LOCK_PI)
+#define FUTEX_LOCK_PI 6
+#endif
+
+#if !defined(FUTEX_UNLOCK_PI)
+#define FUTEX_UNLOCK_PI 7
+#endif
+
+#if !defined(FUTEX_TRYLOCK_PI)
+#define FUTEX_TRYLOCK_PI 8
+#endif
+
+#if !defined(FUTEX_WAIT_BITSET)
+#define FUTEX_WAIT_BITSET 9
+#endif
+
+#if !defined(FUTEX_WAKE_BITSET)
+#define FUTEX_WAKE_BITSET 10
+#endif
+
+#if !defined(FUTEX_WAIT_REQUEUE_PI)
+#define FUTEX_WAIT_REQUEUE_PI 11
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE_PI)
+#define FUTEX_CMP_REQUEUE_PI 12
+#endif
+
+#if !defined(FUTEX_PRIVATE_FLAG)
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+
+#if !defined FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+
+#if !defined(FUTEX_CMD_MASK)
+#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
+#endif
+
+#if !defined(FUTEX_CMP_REQUEUE_PI_PRIVATE)
+#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | FUTEX_PRIVATE_FLAG)
+#endif
+
+#if !defined(FUTEX_UNLOCK_PI_PRIVATE)
+#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/linux_seccomp.h b/security/sandbox/chromium/sandbox/linux/system_headers/linux_seccomp.h
new file mode 100644
index 0000000000..a60fe2ad3d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/linux_seccomp.h
@@ -0,0 +1,110 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
+
+// The Seccomp2 kernel ABI is not part of older versions of glibc.
+// As we can't break compilation with these versions of the library,
+// we explicitly define all missing symbols.
+// If we ever decide that we can now rely on system headers, the following
+// include files should be enabled:
+// #include <linux/audit.h>
+// #include <linux/seccomp.h>
+
+// For audit.h
+#ifndef EM_ARM
+#define EM_ARM 40
+#endif
+#ifndef EM_386
+#define EM_386 3
+#endif
+#ifndef EM_X86_64
+#define EM_X86_64 62
+#endif
+#ifndef EM_MIPS
+#define EM_MIPS 8
+#endif
+#ifndef EM_AARCH64
+#define EM_AARCH64 183
+#endif
+
+#ifndef __AUDIT_ARCH_64BIT
+#define __AUDIT_ARCH_64BIT 0x80000000
+#endif
+#ifndef __AUDIT_ARCH_LE
+#define __AUDIT_ARCH_LE 0x40000000
+#endif
+#ifndef AUDIT_ARCH_ARM
+#define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_I386
+#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_X86_64
+#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_MIPSEL
+#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_MIPSEL64
+#define AUDIT_ARCH_MIPSEL64 (EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#endif
+#ifndef AUDIT_ARCH_AARCH64
+#define AUDIT_ARCH_AARCH64 (EM_AARCH64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
+#endif
+
+// For prctl.h
+#ifndef PR_SET_SECCOMP
+#define PR_SET_SECCOMP 22
+#define PR_GET_SECCOMP 21
+#endif
+#ifndef PR_SET_NO_NEW_PRIVS
+#define PR_SET_NO_NEW_PRIVS 38
+#define PR_GET_NO_NEW_PRIVS 39
+#endif
+#ifndef IPC_64
+#define IPC_64 0x0100
+#endif
+
+// In order to build will older tool chains, we currently have to avoid
+// including <linux/seccomp.h>. Until that can be fixed (if ever). Rely on
+// our own definitions of the seccomp kernel ABI.
+#ifndef SECCOMP_MODE_FILTER
+#define SECCOMP_MODE_DISABLED 0
+#define SECCOMP_MODE_STRICT 1
+#define SECCOMP_MODE_FILTER 2 // User user-supplied filter
+#endif
+
+#ifndef SECCOMP_SET_MODE_STRICT
+#define SECCOMP_SET_MODE_STRICT 0
+#endif
+#ifndef SECCOMP_SET_MODE_FILTER
+#define SECCOMP_SET_MODE_FILTER 1
+#endif
+#ifndef SECCOMP_FILTER_FLAG_TSYNC
+#define SECCOMP_FILTER_FLAG_TSYNC 1
+#endif
+
+#ifndef SECCOMP_RET_KILL
+// Return values supported for BPF filter programs. Please note that the
+// "illegal" SECCOMP_RET_INVALID is not supported by the kernel, should only
+// ever be used internally, and would result in the kernel killing our process.
+#define SECCOMP_RET_KILL 0x00000000U // Kill the task immediately
+#define SECCOMP_RET_INVALID 0x00010000U // Illegal return value
+#define SECCOMP_RET_TRAP 0x00030000U // Disallow and force a SIGSYS
+#define SECCOMP_RET_ERRNO 0x00050000U // Returns an errno
+#define SECCOMP_RET_TRACE 0x7ff00000U // Pass to a tracer or disallow
+#define SECCOMP_RET_ALLOW 0x7fff0000U // Allow
+#define SECCOMP_RET_ACTION 0xffff0000U // Masks for the return value
+#define SECCOMP_RET_DATA 0x0000ffffU // sections
+#else
+#define SECCOMP_RET_INVALID 0x00010000U // Illegal return value
+#endif
+
+#ifndef SYS_SECCOMP
+#define SYS_SECCOMP 1
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SECCOMP_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/linux_signal.h b/security/sandbox/chromium/sandbox/linux/system_headers/linux_signal.h
new file mode 100644
index 0000000000..f5a7367617
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/linux_signal.h
@@ -0,0 +1,150 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
+
+#include <stdint.h>
+
+#include "build/build_config.h"
+
+// NOTE: On some toolchains, signal related ABI is incompatible with Linux's
+// (not undefined, but defined different values and in different memory
+// layouts). So, fill the gap here.
+#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
+ defined(__aarch64__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 7
+#define LINUX_SIGUSR1 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGUSR2 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGCHLD 17
+#define LINUX_SIGSYS 31
+
+#define LINUX_SIG_BLOCK 0
+#define LINUX_SIG_UNBLOCK 1
+
+#define LINUX_SA_SIGINFO 4
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#elif defined(__mips__)
+
+#define LINUX_SIGHUP 1
+#define LINUX_SIGINT 2
+#define LINUX_SIGQUIT 3
+#define LINUX_SIGABRT 6
+#define LINUX_SIGBUS 10
+#define LINUX_SIGSEGV 11
+#define LINUX_SIGSYS 12
+#define LINUX_SIGPIPE 13
+#define LINUX_SIGTERM 15
+#define LINUX_SIGUSR1 16
+#define LINUX_SIGUSR2 17
+#define LINUX_SIGCHLD 18
+
+#define LINUX_SIG_BLOCK 1
+#define LINUX_SIG_UNBLOCK 2
+
+#define LINUX_SA_SIGINFO 0x00000008
+#define LINUX_SA_NODEFER 0x40000000
+#define LINUX_SA_RESTART 0x10000000
+
+#define LINUX_SIG_DFL 0
+
+#else
+#error "Unsupported platform"
+#endif
+
+#if defined(__native_client_nonsfi__)
+#if !defined(__i386__) && !defined(__arm__)
+#error "Unsupported platform"
+#endif
+
+#include <signal.h>
+
+struct LinuxSigInfo {
+ int si_signo;
+ int si_errno;
+ int si_code;
+
+ // Extra data is followed by the |si_code|. The length depends on the
+ // signal number.
+ char _sifields[1];
+};
+
+#include "sandbox/linux/system_headers/linux_ucontext.h"
+
+#else // !defined(__native_client_nonsfi__)
+
+#include <signal.h>
+
+static_assert(LINUX_SIGHUP == SIGHUP, "LINUX_SIGHUP == SIGHUP");
+static_assert(LINUX_SIGINT == SIGINT, "LINUX_SIGINT == SIGINT");
+static_assert(LINUX_SIGQUIT == SIGQUIT, "LINUX_SIGQUIT == SIGQUIT");
+static_assert(LINUX_SIGABRT == SIGABRT, "LINUX_SIGABRT == SIGABRT");
+static_assert(LINUX_SIGBUS == SIGBUS, "LINUX_SIGBUS == SIGBUS");
+static_assert(LINUX_SIGUSR1 == SIGUSR1, "LINUX_SIGUSR1 == SIGUSR1");
+static_assert(LINUX_SIGSEGV == SIGSEGV, "LINUX_SIGSEGV == SIGSEGV");
+static_assert(LINUX_SIGUSR2 == SIGUSR2, "LINUX_SIGUSR2 == SIGUSR2");
+static_assert(LINUX_SIGPIPE == SIGPIPE, "LINUX_SIGPIPE == SIGPIPE");
+static_assert(LINUX_SIGTERM == SIGTERM, "LINUX_SIGTERM == SIGTERM");
+static_assert(LINUX_SIGCHLD == SIGCHLD, "LINUX_SIGCHLD == SIGCHLD");
+static_assert(LINUX_SIGSYS == SIGSYS, "LINUX_SIGSYS == SIGSYS");
+static_assert(LINUX_SIG_BLOCK == SIG_BLOCK, "LINUX_SIG_BLOCK == SIG_BLOCK");
+static_assert(LINUX_SIG_UNBLOCK == SIG_UNBLOCK,
+ "LINUX_SIG_UNBLOCK == SIG_UNBLOCK");
+static_assert(LINUX_SA_SIGINFO == SA_SIGINFO, "LINUX_SA_SIGINFO == SA_SIGINFO");
+static_assert(LINUX_SA_NODEFER == SA_NODEFER, "LINUX_SA_NODEFER == SA_NODEFER");
+static_assert(LINUX_SA_RESTART == SA_RESTART, "LINUX_SA_RESTART == SA_RESTART");
+static_assert(LINUX_SIG_DFL == SIG_DFL, "LINUX_SIG_DFL == SIG_DFL");
+
+typedef siginfo_t LinuxSigInfo;
+
+#endif // !defined(__native_client_nonsfi__)
+
+// struct sigset_t is different size in PNaCl from the Linux's.
+#if (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
+#if !defined(_NSIG_WORDS)
+#define _NSIG_WORDS 4
+#endif
+struct LinuxSigSet {
+ unsigned long sig[_NSIG_WORDS];
+};
+#elif defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+#if !defined(_NSIG_WORDS)
+#define _NSIG_WORDS 2
+#endif
+struct LinuxSigSet {
+ unsigned long sig[_NSIG_WORDS];
+};
+#else
+typedef uint64_t LinuxSigSet;
+#endif
+
+// struct sigaction is different in PNaCl from the Linux's.
+#if defined(__mips__)
+struct LinuxSigAction {
+ unsigned int sa_flags;
+ void (*kernel_handler)(int);
+ LinuxSigSet sa_mask;
+};
+#else
+struct LinuxSigAction {
+ void (*kernel_handler)(int);
+ uint32_t sa_flags;
+ void (*sa_restorer)(void);
+ LinuxSigSet sa_mask;
+};
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SIGNAL_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/linux_syscalls.h
new file mode 100644
index 0000000000..2b78a0cc3b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/linux_syscalls.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This header will be kept up to date so that we can compile system-call
+// policies even when system headers are old.
+// System call numbers are accessible through __NR_syscall_name.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+
+#include "build/build_config.h"
+
+#if defined(__x86_64__)
+#include "sandbox/linux/system_headers/x86_64_linux_syscalls.h"
+#endif
+
+#if defined(__i386__)
+#include "sandbox/linux/system_headers/x86_32_linux_syscalls.h"
+#endif
+
+#if defined(__arm__) && defined(__ARM_EABI__)
+#include "sandbox/linux/system_headers/arm_linux_syscalls.h"
+#endif
+
+#if (defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_32_BITS))
+#include "sandbox/linux/system_headers/mips_linux_syscalls.h"
+#endif
+
+#if defined(ARCH_CPU_MIPS_FAMILY) && defined(ARCH_CPU_64_BITS)
+#include "sandbox/linux/system_headers/mips64_linux_syscalls.h"
+#endif
+
+#if defined(__aarch64__)
+#include "sandbox/linux/system_headers/arm64_linux_syscalls.h"
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_SYSCALLS_H_
+
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/linux_ucontext.h b/security/sandbox/chromium/sandbox/linux/system_headers/linux_ucontext.h
new file mode 100644
index 0000000000..22ce780274
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/linux_ucontext.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
+
+#if defined(__native_client_nonsfi__)
+
+#if defined(__arm__)
+#include "sandbox/linux/system_headers/arm_linux_ucontext.h"
+#elif defined(__i386__)
+#include "sandbox/linux/system_headers/i386_linux_ucontext.h"
+#else
+#error "No support for your architecture in PNaCl header"
+#endif
+
+#else // defined(__native_client_nonsfi__)
+#error "The header file included on non PNaCl."
+#endif // defined(__native_client_nonsfi__)
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_UCONTEXT_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
new file mode 100644
index 0000000000..dc846ee7ad
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
@@ -0,0 +1,1731 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* Constructed by running:
+ * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/x86/entry/syscalls/syscall_32.tbl?h=v5.8
+ * | grep -vE '^#|^$'
+ * | awk '{ if ($2 == "i386") { print "#if !defined(__NR_" $3 ")\n#define __NR_" $3 " " $1 "\n#endif\n"; } }'
+ * */
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
+
+#if !defined(__i386__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 0
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 1
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork 2
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 3
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 4
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open 5
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 6
+#endif
+
+#if !defined(__NR_waitpid)
+#define __NR_waitpid 7
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat 8
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link 9
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink 10
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 11
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 12
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time 13
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod 14
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod 15
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown 16
+#endif
+
+#if !defined(__NR_break)
+#define __NR_break 17
+#endif
+
+#if !defined(__NR_oldstat)
+#define __NR_oldstat 18
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 19
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 20
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 21
+#endif
+
+#if !defined(__NR_umount)
+#define __NR_umount 22
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 23
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 24
+#endif
+
+#if !defined(__NR_stime)
+#define __NR_stime 25
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 26
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm 27
+#endif
+
+#if !defined(__NR_oldfstat)
+#define __NR_oldfstat 28
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause 29
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime 30
+#endif
+
+#if !defined(__NR_stty)
+#define __NR_stty 31
+#endif
+
+#if !defined(__NR_gtty)
+#define __NR_gtty 32
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access 33
+#endif
+
+#if !defined(__NR_nice)
+#define __NR_nice 34
+#endif
+
+#if !defined(__NR_ftime)
+#define __NR_ftime 35
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 36
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 37
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename 38
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir 39
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir 40
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 41
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe 42
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 43
+#endif
+
+#if !defined(__NR_prof)
+#define __NR_prof 44
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 45
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 46
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 47
+#endif
+
+#if !defined(__NR_signal)
+#define __NR_signal 48
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 49
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 50
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 51
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 52
+#endif
+
+#if !defined(__NR_lock)
+#define __NR_lock 53
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 54
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 55
+#endif
+
+#if !defined(__NR_mpx)
+#define __NR_mpx 56
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 57
+#endif
+
+#if !defined(__NR_ulimit)
+#define __NR_ulimit 58
+#endif
+
+#if !defined(__NR_oldolduname)
+#define __NR_oldolduname 59
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 60
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 61
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat 62
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 63
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 64
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp 65
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 66
+#endif
+
+#if !defined(__NR_sigaction)
+#define __NR_sigaction 67
+#endif
+
+#if !defined(__NR_sgetmask)
+#define __NR_sgetmask 68
+#endif
+
+#if !defined(__NR_ssetmask)
+#define __NR_ssetmask 69
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 70
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 71
+#endif
+
+#if !defined(__NR_sigsuspend)
+#define __NR_sigsuspend 72
+#endif
+
+#if !defined(__NR_sigpending)
+#define __NR_sigpending 73
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 74
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 75
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 76
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 77
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 78
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 79
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 80
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 81
+#endif
+
+#if !defined(__NR_select)
+#define __NR_select 82
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink 83
+#endif
+
+#if !defined(__NR_oldlstat)
+#define __NR_oldlstat 84
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink 85
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib 86
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 87
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 88
+#endif
+
+#if !defined(__NR_readdir)
+#define __NR_readdir 89
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 90
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 91
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 92
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 93
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 94
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 95
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 96
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 97
+#endif
+
+#if !defined(__NR_profil)
+#define __NR_profil 98
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 99
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 100
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm 101
+#endif
+
+#if !defined(__NR_socketcall)
+#define __NR_socketcall 102
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 103
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 104
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 105
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat 106
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat 107
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 108
+#endif
+
+#if !defined(__NR_olduname)
+#define __NR_olduname 109
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl 110
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 111
+#endif
+
+#if !defined(__NR_idle)
+#define __NR_idle 112
+#endif
+
+#if !defined(__NR_vm86old)
+#define __NR_vm86old 113
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 114
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 115
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 116
+#endif
+
+#if !defined(__NR_ipc)
+#define __NR_ipc 117
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 118
+#endif
+
+#if !defined(__NR_sigreturn)
+#define __NR_sigreturn 119
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 120
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 121
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 122
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt 123
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 124
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 125
+#endif
+
+#if !defined(__NR_sigprocmask)
+#define __NR_sigprocmask 126
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module 127
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 128
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 129
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms 130
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 131
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 132
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 133
+#endif
+
+#if !defined(__NR_bdflush)
+#define __NR_bdflush 134
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs 135
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 136
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall 137
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 138
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 139
+#endif
+
+#if !defined(__NR__llseek)
+#define __NR__llseek 140
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents 141
+#endif
+
+#if !defined(__NR__newselect)
+#define __NR__newselect 142
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 143
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 144
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 145
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 146
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 147
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 148
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl 149
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 150
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 151
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 152
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 153
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 154
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 155
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 156
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 157
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 158
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 159
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 160
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 161
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 162
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 163
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 164
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 165
+#endif
+
+#if !defined(__NR_vm86)
+#define __NR_vm86 166
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module 167
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll 168
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 169
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 170
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 171
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 172
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 173
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 174
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 175
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 176
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 177
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 178
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 179
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 180
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 181
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown 182
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 183
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 184
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 185
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 186
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 187
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg 188
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg 189
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork 190
+#endif
+
+#if !defined(__NR_ugetrlimit)
+#define __NR_ugetrlimit 191
+#endif
+
+#if !defined(__NR_mmap2)
+#define __NR_mmap2 192
+#endif
+
+#if !defined(__NR_truncate64)
+#define __NR_truncate64 193
+#endif
+
+#if !defined(__NR_ftruncate64)
+#define __NR_ftruncate64 194
+#endif
+
+#if !defined(__NR_stat64)
+#define __NR_stat64 195
+#endif
+
+#if !defined(__NR_lstat64)
+#define __NR_lstat64 196
+#endif
+
+#if !defined(__NR_fstat64)
+#define __NR_fstat64 197
+#endif
+
+#if !defined(__NR_lchown32)
+#define __NR_lchown32 198
+#endif
+
+#if !defined(__NR_getuid32)
+#define __NR_getuid32 199
+#endif
+
+#if !defined(__NR_getgid32)
+#define __NR_getgid32 200
+#endif
+
+#if !defined(__NR_geteuid32)
+#define __NR_geteuid32 201
+#endif
+
+#if !defined(__NR_getegid32)
+#define __NR_getegid32 202
+#endif
+
+#if !defined(__NR_setreuid32)
+#define __NR_setreuid32 203
+#endif
+
+#if !defined(__NR_setregid32)
+#define __NR_setregid32 204
+#endif
+
+#if !defined(__NR_getgroups32)
+#define __NR_getgroups32 205
+#endif
+
+#if !defined(__NR_setgroups32)
+#define __NR_setgroups32 206
+#endif
+
+#if !defined(__NR_fchown32)
+#define __NR_fchown32 207
+#endif
+
+#if !defined(__NR_setresuid32)
+#define __NR_setresuid32 208
+#endif
+
+#if !defined(__NR_getresuid32)
+#define __NR_getresuid32 209
+#endif
+
+#if !defined(__NR_setresgid32)
+#define __NR_setresgid32 210
+#endif
+
+#if !defined(__NR_getresgid32)
+#define __NR_getresgid32 211
+#endif
+
+#if !defined(__NR_chown32)
+#define __NR_chown32 212
+#endif
+
+#if !defined(__NR_setuid32)
+#define __NR_setuid32 213
+#endif
+
+#if !defined(__NR_setgid32)
+#define __NR_setgid32 214
+#endif
+
+#if !defined(__NR_setfsuid32)
+#define __NR_setfsuid32 215
+#endif
+
+#if !defined(__NR_setfsgid32)
+#define __NR_setfsgid32 216
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 217
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 218
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 219
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 220
+#endif
+
+#if !defined(__NR_fcntl64)
+#define __NR_fcntl64 221
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 224
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 225
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 226
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 227
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 228
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 229
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 230
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 231
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 232
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 233
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 234
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 235
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 236
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 237
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 238
+#endif
+
+#if !defined(__NR_sendfile64)
+#define __NR_sendfile64 239
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 240
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 241
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 242
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area 243
+#endif
+
+#if !defined(__NR_get_thread_area)
+#define __NR_get_thread_area 244
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 245
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 246
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 247
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 248
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 249
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 250
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 252
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 253
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create 254
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 255
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait 256
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 257
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 258
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 259
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 260
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 261
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 262
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 263
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 264
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 265
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 266
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 267
+#endif
+
+#if !defined(__NR_statfs64)
+#define __NR_statfs64 268
+#endif
+
+#if !defined(__NR_fstatfs64)
+#define __NR_fstatfs64 269
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 270
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes 271
+#endif
+
+#if !defined(__NR_fadvise64_64)
+#define __NR_fadvise64_64 272
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver 273
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 274
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 275
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 276
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 277
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 278
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 279
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 280
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 281
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 282
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 283
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 284
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 286
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 287
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 288
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 289
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 290
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init 291
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 292
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 293
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 294
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 295
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 296
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 297
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 298
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat 299
+#endif
+
+#if !defined(__NR_fstatat64)
+#define __NR_fstatat64 300
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 301
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 302
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 303
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 304
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 305
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 306
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 307
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 308
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 309
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 310
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 311
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 312
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 313
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 314
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 315
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 316
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 317
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 318
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 319
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 320
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd 321
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 322
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd 323
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 324
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 325
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 326
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 327
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 328
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 329
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 330
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 331
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 332
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 333
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 334
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 335
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 336
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 337
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 338
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 339
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 340
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 341
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 342
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 343
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 344
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 345
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 346
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 347
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 348
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 349
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 350
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 351
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 352
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 353
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 354
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 355
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create 356
+#endif
+
+#if !defined(__NR_bpf)
+#define __NR_bpf 357
+#endif
+
+#if !defined(__NR_execveat)
+#define __NR_execveat 358
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 359
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 360
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 361
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 362
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 363
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 364
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 365
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 366
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 367
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 368
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 369
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 370
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 371
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 372
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 373
+#endif
+
+#if !defined(__NR_userfaultfd)
+#define __NR_userfaultfd 374
+#endif
+
+#if !defined(__NR_membarrier)
+#define __NR_membarrier 375
+#endif
+
+#if !defined(__NR_mlock2)
+#define __NR_mlock2 376
+#endif
+
+#if !defined(__NR_copy_file_range)
+#define __NR_copy_file_range 377
+#endif
+
+#if !defined(__NR_preadv2)
+#define __NR_preadv2 378
+#endif
+
+#if !defined(__NR_pwritev2)
+#define __NR_pwritev2 379
+#endif
+
+#if !defined(__NR_pkey_mprotect)
+#define __NR_pkey_mprotect 380
+#endif
+
+#if !defined(__NR_pkey_alloc)
+#define __NR_pkey_alloc 381
+#endif
+
+#if !defined(__NR_pkey_free)
+#define __NR_pkey_free 382
+#endif
+
+#if !defined(__NR_statx)
+#define __NR_statx 383
+#endif
+
+#if !defined(__NR_arch_prctl)
+#define __NR_arch_prctl 384
+#endif
+
+#if !defined(__NR_io_pgetevents)
+#define __NR_io_pgetevents 385
+#endif
+
+#if !defined(__NR_rseq)
+#define __NR_rseq 386
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 393
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 394
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 395
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 396
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 397
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 398
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 399
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 400
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 401
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 402
+#endif
+
+#if !defined(__NR_clock_gettime64)
+#define __NR_clock_gettime64 403
+#endif
+
+#if !defined(__NR_clock_settime64)
+#define __NR_clock_settime64 404
+#endif
+
+#if !defined(__NR_clock_adjtime64)
+#define __NR_clock_adjtime64 405
+#endif
+
+#if !defined(__NR_clock_getres_time64)
+#define __NR_clock_getres_time64 406
+#endif
+
+#if !defined(__NR_clock_nanosleep_time64)
+#define __NR_clock_nanosleep_time64 407
+#endif
+
+#if !defined(__NR_timer_gettime64)
+#define __NR_timer_gettime64 408
+#endif
+
+#if !defined(__NR_timer_settime64)
+#define __NR_timer_settime64 409
+#endif
+
+#if !defined(__NR_timerfd_gettime64)
+#define __NR_timerfd_gettime64 410
+#endif
+
+#if !defined(__NR_timerfd_settime64)
+#define __NR_timerfd_settime64 411
+#endif
+
+#if !defined(__NR_utimensat_time64)
+#define __NR_utimensat_time64 412
+#endif
+
+#if !defined(__NR_pselect6_time64)
+#define __NR_pselect6_time64 413
+#endif
+
+#if !defined(__NR_ppoll_time64)
+#define __NR_ppoll_time64 414
+#endif
+
+#if !defined(__NR_io_pgetevents_time64)
+#define __NR_io_pgetevents_time64 416
+#endif
+
+#if !defined(__NR_recvmmsg_time64)
+#define __NR_recvmmsg_time64 417
+#endif
+
+#if !defined(__NR_mq_timedsend_time64)
+#define __NR_mq_timedsend_time64 418
+#endif
+
+#if !defined(__NR_mq_timedreceive_time64)
+#define __NR_mq_timedreceive_time64 419
+#endif
+
+#if !defined(__NR_semtimedop_time64)
+#define __NR_semtimedop_time64 420
+#endif
+
+#if !defined(__NR_rt_sigtimedwait_time64)
+#define __NR_rt_sigtimedwait_time64 421
+#endif
+
+#if !defined(__NR_futex_time64)
+#define __NR_futex_time64 422
+#endif
+
+#if !defined(__NR_sched_rr_get_interval_time64)
+#define __NR_sched_rr_get_interval_time64 423
+#endif
+
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal 424
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup 425
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter 426
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register 427
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree 428
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount 429
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen 430
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig 431
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount 432
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick 433
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open 434
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 435
+#endif
+
+#if !defined(__NR_openat2)
+#define __NR_openat2 437
+#endif
+
+#if !defined(__NR_pidfd_getfd)
+#define __NR_pidfd_getfd 438
+#endif
+
+#if !defined(__NR_faccessat2)
+#define __NR_faccessat2 439
+#endif
+
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h
new file mode 100644
index 0000000000..ab51703464
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/x86_64_linux_syscalls.h
@@ -0,0 +1,1418 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* Constructed by running:
+ * curl -vsSL https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/x86/entry/syscalls/syscall_64.tbl?h=v5.8
+ * | grep -vE '^#|^$'
+ * | awk '{ if ($2 != "x32") { print "#if !defined(__NR_" $3 ")\n#define __NR_" $3 " " $1 "\n#endif\n"; } }'
+ * */
+
+#ifndef SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+#define SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
+
+#if !defined(__x86_64__)
+#error "Including header on wrong architecture"
+#endif
+
+#if !defined(__NR_read)
+#define __NR_read 0
+#endif
+
+#if !defined(__NR_write)
+#define __NR_write 1
+#endif
+
+#if !defined(__NR_open)
+#define __NR_open 2
+#endif
+
+#if !defined(__NR_close)
+#define __NR_close 3
+#endif
+
+#if !defined(__NR_stat)
+#define __NR_stat 4
+#endif
+
+#if !defined(__NR_fstat)
+#define __NR_fstat 5
+#endif
+
+#if !defined(__NR_lstat)
+#define __NR_lstat 6
+#endif
+
+#if !defined(__NR_poll)
+#define __NR_poll 7
+#endif
+
+#if !defined(__NR_lseek)
+#define __NR_lseek 8
+#endif
+
+#if !defined(__NR_mmap)
+#define __NR_mmap 9
+#endif
+
+#if !defined(__NR_mprotect)
+#define __NR_mprotect 10
+#endif
+
+#if !defined(__NR_munmap)
+#define __NR_munmap 11
+#endif
+
+#if !defined(__NR_brk)
+#define __NR_brk 12
+#endif
+
+#if !defined(__NR_rt_sigaction)
+#define __NR_rt_sigaction 13
+#endif
+
+#if !defined(__NR_rt_sigprocmask)
+#define __NR_rt_sigprocmask 14
+#endif
+
+#if !defined(__NR_rt_sigreturn)
+#define __NR_rt_sigreturn 15
+#endif
+
+#if !defined(__NR_ioctl)
+#define __NR_ioctl 16
+#endif
+
+#if !defined(__NR_pread64)
+#define __NR_pread64 17
+#endif
+
+#if !defined(__NR_pwrite64)
+#define __NR_pwrite64 18
+#endif
+
+#if !defined(__NR_readv)
+#define __NR_readv 19
+#endif
+
+#if !defined(__NR_writev)
+#define __NR_writev 20
+#endif
+
+#if !defined(__NR_access)
+#define __NR_access 21
+#endif
+
+#if !defined(__NR_pipe)
+#define __NR_pipe 22
+#endif
+
+#if !defined(__NR_select)
+#define __NR_select 23
+#endif
+
+#if !defined(__NR_sched_yield)
+#define __NR_sched_yield 24
+#endif
+
+#if !defined(__NR_mremap)
+#define __NR_mremap 25
+#endif
+
+#if !defined(__NR_msync)
+#define __NR_msync 26
+#endif
+
+#if !defined(__NR_mincore)
+#define __NR_mincore 27
+#endif
+
+#if !defined(__NR_madvise)
+#define __NR_madvise 28
+#endif
+
+#if !defined(__NR_shmget)
+#define __NR_shmget 29
+#endif
+
+#if !defined(__NR_shmat)
+#define __NR_shmat 30
+#endif
+
+#if !defined(__NR_shmctl)
+#define __NR_shmctl 31
+#endif
+
+#if !defined(__NR_dup)
+#define __NR_dup 32
+#endif
+
+#if !defined(__NR_dup2)
+#define __NR_dup2 33
+#endif
+
+#if !defined(__NR_pause)
+#define __NR_pause 34
+#endif
+
+#if !defined(__NR_nanosleep)
+#define __NR_nanosleep 35
+#endif
+
+#if !defined(__NR_getitimer)
+#define __NR_getitimer 36
+#endif
+
+#if !defined(__NR_alarm)
+#define __NR_alarm 37
+#endif
+
+#if !defined(__NR_setitimer)
+#define __NR_setitimer 38
+#endif
+
+#if !defined(__NR_getpid)
+#define __NR_getpid 39
+#endif
+
+#if !defined(__NR_sendfile)
+#define __NR_sendfile 40
+#endif
+
+#if !defined(__NR_socket)
+#define __NR_socket 41
+#endif
+
+#if !defined(__NR_connect)
+#define __NR_connect 42
+#endif
+
+#if !defined(__NR_accept)
+#define __NR_accept 43
+#endif
+
+#if !defined(__NR_sendto)
+#define __NR_sendto 44
+#endif
+
+#if !defined(__NR_recvfrom)
+#define __NR_recvfrom 45
+#endif
+
+#if !defined(__NR_sendmsg)
+#define __NR_sendmsg 46
+#endif
+
+#if !defined(__NR_recvmsg)
+#define __NR_recvmsg 47
+#endif
+
+#if !defined(__NR_shutdown)
+#define __NR_shutdown 48
+#endif
+
+#if !defined(__NR_bind)
+#define __NR_bind 49
+#endif
+
+#if !defined(__NR_listen)
+#define __NR_listen 50
+#endif
+
+#if !defined(__NR_getsockname)
+#define __NR_getsockname 51
+#endif
+
+#if !defined(__NR_getpeername)
+#define __NR_getpeername 52
+#endif
+
+#if !defined(__NR_socketpair)
+#define __NR_socketpair 53
+#endif
+
+#if !defined(__NR_setsockopt)
+#define __NR_setsockopt 54
+#endif
+
+#if !defined(__NR_getsockopt)
+#define __NR_getsockopt 55
+#endif
+
+#if !defined(__NR_clone)
+#define __NR_clone 56
+#endif
+
+#if !defined(__NR_fork)
+#define __NR_fork 57
+#endif
+
+#if !defined(__NR_vfork)
+#define __NR_vfork 58
+#endif
+
+#if !defined(__NR_execve)
+#define __NR_execve 59
+#endif
+
+#if !defined(__NR_exit)
+#define __NR_exit 60
+#endif
+
+#if !defined(__NR_wait4)
+#define __NR_wait4 61
+#endif
+
+#if !defined(__NR_kill)
+#define __NR_kill 62
+#endif
+
+#if !defined(__NR_uname)
+#define __NR_uname 63
+#endif
+
+#if !defined(__NR_semget)
+#define __NR_semget 64
+#endif
+
+#if !defined(__NR_semop)
+#define __NR_semop 65
+#endif
+
+#if !defined(__NR_semctl)
+#define __NR_semctl 66
+#endif
+
+#if !defined(__NR_shmdt)
+#define __NR_shmdt 67
+#endif
+
+#if !defined(__NR_msgget)
+#define __NR_msgget 68
+#endif
+
+#if !defined(__NR_msgsnd)
+#define __NR_msgsnd 69
+#endif
+
+#if !defined(__NR_msgrcv)
+#define __NR_msgrcv 70
+#endif
+
+#if !defined(__NR_msgctl)
+#define __NR_msgctl 71
+#endif
+
+#if !defined(__NR_fcntl)
+#define __NR_fcntl 72
+#endif
+
+#if !defined(__NR_flock)
+#define __NR_flock 73
+#endif
+
+#if !defined(__NR_fsync)
+#define __NR_fsync 74
+#endif
+
+#if !defined(__NR_fdatasync)
+#define __NR_fdatasync 75
+#endif
+
+#if !defined(__NR_truncate)
+#define __NR_truncate 76
+#endif
+
+#if !defined(__NR_ftruncate)
+#define __NR_ftruncate 77
+#endif
+
+#if !defined(__NR_getdents)
+#define __NR_getdents 78
+#endif
+
+#if !defined(__NR_getcwd)
+#define __NR_getcwd 79
+#endif
+
+#if !defined(__NR_chdir)
+#define __NR_chdir 80
+#endif
+
+#if !defined(__NR_fchdir)
+#define __NR_fchdir 81
+#endif
+
+#if !defined(__NR_rename)
+#define __NR_rename 82
+#endif
+
+#if !defined(__NR_mkdir)
+#define __NR_mkdir 83
+#endif
+
+#if !defined(__NR_rmdir)
+#define __NR_rmdir 84
+#endif
+
+#if !defined(__NR_creat)
+#define __NR_creat 85
+#endif
+
+#if !defined(__NR_link)
+#define __NR_link 86
+#endif
+
+#if !defined(__NR_unlink)
+#define __NR_unlink 87
+#endif
+
+#if !defined(__NR_symlink)
+#define __NR_symlink 88
+#endif
+
+#if !defined(__NR_readlink)
+#define __NR_readlink 89
+#endif
+
+#if !defined(__NR_chmod)
+#define __NR_chmod 90
+#endif
+
+#if !defined(__NR_fchmod)
+#define __NR_fchmod 91
+#endif
+
+#if !defined(__NR_chown)
+#define __NR_chown 92
+#endif
+
+#if !defined(__NR_fchown)
+#define __NR_fchown 93
+#endif
+
+#if !defined(__NR_lchown)
+#define __NR_lchown 94
+#endif
+
+#if !defined(__NR_umask)
+#define __NR_umask 95
+#endif
+
+#if !defined(__NR_gettimeofday)
+#define __NR_gettimeofday 96
+#endif
+
+#if !defined(__NR_getrlimit)
+#define __NR_getrlimit 97
+#endif
+
+#if !defined(__NR_getrusage)
+#define __NR_getrusage 98
+#endif
+
+#if !defined(__NR_sysinfo)
+#define __NR_sysinfo 99
+#endif
+
+#if !defined(__NR_times)
+#define __NR_times 100
+#endif
+
+#if !defined(__NR_ptrace)
+#define __NR_ptrace 101
+#endif
+
+#if !defined(__NR_getuid)
+#define __NR_getuid 102
+#endif
+
+#if !defined(__NR_syslog)
+#define __NR_syslog 103
+#endif
+
+#if !defined(__NR_getgid)
+#define __NR_getgid 104
+#endif
+
+#if !defined(__NR_setuid)
+#define __NR_setuid 105
+#endif
+
+#if !defined(__NR_setgid)
+#define __NR_setgid 106
+#endif
+
+#if !defined(__NR_geteuid)
+#define __NR_geteuid 107
+#endif
+
+#if !defined(__NR_getegid)
+#define __NR_getegid 108
+#endif
+
+#if !defined(__NR_setpgid)
+#define __NR_setpgid 109
+#endif
+
+#if !defined(__NR_getppid)
+#define __NR_getppid 110
+#endif
+
+#if !defined(__NR_getpgrp)
+#define __NR_getpgrp 111
+#endif
+
+#if !defined(__NR_setsid)
+#define __NR_setsid 112
+#endif
+
+#if !defined(__NR_setreuid)
+#define __NR_setreuid 113
+#endif
+
+#if !defined(__NR_setregid)
+#define __NR_setregid 114
+#endif
+
+#if !defined(__NR_getgroups)
+#define __NR_getgroups 115
+#endif
+
+#if !defined(__NR_setgroups)
+#define __NR_setgroups 116
+#endif
+
+#if !defined(__NR_setresuid)
+#define __NR_setresuid 117
+#endif
+
+#if !defined(__NR_getresuid)
+#define __NR_getresuid 118
+#endif
+
+#if !defined(__NR_setresgid)
+#define __NR_setresgid 119
+#endif
+
+#if !defined(__NR_getresgid)
+#define __NR_getresgid 120
+#endif
+
+#if !defined(__NR_getpgid)
+#define __NR_getpgid 121
+#endif
+
+#if !defined(__NR_setfsuid)
+#define __NR_setfsuid 122
+#endif
+
+#if !defined(__NR_setfsgid)
+#define __NR_setfsgid 123
+#endif
+
+#if !defined(__NR_getsid)
+#define __NR_getsid 124
+#endif
+
+#if !defined(__NR_capget)
+#define __NR_capget 125
+#endif
+
+#if !defined(__NR_capset)
+#define __NR_capset 126
+#endif
+
+#if !defined(__NR_rt_sigpending)
+#define __NR_rt_sigpending 127
+#endif
+
+#if !defined(__NR_rt_sigtimedwait)
+#define __NR_rt_sigtimedwait 128
+#endif
+
+#if !defined(__NR_rt_sigqueueinfo)
+#define __NR_rt_sigqueueinfo 129
+#endif
+
+#if !defined(__NR_rt_sigsuspend)
+#define __NR_rt_sigsuspend 130
+#endif
+
+#if !defined(__NR_sigaltstack)
+#define __NR_sigaltstack 131
+#endif
+
+#if !defined(__NR_utime)
+#define __NR_utime 132
+#endif
+
+#if !defined(__NR_mknod)
+#define __NR_mknod 133
+#endif
+
+#if !defined(__NR_uselib)
+#define __NR_uselib 134
+#endif
+
+#if !defined(__NR_personality)
+#define __NR_personality 135
+#endif
+
+#if !defined(__NR_ustat)
+#define __NR_ustat 136
+#endif
+
+#if !defined(__NR_statfs)
+#define __NR_statfs 137
+#endif
+
+#if !defined(__NR_fstatfs)
+#define __NR_fstatfs 138
+#endif
+
+#if !defined(__NR_sysfs)
+#define __NR_sysfs 139
+#endif
+
+#if !defined(__NR_getpriority)
+#define __NR_getpriority 140
+#endif
+
+#if !defined(__NR_setpriority)
+#define __NR_setpriority 141
+#endif
+
+#if !defined(__NR_sched_setparam)
+#define __NR_sched_setparam 142
+#endif
+
+#if !defined(__NR_sched_getparam)
+#define __NR_sched_getparam 143
+#endif
+
+#if !defined(__NR_sched_setscheduler)
+#define __NR_sched_setscheduler 144
+#endif
+
+#if !defined(__NR_sched_getscheduler)
+#define __NR_sched_getscheduler 145
+#endif
+
+#if !defined(__NR_sched_get_priority_max)
+#define __NR_sched_get_priority_max 146
+#endif
+
+#if !defined(__NR_sched_get_priority_min)
+#define __NR_sched_get_priority_min 147
+#endif
+
+#if !defined(__NR_sched_rr_get_interval)
+#define __NR_sched_rr_get_interval 148
+#endif
+
+#if !defined(__NR_mlock)
+#define __NR_mlock 149
+#endif
+
+#if !defined(__NR_munlock)
+#define __NR_munlock 150
+#endif
+
+#if !defined(__NR_mlockall)
+#define __NR_mlockall 151
+#endif
+
+#if !defined(__NR_munlockall)
+#define __NR_munlockall 152
+#endif
+
+#if !defined(__NR_vhangup)
+#define __NR_vhangup 153
+#endif
+
+#if !defined(__NR_modify_ldt)
+#define __NR_modify_ldt 154
+#endif
+
+#if !defined(__NR_pivot_root)
+#define __NR_pivot_root 155
+#endif
+
+#if !defined(__NR__sysctl)
+#define __NR__sysctl 156
+#endif
+
+#if !defined(__NR_prctl)
+#define __NR_prctl 157
+#endif
+
+#if !defined(__NR_arch_prctl)
+#define __NR_arch_prctl 158
+#endif
+
+#if !defined(__NR_adjtimex)
+#define __NR_adjtimex 159
+#endif
+
+#if !defined(__NR_setrlimit)
+#define __NR_setrlimit 160
+#endif
+
+#if !defined(__NR_chroot)
+#define __NR_chroot 161
+#endif
+
+#if !defined(__NR_sync)
+#define __NR_sync 162
+#endif
+
+#if !defined(__NR_acct)
+#define __NR_acct 163
+#endif
+
+#if !defined(__NR_settimeofday)
+#define __NR_settimeofday 164
+#endif
+
+#if !defined(__NR_mount)
+#define __NR_mount 165
+#endif
+
+#if !defined(__NR_umount2)
+#define __NR_umount2 166
+#endif
+
+#if !defined(__NR_swapon)
+#define __NR_swapon 167
+#endif
+
+#if !defined(__NR_swapoff)
+#define __NR_swapoff 168
+#endif
+
+#if !defined(__NR_reboot)
+#define __NR_reboot 169
+#endif
+
+#if !defined(__NR_sethostname)
+#define __NR_sethostname 170
+#endif
+
+#if !defined(__NR_setdomainname)
+#define __NR_setdomainname 171
+#endif
+
+#if !defined(__NR_iopl)
+#define __NR_iopl 172
+#endif
+
+#if !defined(__NR_ioperm)
+#define __NR_ioperm 173
+#endif
+
+#if !defined(__NR_create_module)
+#define __NR_create_module 174
+#endif
+
+#if !defined(__NR_init_module)
+#define __NR_init_module 175
+#endif
+
+#if !defined(__NR_delete_module)
+#define __NR_delete_module 176
+#endif
+
+#if !defined(__NR_get_kernel_syms)
+#define __NR_get_kernel_syms 177
+#endif
+
+#if !defined(__NR_query_module)
+#define __NR_query_module 178
+#endif
+
+#if !defined(__NR_quotactl)
+#define __NR_quotactl 179
+#endif
+
+#if !defined(__NR_nfsservctl)
+#define __NR_nfsservctl 180
+#endif
+
+#if !defined(__NR_getpmsg)
+#define __NR_getpmsg 181
+#endif
+
+#if !defined(__NR_putpmsg)
+#define __NR_putpmsg 182
+#endif
+
+#if !defined(__NR_afs_syscall)
+#define __NR_afs_syscall 183
+#endif
+
+#if !defined(__NR_tuxcall)
+#define __NR_tuxcall 184
+#endif
+
+#if !defined(__NR_security)
+#define __NR_security 185
+#endif
+
+#if !defined(__NR_gettid)
+#define __NR_gettid 186
+#endif
+
+#if !defined(__NR_readahead)
+#define __NR_readahead 187
+#endif
+
+#if !defined(__NR_setxattr)
+#define __NR_setxattr 188
+#endif
+
+#if !defined(__NR_lsetxattr)
+#define __NR_lsetxattr 189
+#endif
+
+#if !defined(__NR_fsetxattr)
+#define __NR_fsetxattr 190
+#endif
+
+#if !defined(__NR_getxattr)
+#define __NR_getxattr 191
+#endif
+
+#if !defined(__NR_lgetxattr)
+#define __NR_lgetxattr 192
+#endif
+
+#if !defined(__NR_fgetxattr)
+#define __NR_fgetxattr 193
+#endif
+
+#if !defined(__NR_listxattr)
+#define __NR_listxattr 194
+#endif
+
+#if !defined(__NR_llistxattr)
+#define __NR_llistxattr 195
+#endif
+
+#if !defined(__NR_flistxattr)
+#define __NR_flistxattr 196
+#endif
+
+#if !defined(__NR_removexattr)
+#define __NR_removexattr 197
+#endif
+
+#if !defined(__NR_lremovexattr)
+#define __NR_lremovexattr 198
+#endif
+
+#if !defined(__NR_fremovexattr)
+#define __NR_fremovexattr 199
+#endif
+
+#if !defined(__NR_tkill)
+#define __NR_tkill 200
+#endif
+
+#if !defined(__NR_time)
+#define __NR_time 201
+#endif
+
+#if !defined(__NR_futex)
+#define __NR_futex 202
+#endif
+
+#if !defined(__NR_sched_setaffinity)
+#define __NR_sched_setaffinity 203
+#endif
+
+#if !defined(__NR_sched_getaffinity)
+#define __NR_sched_getaffinity 204
+#endif
+
+#if !defined(__NR_set_thread_area)
+#define __NR_set_thread_area 205
+#endif
+
+#if !defined(__NR_io_setup)
+#define __NR_io_setup 206
+#endif
+
+#if !defined(__NR_io_destroy)
+#define __NR_io_destroy 207
+#endif
+
+#if !defined(__NR_io_getevents)
+#define __NR_io_getevents 208
+#endif
+
+#if !defined(__NR_io_submit)
+#define __NR_io_submit 209
+#endif
+
+#if !defined(__NR_io_cancel)
+#define __NR_io_cancel 210
+#endif
+
+#if !defined(__NR_get_thread_area)
+#define __NR_get_thread_area 211
+#endif
+
+#if !defined(__NR_lookup_dcookie)
+#define __NR_lookup_dcookie 212
+#endif
+
+#if !defined(__NR_epoll_create)
+#define __NR_epoll_create 213
+#endif
+
+#if !defined(__NR_epoll_ctl_old)
+#define __NR_epoll_ctl_old 214
+#endif
+
+#if !defined(__NR_epoll_wait_old)
+#define __NR_epoll_wait_old 215
+#endif
+
+#if !defined(__NR_remap_file_pages)
+#define __NR_remap_file_pages 216
+#endif
+
+#if !defined(__NR_getdents64)
+#define __NR_getdents64 217
+#endif
+
+#if !defined(__NR_set_tid_address)
+#define __NR_set_tid_address 218
+#endif
+
+#if !defined(__NR_restart_syscall)
+#define __NR_restart_syscall 219
+#endif
+
+#if !defined(__NR_semtimedop)
+#define __NR_semtimedop 220
+#endif
+
+#if !defined(__NR_fadvise64)
+#define __NR_fadvise64 221
+#endif
+
+#if !defined(__NR_timer_create)
+#define __NR_timer_create 222
+#endif
+
+#if !defined(__NR_timer_settime)
+#define __NR_timer_settime 223
+#endif
+
+#if !defined(__NR_timer_gettime)
+#define __NR_timer_gettime 224
+#endif
+
+#if !defined(__NR_timer_getoverrun)
+#define __NR_timer_getoverrun 225
+#endif
+
+#if !defined(__NR_timer_delete)
+#define __NR_timer_delete 226
+#endif
+
+#if !defined(__NR_clock_settime)
+#define __NR_clock_settime 227
+#endif
+
+#if !defined(__NR_clock_gettime)
+#define __NR_clock_gettime 228
+#endif
+
+#if !defined(__NR_clock_getres)
+#define __NR_clock_getres 229
+#endif
+
+#if !defined(__NR_clock_nanosleep)
+#define __NR_clock_nanosleep 230
+#endif
+
+#if !defined(__NR_exit_group)
+#define __NR_exit_group 231
+#endif
+
+#if !defined(__NR_epoll_wait)
+#define __NR_epoll_wait 232
+#endif
+
+#if !defined(__NR_epoll_ctl)
+#define __NR_epoll_ctl 233
+#endif
+
+#if !defined(__NR_tgkill)
+#define __NR_tgkill 234
+#endif
+
+#if !defined(__NR_utimes)
+#define __NR_utimes 235
+#endif
+
+#if !defined(__NR_vserver)
+#define __NR_vserver 236
+#endif
+
+#if !defined(__NR_mbind)
+#define __NR_mbind 237
+#endif
+
+#if !defined(__NR_set_mempolicy)
+#define __NR_set_mempolicy 238
+#endif
+
+#if !defined(__NR_get_mempolicy)
+#define __NR_get_mempolicy 239
+#endif
+
+#if !defined(__NR_mq_open)
+#define __NR_mq_open 240
+#endif
+
+#if !defined(__NR_mq_unlink)
+#define __NR_mq_unlink 241
+#endif
+
+#if !defined(__NR_mq_timedsend)
+#define __NR_mq_timedsend 242
+#endif
+
+#if !defined(__NR_mq_timedreceive)
+#define __NR_mq_timedreceive 243
+#endif
+
+#if !defined(__NR_mq_notify)
+#define __NR_mq_notify 244
+#endif
+
+#if !defined(__NR_mq_getsetattr)
+#define __NR_mq_getsetattr 245
+#endif
+
+#if !defined(__NR_kexec_load)
+#define __NR_kexec_load 246
+#endif
+
+#if !defined(__NR_waitid)
+#define __NR_waitid 247
+#endif
+
+#if !defined(__NR_add_key)
+#define __NR_add_key 248
+#endif
+
+#if !defined(__NR_request_key)
+#define __NR_request_key 249
+#endif
+
+#if !defined(__NR_keyctl)
+#define __NR_keyctl 250
+#endif
+
+#if !defined(__NR_ioprio_set)
+#define __NR_ioprio_set 251
+#endif
+
+#if !defined(__NR_ioprio_get)
+#define __NR_ioprio_get 252
+#endif
+
+#if !defined(__NR_inotify_init)
+#define __NR_inotify_init 253
+#endif
+
+#if !defined(__NR_inotify_add_watch)
+#define __NR_inotify_add_watch 254
+#endif
+
+#if !defined(__NR_inotify_rm_watch)
+#define __NR_inotify_rm_watch 255
+#endif
+
+#if !defined(__NR_migrate_pages)
+#define __NR_migrate_pages 256
+#endif
+
+#if !defined(__NR_openat)
+#define __NR_openat 257
+#endif
+
+#if !defined(__NR_mkdirat)
+#define __NR_mkdirat 258
+#endif
+
+#if !defined(__NR_mknodat)
+#define __NR_mknodat 259
+#endif
+
+#if !defined(__NR_fchownat)
+#define __NR_fchownat 260
+#endif
+
+#if !defined(__NR_futimesat)
+#define __NR_futimesat 261
+#endif
+
+#if !defined(__NR_newfstatat)
+#define __NR_newfstatat 262
+#endif
+
+#if !defined(__NR_unlinkat)
+#define __NR_unlinkat 263
+#endif
+
+#if !defined(__NR_renameat)
+#define __NR_renameat 264
+#endif
+
+#if !defined(__NR_linkat)
+#define __NR_linkat 265
+#endif
+
+#if !defined(__NR_symlinkat)
+#define __NR_symlinkat 266
+#endif
+
+#if !defined(__NR_readlinkat)
+#define __NR_readlinkat 267
+#endif
+
+#if !defined(__NR_fchmodat)
+#define __NR_fchmodat 268
+#endif
+
+#if !defined(__NR_faccessat)
+#define __NR_faccessat 269
+#endif
+
+#if !defined(__NR_pselect6)
+#define __NR_pselect6 270
+#endif
+
+#if !defined(__NR_ppoll)
+#define __NR_ppoll 271
+#endif
+
+#if !defined(__NR_unshare)
+#define __NR_unshare 272
+#endif
+
+#if !defined(__NR_set_robust_list)
+#define __NR_set_robust_list 273
+#endif
+
+#if !defined(__NR_get_robust_list)
+#define __NR_get_robust_list 274
+#endif
+
+#if !defined(__NR_splice)
+#define __NR_splice 275
+#endif
+
+#if !defined(__NR_tee)
+#define __NR_tee 276
+#endif
+
+#if !defined(__NR_sync_file_range)
+#define __NR_sync_file_range 277
+#endif
+
+#if !defined(__NR_vmsplice)
+#define __NR_vmsplice 278
+#endif
+
+#if !defined(__NR_move_pages)
+#define __NR_move_pages 279
+#endif
+
+#if !defined(__NR_utimensat)
+#define __NR_utimensat 280
+#endif
+
+#if !defined(__NR_epoll_pwait)
+#define __NR_epoll_pwait 281
+#endif
+
+#if !defined(__NR_signalfd)
+#define __NR_signalfd 282
+#endif
+
+#if !defined(__NR_timerfd_create)
+#define __NR_timerfd_create 283
+#endif
+
+#if !defined(__NR_eventfd)
+#define __NR_eventfd 284
+#endif
+
+#if !defined(__NR_fallocate)
+#define __NR_fallocate 285
+#endif
+
+#if !defined(__NR_timerfd_settime)
+#define __NR_timerfd_settime 286
+#endif
+
+#if !defined(__NR_timerfd_gettime)
+#define __NR_timerfd_gettime 287
+#endif
+
+#if !defined(__NR_accept4)
+#define __NR_accept4 288
+#endif
+
+#if !defined(__NR_signalfd4)
+#define __NR_signalfd4 289
+#endif
+
+#if !defined(__NR_eventfd2)
+#define __NR_eventfd2 290
+#endif
+
+#if !defined(__NR_epoll_create1)
+#define __NR_epoll_create1 291
+#endif
+
+#if !defined(__NR_dup3)
+#define __NR_dup3 292
+#endif
+
+#if !defined(__NR_pipe2)
+#define __NR_pipe2 293
+#endif
+
+#if !defined(__NR_inotify_init1)
+#define __NR_inotify_init1 294
+#endif
+
+#if !defined(__NR_preadv)
+#define __NR_preadv 295
+#endif
+
+#if !defined(__NR_pwritev)
+#define __NR_pwritev 296
+#endif
+
+#if !defined(__NR_rt_tgsigqueueinfo)
+#define __NR_rt_tgsigqueueinfo 297
+#endif
+
+#if !defined(__NR_perf_event_open)
+#define __NR_perf_event_open 298
+#endif
+
+#if !defined(__NR_recvmmsg)
+#define __NR_recvmmsg 299
+#endif
+
+#if !defined(__NR_fanotify_init)
+#define __NR_fanotify_init 300
+#endif
+
+#if !defined(__NR_fanotify_mark)
+#define __NR_fanotify_mark 301
+#endif
+
+#if !defined(__NR_prlimit64)
+#define __NR_prlimit64 302
+#endif
+
+#if !defined(__NR_name_to_handle_at)
+#define __NR_name_to_handle_at 303
+#endif
+
+#if !defined(__NR_open_by_handle_at)
+#define __NR_open_by_handle_at 304
+#endif
+
+#if !defined(__NR_clock_adjtime)
+#define __NR_clock_adjtime 305
+#endif
+
+#if !defined(__NR_syncfs)
+#define __NR_syncfs 306
+#endif
+
+#if !defined(__NR_sendmmsg)
+#define __NR_sendmmsg 307
+#endif
+
+#if !defined(__NR_setns)
+#define __NR_setns 308
+#endif
+
+#if !defined(__NR_getcpu)
+#define __NR_getcpu 309
+#endif
+
+#if !defined(__NR_process_vm_readv)
+#define __NR_process_vm_readv 310
+#endif
+
+#if !defined(__NR_process_vm_writev)
+#define __NR_process_vm_writev 311
+#endif
+
+#if !defined(__NR_kcmp)
+#define __NR_kcmp 312
+#endif
+
+#if !defined(__NR_finit_module)
+#define __NR_finit_module 313
+#endif
+
+#if !defined(__NR_sched_setattr)
+#define __NR_sched_setattr 314
+#endif
+
+#if !defined(__NR_sched_getattr)
+#define __NR_sched_getattr 315
+#endif
+
+#if !defined(__NR_renameat2)
+#define __NR_renameat2 316
+#endif
+
+#if !defined(__NR_seccomp)
+#define __NR_seccomp 317
+#endif
+
+#if !defined(__NR_getrandom)
+#define __NR_getrandom 318
+#endif
+
+#if !defined(__NR_memfd_create)
+#define __NR_memfd_create 319
+#endif
+
+#if !defined(__NR_kexec_file_load)
+#define __NR_kexec_file_load 320
+#endif
+
+#if !defined(__NR_bpf)
+#define __NR_bpf 321
+#endif
+
+#if !defined(__NR_execveat)
+#define __NR_execveat 322
+#endif
+
+#if !defined(__NR_userfaultfd)
+#define __NR_userfaultfd 323
+#endif
+
+#if !defined(__NR_membarrier)
+#define __NR_membarrier 324
+#endif
+
+#if !defined(__NR_mlock2)
+#define __NR_mlock2 325
+#endif
+
+#if !defined(__NR_copy_file_range)
+#define __NR_copy_file_range 326
+#endif
+
+#if !defined(__NR_preadv2)
+#define __NR_preadv2 327
+#endif
+
+#if !defined(__NR_pwritev2)
+#define __NR_pwritev2 328
+#endif
+
+#if !defined(__NR_pkey_mprotect)
+#define __NR_pkey_mprotect 329
+#endif
+
+#if !defined(__NR_pkey_alloc)
+#define __NR_pkey_alloc 330
+#endif
+
+#if !defined(__NR_pkey_free)
+#define __NR_pkey_free 331
+#endif
+
+#if !defined(__NR_statx)
+#define __NR_statx 332
+#endif
+
+#if !defined(__NR_io_pgetevents)
+#define __NR_io_pgetevents 333
+#endif
+
+#if !defined(__NR_rseq)
+#define __NR_rseq 334
+#endif
+
+#if !defined(__NR_pidfd_send_signal)
+#define __NR_pidfd_send_signal 424
+#endif
+
+#if !defined(__NR_io_uring_setup)
+#define __NR_io_uring_setup 425
+#endif
+
+#if !defined(__NR_io_uring_enter)
+#define __NR_io_uring_enter 426
+#endif
+
+#if !defined(__NR_io_uring_register)
+#define __NR_io_uring_register 427
+#endif
+
+#if !defined(__NR_open_tree)
+#define __NR_open_tree 428
+#endif
+
+#if !defined(__NR_move_mount)
+#define __NR_move_mount 429
+#endif
+
+#if !defined(__NR_fsopen)
+#define __NR_fsopen 430
+#endif
+
+#if !defined(__NR_fsconfig)
+#define __NR_fsconfig 431
+#endif
+
+#if !defined(__NR_fsmount)
+#define __NR_fsmount 432
+#endif
+
+#if !defined(__NR_fspick)
+#define __NR_fspick 433
+#endif
+
+#if !defined(__NR_pidfd_open)
+#define __NR_pidfd_open 434
+#endif
+
+#if !defined(__NR_clone3)
+#define __NR_clone3 435
+#endif
+
+#if !defined(__NR_openat2)
+#define __NR_openat2 437
+#endif
+
+#if !defined(__NR_pidfd_getfd)
+#define __NR_pidfd_getfd 438
+#endif
+
+#if !defined(__NR_faccessat2)
+#define __NR_faccessat2 439
+#endif
+
+#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_64_LINUX_SYSCALLS_H_
diff --git a/security/sandbox/chromium/sandbox/sandbox_export.h b/security/sandbox/chromium/sandbox/sandbox_export.h
new file mode 100644
index 0000000000..35d6a1ba26
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/sandbox_export.h
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SANDBOX_EXPORT_H_
+#define SANDBOX_SANDBOX_EXPORT_H_
+
+#if defined(WIN32)
+#error "sandbox_export.h does not support WIN32."
+#endif
+
+#if defined(COMPONENT_BUILD)
+
+#if defined(SANDBOX_IMPLEMENTATION)
+#define SANDBOX_EXPORT __attribute__((visibility("default")))
+#else
+#define SANDBOX_EXPORT
+#endif // defined(SANDBOX_IMPLEMENTATION)
+
+#else // defined(COMPONENT_BUILD)
+
+#define SANDBOX_EXPORT
+
+#endif // defined(COMPONENT_BUILD)
+
+#endif // SANDBOX_SANDBOX_EXPORT_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/acl.cc b/security/sandbox/chromium/sandbox/win/src/acl.cc
new file mode 100644
index 0000000000..bd0b181833
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/acl.cc
@@ -0,0 +1,171 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/acl.h"
+
+#include <aclapi.h>
+#include <sddl.h>
+
+#include "base/logging.h"
+#include "base/memory/free_deleter.h"
+
+namespace sandbox {
+
+bool GetDefaultDacl(
+ HANDLE token,
+ std::unique_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter>* default_dacl) {
+ if (!token)
+ return false;
+
+ DCHECK(default_dacl);
+
+ unsigned long length = 0;
+ ::GetTokenInformation(token, TokenDefaultDacl, nullptr, 0, &length);
+ if (length == 0) {
+ NOTREACHED();
+ return false;
+ }
+
+ TOKEN_DEFAULT_DACL* acl =
+ reinterpret_cast<TOKEN_DEFAULT_DACL*>(malloc(length));
+ default_dacl->reset(acl);
+
+ if (!::GetTokenInformation(token, TokenDefaultDacl, default_dacl->get(),
+ length, &length))
+ return false;
+
+ return true;
+}
+
+bool AddSidToDacl(const Sid& sid,
+ ACL* old_dacl,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access,
+ ACL** new_dacl) {
+ EXPLICIT_ACCESS new_access = {0};
+ new_access.grfAccessMode = access_mode;
+ new_access.grfAccessPermissions = access;
+ new_access.grfInheritance = NO_INHERITANCE;
+
+ new_access.Trustee.pMultipleTrustee = nullptr;
+ new_access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+ new_access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ new_access.Trustee.ptstrName = reinterpret_cast<LPWSTR>(sid.GetPSID());
+
+ if (ERROR_SUCCESS != ::SetEntriesInAcl(1, &new_access, old_dacl, new_dacl))
+ return false;
+
+ return true;
+}
+
+bool AddSidToDefaultDacl(HANDLE token,
+ const Sid& sid,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access) {
+ if (!token)
+ return false;
+
+ std::unique_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter> default_dacl;
+ if (!GetDefaultDacl(token, &default_dacl))
+ return false;
+
+ ACL* new_dacl = nullptr;
+ if (!AddSidToDacl(sid, default_dacl->DefaultDacl, access_mode, access,
+ &new_dacl))
+ return false;
+
+ TOKEN_DEFAULT_DACL new_token_dacl = {0};
+ new_token_dacl.DefaultDacl = new_dacl;
+
+ bool ret = ::SetTokenInformation(token, TokenDefaultDacl, &new_token_dacl,
+ sizeof(new_token_dacl));
+ ::LocalFree(new_dacl);
+ return ret;
+}
+
+bool RevokeLogonSidFromDefaultDacl(HANDLE token) {
+ DWORD size = sizeof(TOKEN_GROUPS) + SECURITY_MAX_SID_SIZE;
+ TOKEN_GROUPS* logon_sid = reinterpret_cast<TOKEN_GROUPS*>(malloc(size));
+
+ std::unique_ptr<TOKEN_GROUPS, base::FreeDeleter> logon_sid_ptr(logon_sid);
+
+ if (!::GetTokenInformation(token, TokenLogonSid, logon_sid, size, &size)) {
+ // If no logon sid, there's nothing to revoke.
+ if (::GetLastError() == ERROR_NOT_FOUND)
+ return true;
+ return false;
+ }
+ if (logon_sid->GroupCount < 1) {
+ ::SetLastError(ERROR_INVALID_TOKEN);
+ return false;
+ }
+ return AddSidToDefaultDacl(token,
+ reinterpret_cast<SID*>(logon_sid->Groups[0].Sid),
+ REVOKE_ACCESS, 0);
+}
+
+bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access) {
+ DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+ TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(malloc(size));
+
+ std::unique_ptr<TOKEN_USER, base::FreeDeleter> token_user_ptr(token_user);
+
+ if (!::GetTokenInformation(token, TokenUser, token_user, size, &size))
+ return false;
+
+ return AddSidToDefaultDacl(token,
+ reinterpret_cast<SID*>(token_user->User.Sid),
+ GRANT_ACCESS, access);
+}
+
+bool AddKnownSidToObject(HANDLE object,
+ SE_OBJECT_TYPE object_type,
+ const Sid& sid,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access) {
+ PSECURITY_DESCRIPTOR descriptor = nullptr;
+ PACL old_dacl = nullptr;
+ PACL new_dacl = nullptr;
+
+ if (ERROR_SUCCESS !=
+ ::GetSecurityInfo(object, object_type, DACL_SECURITY_INFORMATION, nullptr,
+ nullptr, &old_dacl, nullptr, &descriptor))
+ return false;
+
+ if (!AddSidToDacl(sid, old_dacl, access_mode, access, &new_dacl)) {
+ ::LocalFree(descriptor);
+ return false;
+ }
+
+ DWORD result =
+ ::SetSecurityInfo(object, object_type, DACL_SECURITY_INFORMATION, nullptr,
+ nullptr, new_dacl, nullptr);
+
+ ::LocalFree(new_dacl);
+ ::LocalFree(descriptor);
+
+ if (ERROR_SUCCESS != result)
+ return false;
+
+ return true;
+}
+
+bool ReplacePackageSidInDacl(HANDLE object,
+ SE_OBJECT_TYPE object_type,
+ const Sid& package_sid,
+ ACCESS_MASK access) {
+ if (!AddKnownSidToObject(object, object_type, package_sid, REVOKE_ACCESS,
+ 0)) {
+ return false;
+ }
+
+ Sid any_package_sid(::WinBuiltinAnyPackageSid);
+ if (!AddKnownSidToObject(object, object_type, any_package_sid, GRANT_ACCESS,
+ access)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/acl.h b/security/sandbox/chromium/sandbox/win/src/acl.h
new file mode 100644
index 0000000000..194edb0988
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/acl.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_ACL_H_
+#define SANDBOX_SRC_ACL_H_
+
+#include <accctrl.h>
+#include <windows.h>
+
+#include <memory>
+
+#include "base/memory/free_deleter.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+// Returns the default dacl from the token passed in.
+bool GetDefaultDacl(
+ HANDLE token,
+ std::unique_ptr<TOKEN_DEFAULT_DACL, base::FreeDeleter>* default_dacl);
+
+// Appends an ACE represented by |sid|, |access_mode|, and |access| to
+// |old_dacl|. If the function succeeds, new_dacl contains the new dacl and
+// must be freed using LocalFree.
+bool AddSidToDacl(const Sid& sid,
+ ACL* old_dacl,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access,
+ ACL** new_dacl);
+
+// Adds an ACE represented by |sid| and |access| with |access_mode| to the
+// default dacl present in the token.
+bool AddSidToDefaultDacl(HANDLE token,
+ const Sid& sid,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access);
+
+// Revokes access to the logon SID for the default dacl present in the token.
+bool RevokeLogonSidFromDefaultDacl(HANDLE token);
+
+// Adds an ACE represented by the user sid and |access| to the default dacl
+// present in the token.
+bool AddUserSidToDefaultDacl(HANDLE token, ACCESS_MASK access);
+
+// Adds an ACE represented by |known_sid|, |access_mode|, and |access| to
+// the dacl of the kernel object referenced by |object| and of |object_type|.
+bool AddKnownSidToObject(HANDLE object,
+ SE_OBJECT_TYPE object_type,
+ const Sid& sid,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access);
+
+// Replace package SID in DACL to the "any package" SID. It allows Low-IL
+// tokens to open the object which is important for warm up when using renderer
+// AppContainer.
+bool ReplacePackageSidInDacl(HANDLE object,
+ SE_OBJECT_TYPE object_type,
+ const Sid& package_sid,
+ ACCESS_MASK access);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_ACL_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_profile.h b/security/sandbox/chromium/sandbox/win/src/app_container_profile.h
new file mode 100644
index 0000000000..c95c68e552
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/app_container_profile.h
@@ -0,0 +1,74 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_APP_CONTAINER_PROFILE_H_
+#define SANDBOX_SRC_APP_CONTAINER_PROFILE_H_
+
+#include <windows.h>
+
+#include <accctrl.h>
+
+#include "base/files/file_path.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+class AppContainerProfile {
+ public:
+ // Increments the reference count of this object. The reference count must
+ // be incremented if this interface is given to another component.
+ virtual void AddRef() = 0;
+
+ // Decrements the reference count of this object. When the reference count
+ // is zero the object is automatically destroyed.
+ // Indicates that the caller is done with this interface. After calling
+ // release no other method should be called.
+ virtual void Release() = 0;
+
+ // Get a handle to a registry key for this package.
+ virtual bool GetRegistryLocation(REGSAM desired_access,
+ base::win::ScopedHandle* key) = 0;
+
+ // Get a folder path to a location for this package.
+ virtual bool GetFolderPath(base::FilePath* file_path) = 0;
+
+ // Get a pipe name usable by this AC.
+ virtual bool GetPipePath(const wchar_t* pipe_name,
+ base::FilePath* pipe_path) = 0;
+
+ // Do an access check based on this profile for a named object. If method
+ // returns true then access_status reflects whether access was granted and
+ // granted_access gives the final access rights. The object_type can be one of
+ // SE_FILE_OBJECT, SE_REGISTRY_KEY, SE_REGISTRY_WOW64_32KEY. See
+ // ::GetNamedSecurityInfo for more information about how the enumeration is
+ // used and what format object_name needs to be.
+ virtual bool AccessCheck(const wchar_t* object_name,
+ SE_OBJECT_TYPE object_type,
+ DWORD desired_access,
+ DWORD* granted_access,
+ BOOL* access_status) = 0;
+
+ // Adds a capability by name to this profile.
+ virtual bool AddCapability(const wchar_t* capability_name) = 0;
+ // Adds a capability from a known list.
+ virtual bool AddCapability(WellKnownCapabilities capability) = 0;
+ // Adds a capability from a SID
+ virtual bool AddCapabilitySddl(const wchar_t* sddl_sid) = 0;
+
+ // Adds an impersonation capability by name to this profile.
+ virtual bool AddImpersonationCapability(const wchar_t* capability_name) = 0;
+ // Adds an impersonation capability from a known list.
+ virtual bool AddImpersonationCapability(WellKnownCapabilities capability) = 0;
+ // Adds an impersonation capability from a SID
+ virtual bool AddImpersonationCapabilitySddl(const wchar_t* sddl_sid) = 0;
+
+ // Enable Low Privilege AC.
+ virtual void SetEnableLowPrivilegeAppContainer(bool enable) = 0;
+ virtual bool GetEnableLowPrivilegeAppContainer() = 0;
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_APP_CONTAINER_PROFILE_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc b/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc
new file mode 100644
index 0000000000..e388a9978e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.cc
@@ -0,0 +1,337 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include <aclapi.h>
+#include <userenv.h>
+
+#include "base/strings/stringprintf.h"
+#if !defined(MOZ_SANDBOX)
+#include "base/win/scoped_co_mem.h"
+#endif
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/app_container_profile_base.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+typedef decltype(::CreateAppContainerProfile) CreateAppContainerProfileFunc;
+
+typedef decltype(::DeriveAppContainerSidFromAppContainerName)
+ DeriveAppContainerSidFromAppContainerNameFunc;
+
+typedef decltype(::DeleteAppContainerProfile) DeleteAppContainerProfileFunc;
+
+typedef decltype(::GetAppContainerFolderPath) GetAppContainerFolderPathFunc;
+
+typedef decltype(
+ ::GetAppContainerRegistryLocation) GetAppContainerRegistryLocationFunc;
+
+struct FreeSidDeleter {
+ inline void operator()(void* ptr) const { ::FreeSid(ptr); }
+};
+
+bool IsValidObjectType(SE_OBJECT_TYPE object_type) {
+ switch (object_type) {
+ case SE_FILE_OBJECT:
+ case SE_REGISTRY_KEY:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool GetGenericMappingForType(SE_OBJECT_TYPE object_type,
+ GENERIC_MAPPING* generic_mapping) {
+ if (!IsValidObjectType(object_type))
+ return false;
+ if (object_type == SE_FILE_OBJECT) {
+ generic_mapping->GenericRead = FILE_GENERIC_READ;
+ generic_mapping->GenericWrite = FILE_GENERIC_WRITE;
+ generic_mapping->GenericExecute = FILE_GENERIC_EXECUTE;
+ generic_mapping->GenericAll = FILE_ALL_ACCESS;
+ } else {
+ generic_mapping->GenericRead = KEY_READ;
+ generic_mapping->GenericWrite = KEY_WRITE;
+ generic_mapping->GenericExecute = KEY_EXECUTE;
+ generic_mapping->GenericAll = KEY_ALL_ACCESS;
+ }
+ return true;
+}
+
+class ScopedImpersonation {
+ public:
+ ScopedImpersonation(const base::win::ScopedHandle& token) {
+ BOOL result = ::ImpersonateLoggedOnUser(token.Get());
+ DCHECK(result);
+ }
+
+ ~ScopedImpersonation() {
+ BOOL result = ::RevertToSelf();
+ DCHECK(result);
+ }
+};
+
+} // namespace
+
+// static
+AppContainerProfileBase* AppContainerProfileBase::Create(
+ const wchar_t* package_name,
+ const wchar_t* display_name,
+ const wchar_t* description) {
+ static auto create_app_container_profile =
+ reinterpret_cast<CreateAppContainerProfileFunc*>(GetProcAddress(
+ GetModuleHandle(L"userenv"), "CreateAppContainerProfile"));
+ if (!create_app_container_profile)
+ return nullptr;
+
+ PSID package_sid = nullptr;
+ HRESULT hr = create_app_container_profile(
+ package_name, display_name, description, nullptr, 0, &package_sid);
+ if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
+ return Open(package_name);
+
+ if (FAILED(hr))
+ return nullptr;
+ std::unique_ptr<void, FreeSidDeleter> sid_deleter(package_sid);
+ return new AppContainerProfileBase(Sid(package_sid));
+}
+
+// static
+AppContainerProfileBase* AppContainerProfileBase::Open(
+ const wchar_t* package_name) {
+ static auto derive_app_container_sid =
+ reinterpret_cast<DeriveAppContainerSidFromAppContainerNameFunc*>(
+ GetProcAddress(GetModuleHandle(L"userenv"),
+ "DeriveAppContainerSidFromAppContainerName"));
+ if (!derive_app_container_sid)
+ return nullptr;
+
+ PSID package_sid = nullptr;
+ HRESULT hr = derive_app_container_sid(package_name, &package_sid);
+ if (FAILED(hr))
+ return nullptr;
+
+ std::unique_ptr<void, FreeSidDeleter> sid_deleter(package_sid);
+ return new AppContainerProfileBase(Sid(package_sid));
+}
+
+// static
+bool AppContainerProfileBase::Delete(const wchar_t* package_name) {
+ static auto delete_app_container_profile =
+ reinterpret_cast<DeleteAppContainerProfileFunc*>(GetProcAddress(
+ GetModuleHandle(L"userenv"), "DeleteAppContainerProfile"));
+ if (!delete_app_container_profile)
+ return false;
+
+ return SUCCEEDED(delete_app_container_profile(package_name));
+}
+
+AppContainerProfileBase::AppContainerProfileBase(const Sid& package_sid)
+ : ref_count_(0),
+ package_sid_(package_sid),
+ enable_low_privilege_app_container_(false) {}
+
+AppContainerProfileBase::~AppContainerProfileBase() {}
+
+void AppContainerProfileBase::AddRef() {
+ ::InterlockedIncrement(&ref_count_);
+}
+
+void AppContainerProfileBase::Release() {
+ LONG ref_count = ::InterlockedDecrement(&ref_count_);
+ if (ref_count == 0) {
+ delete this;
+ }
+}
+
+bool AppContainerProfileBase::GetRegistryLocation(
+ REGSAM desired_access,
+ base::win::ScopedHandle* key) {
+ static GetAppContainerRegistryLocationFunc*
+ get_app_container_registry_location =
+ reinterpret_cast<GetAppContainerRegistryLocationFunc*>(GetProcAddress(
+ GetModuleHandle(L"userenv"), "GetAppContainerRegistryLocation"));
+ if (!get_app_container_registry_location)
+ return false;
+
+ base::win::ScopedHandle token;
+ if (!BuildLowBoxToken(&token))
+ return false;
+
+ ScopedImpersonation impersonation(token);
+ HKEY key_handle;
+ if (FAILED(get_app_container_registry_location(desired_access, &key_handle)))
+ return false;
+ key->Set(key_handle);
+ return true;
+}
+
+bool AppContainerProfileBase::GetFolderPath(base::FilePath* file_path) {
+#if defined(MOZ_SANDBOX)
+ IMMEDIATE_CRASH();
+#else
+ static GetAppContainerFolderPathFunc* get_app_container_folder_path =
+ reinterpret_cast<GetAppContainerFolderPathFunc*>(GetProcAddress(
+ GetModuleHandle(L"userenv"), "GetAppContainerFolderPath"));
+ if (!get_app_container_folder_path)
+ return false;
+ std::wstring sddl_str;
+ if (!package_sid_.ToSddlString(&sddl_str))
+ return false;
+ base::win::ScopedCoMem<wchar_t> path_str;
+ if (FAILED(get_app_container_folder_path(sddl_str.c_str(), &path_str)))
+ return false;
+ *file_path = base::FilePath(path_str.get());
+ return true;
+#endif
+}
+
+bool AppContainerProfileBase::GetPipePath(const wchar_t* pipe_name,
+ base::FilePath* pipe_path) {
+#if defined(MOZ_SANDBOX)
+ IMMEDIATE_CRASH();
+#else
+ std::wstring sddl_str;
+ if (!package_sid_.ToSddlString(&sddl_str))
+ return false;
+ *pipe_path = base::FilePath(base::StringPrintf(L"\\\\.\\pipe\\%ls\\%ls",
+ sddl_str.c_str(), pipe_name));
+ return true;
+#endif
+}
+
+bool AppContainerProfileBase::AccessCheck(const wchar_t* object_name,
+ SE_OBJECT_TYPE object_type,
+ DWORD desired_access,
+ DWORD* granted_access,
+ BOOL* access_status) {
+ GENERIC_MAPPING generic_mapping;
+ if (!GetGenericMappingForType(object_type, &generic_mapping))
+ return false;
+ MapGenericMask(&desired_access, &generic_mapping);
+ PSECURITY_DESCRIPTOR sd = nullptr;
+ PACL dacl = nullptr;
+ if (GetNamedSecurityInfo(
+ object_name, object_type,
+ OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
+ DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
+ nullptr, nullptr, &dacl, nullptr, &sd) != ERROR_SUCCESS) {
+ return false;
+ }
+
+ std::unique_ptr<void, LocalFreeDeleter> sd_ptr(sd);
+
+ if (enable_low_privilege_app_container_) {
+ Sid any_package_sid(::WinBuiltinAnyPackageSid);
+ // We can't create a LPAC token directly, so modify the DACL to simulate it.
+ // Set mask for ALL APPLICATION PACKAGE Sid to 0.
+ for (WORD index = 0; index < dacl->AceCount; ++index) {
+ PVOID temp_ace;
+ if (!GetAce(dacl, index, &temp_ace))
+ return false;
+ PACE_HEADER header = static_cast<PACE_HEADER>(temp_ace);
+ if ((header->AceType != ACCESS_ALLOWED_ACE_TYPE) &&
+ (header->AceType != ACCESS_DENIED_ACE_TYPE)) {
+ continue;
+ }
+ // Allowed and deny aces have the same underlying structure.
+ PACCESS_ALLOWED_ACE ace = static_cast<PACCESS_ALLOWED_ACE>(temp_ace);
+ if (!::IsValidSid(&ace->SidStart)) {
+ continue;
+ }
+ if (::EqualSid(&ace->SidStart, any_package_sid.GetPSID())) {
+ ace->Mask = 0;
+ }
+ }
+ }
+
+ PRIVILEGE_SET priv_set = {};
+ DWORD priv_set_length = sizeof(PRIVILEGE_SET);
+
+ base::win::ScopedHandle token;
+ if (!BuildLowBoxToken(&token))
+ return false;
+
+ return !!::AccessCheck(sd, token.Get(), desired_access, &generic_mapping,
+ &priv_set, &priv_set_length, granted_access,
+ access_status);
+}
+
+bool AppContainerProfileBase::AddCapability(const wchar_t* capability_name) {
+ return AddCapability(Sid::FromNamedCapability(capability_name), false);
+}
+
+bool AppContainerProfileBase::AddCapability(WellKnownCapabilities capability) {
+ return AddCapability(Sid::FromKnownCapability(capability), false);
+}
+
+bool AppContainerProfileBase::AddCapabilitySddl(const wchar_t* sddl_sid) {
+ return AddCapability(Sid::FromSddlString(sddl_sid), false);
+}
+
+bool AppContainerProfileBase::AddCapability(const Sid& capability_sid,
+ bool impersonation_only) {
+ if (!capability_sid.IsValid())
+ return false;
+ if (!impersonation_only)
+ capabilities_.push_back(capability_sid);
+ impersonation_capabilities_.push_back(capability_sid);
+ return true;
+}
+
+bool AppContainerProfileBase::AddImpersonationCapability(
+ const wchar_t* capability_name) {
+ return AddCapability(Sid::FromNamedCapability(capability_name), true);
+}
+
+bool AppContainerProfileBase::AddImpersonationCapability(
+ WellKnownCapabilities capability) {
+ return AddCapability(Sid::FromKnownCapability(capability), true);
+}
+
+bool AppContainerProfileBase::AddImpersonationCapabilitySddl(
+ const wchar_t* sddl_sid) {
+ return AddCapability(Sid::FromSddlString(sddl_sid), true);
+}
+
+const std::vector<Sid>& AppContainerProfileBase::GetCapabilities() {
+ return capabilities_;
+}
+
+const std::vector<Sid>&
+AppContainerProfileBase::GetImpersonationCapabilities() {
+ return impersonation_capabilities_;
+}
+
+Sid AppContainerProfileBase::GetPackageSid() const {
+ return package_sid_;
+}
+
+void AppContainerProfileBase::SetEnableLowPrivilegeAppContainer(bool enable) {
+ enable_low_privilege_app_container_ = enable;
+}
+
+bool AppContainerProfileBase::GetEnableLowPrivilegeAppContainer() {
+ return enable_low_privilege_app_container_;
+}
+
+std::unique_ptr<SecurityCapabilities>
+AppContainerProfileBase::GetSecurityCapabilities() {
+ return std::unique_ptr<SecurityCapabilities>(
+ new SecurityCapabilities(package_sid_, capabilities_));
+}
+
+bool AppContainerProfileBase::BuildLowBoxToken(base::win::ScopedHandle* token) {
+ return CreateLowBoxToken(nullptr, IMPERSONATION,
+ GetSecurityCapabilities().get(), nullptr, 0,
+ token) == ERROR_SUCCESS;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.h b/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.h
new file mode 100644
index 0000000000..35fb4efdf5
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/app_container_profile_base.h
@@ -0,0 +1,94 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_APP_CONTAINER_PROFILE_BASE_H_
+#define SANDBOX_SRC_APP_CONTAINER_PROFILE_BASE_H_
+
+#include <windows.h>
+
+#include <accctrl.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/app_container_profile.h"
+#include "sandbox/win/src/security_capabilities.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+class AppContainerProfileBase final : public AppContainerProfile {
+ public:
+ void AddRef() override;
+ void Release() override;
+ bool GetRegistryLocation(REGSAM desired_access,
+ base::win::ScopedHandle* key) override;
+ bool GetFolderPath(base::FilePath* file_path) override;
+ bool GetPipePath(const wchar_t* pipe_name,
+ base::FilePath* pipe_path) override;
+ bool AccessCheck(const wchar_t* object_name,
+ SE_OBJECT_TYPE object_type,
+ DWORD desired_access,
+ DWORD* granted_access,
+ BOOL* access_status) override;
+ bool AddCapability(const wchar_t* capability_name) override;
+ bool AddCapability(WellKnownCapabilities capability) override;
+ bool AddCapabilitySddl(const wchar_t* sddl_sid) override;
+ bool AddImpersonationCapability(const wchar_t* capability_name) override;
+ bool AddImpersonationCapability(WellKnownCapabilities capability) override;
+ bool AddImpersonationCapabilitySddl(const wchar_t* sddl_sid) override;
+ void SetEnableLowPrivilegeAppContainer(bool enable) override;
+ bool GetEnableLowPrivilegeAppContainer() override;
+
+ // Get the package SID for this AC.
+ Sid GetPackageSid() const;
+
+ // Get an allocated SecurityCapabilities object for this App Container.
+ std::unique_ptr<SecurityCapabilities> GetSecurityCapabilities();
+
+ // Get a vector of capabilities.
+ const std::vector<Sid>& GetCapabilities();
+
+ // Get a vector of impersonation only capabilities. Used if the process needs
+ // a more privileged token to start.
+ const std::vector<Sid>& GetImpersonationCapabilities();
+
+ // Creates a new AppContainerProfile object. This will create a new profile
+ // if it doesn't already exist. The profile must be deleted manually using
+ // the Delete method if it's no longer required.
+ static AppContainerProfileBase* Create(const wchar_t* package_name,
+ const wchar_t* display_name,
+ const wchar_t* description);
+
+ // Opens an AppContainerProfile object. No checks will be made on
+ // whether the package exists or not.
+ static AppContainerProfileBase* Open(const wchar_t* package_name);
+
+ // Delete a profile based on name. Returns true if successful, or if the
+ // package doesn't already exist.
+ static bool Delete(const wchar_t* package_name);
+
+ private:
+ AppContainerProfileBase(const Sid& package_sid);
+ ~AppContainerProfileBase();
+
+ bool BuildLowBoxToken(base::win::ScopedHandle* token);
+ bool AddCapability(const Sid& capability_sid, bool impersonation_only);
+
+ // Standard object-lifetime reference counter.
+ volatile LONG ref_count_;
+ Sid package_sid_;
+ bool enable_low_privilege_app_container_;
+ std::vector<Sid> capabilities_;
+ std::vector<Sid> impersonation_capabilities_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppContainerProfileBase);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_APP_CONTAINER_PROFILE_BASE_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_test.cc b/security/sandbox/chromium/sandbox/win/src/app_container_test.cc
new file mode 100644
index 0000000000..a6c0948a94
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/app_container_test.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include <sddl.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/app_container_profile_base.h"
+#include "sandbox/win/src/sync_policy_test.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+const wchar_t kAppContainerSid[] =
+ L"S-1-15-2-3251537155-1984446955-2931258699-841473695-1938553385-"
+ L"924012148-2839372144";
+
+std::wstring GenerateRandomPackageName() {
+ return base::StringPrintf(L"%016lX%016lX", base::RandUint64(),
+ base::RandUint64());
+}
+
+const char* TokenTypeToName(TOKEN_TYPE token_type) {
+ return token_type == ::TokenPrimary ? "Primary Token" : "Impersonation Token";
+}
+
+void CheckToken(HANDLE token,
+ TOKEN_TYPE token_type,
+ PSECURITY_CAPABILITIES security_capabilities,
+ BOOL restricted) {
+ ASSERT_EQ(restricted, ::IsTokenRestricted(token))
+ << TokenTypeToName(token_type);
+
+ DWORD appcontainer;
+ DWORD return_length;
+ ASSERT_TRUE(::GetTokenInformation(token, ::TokenIsAppContainer, &appcontainer,
+ sizeof(appcontainer), &return_length))
+ << TokenTypeToName(token_type);
+ ASSERT_TRUE(appcontainer) << TokenTypeToName(token_type);
+ TOKEN_TYPE token_type_real;
+ ASSERT_TRUE(::GetTokenInformation(token, ::TokenType, &token_type_real,
+ sizeof(token_type_real), &return_length))
+ << TokenTypeToName(token_type);
+ ASSERT_EQ(token_type_real, token_type) << TokenTypeToName(token_type);
+ if (token_type == ::TokenImpersonation) {
+ SECURITY_IMPERSONATION_LEVEL imp_level;
+ ASSERT_TRUE(::GetTokenInformation(token, ::TokenImpersonationLevel,
+ &imp_level, sizeof(imp_level),
+ &return_length))
+ << TokenTypeToName(token_type);
+ ASSERT_EQ(imp_level, ::SecurityImpersonation)
+ << TokenTypeToName(token_type);
+ }
+
+ std::unique_ptr<Sid> package_sid;
+ ASSERT_TRUE(GetTokenAppContainerSid(token, &package_sid))
+ << TokenTypeToName(token_type);
+ EXPECT_TRUE(::EqualSid(security_capabilities->AppContainerSid,
+ package_sid->GetPSID()))
+ << TokenTypeToName(token_type);
+
+ std::vector<SidAndAttributes> capabilities;
+ ASSERT_TRUE(GetTokenGroups(token, ::TokenCapabilities, &capabilities))
+ << TokenTypeToName(token_type);
+
+ ASSERT_EQ(capabilities.size(), security_capabilities->CapabilityCount)
+ << TokenTypeToName(token_type);
+ for (size_t index = 0; index < capabilities.size(); ++index) {
+ EXPECT_EQ(capabilities[index].GetAttributes(),
+ security_capabilities->Capabilities[index].Attributes)
+ << TokenTypeToName(token_type);
+ EXPECT_TRUE(::EqualSid(capabilities[index].GetPSID(),
+ security_capabilities->Capabilities[index].Sid))
+ << TokenTypeToName(token_type);
+ }
+}
+
+void CheckProcessToken(HANDLE process,
+ PSECURITY_CAPABILITIES security_capabilities,
+ bool restricted) {
+ HANDLE token_handle;
+ ASSERT_TRUE(::OpenProcessToken(process, TOKEN_ALL_ACCESS, &token_handle));
+ base::win::ScopedHandle token(token_handle);
+ CheckToken(token_handle, ::TokenPrimary, security_capabilities, restricted);
+}
+
+void CheckThreadToken(HANDLE thread,
+ PSECURITY_CAPABILITIES security_capabilities,
+ bool restricted) {
+ HANDLE token_handle;
+ ASSERT_TRUE(::OpenThreadToken(thread, TOKEN_ALL_ACCESS, TRUE, &token_handle));
+ base::win::ScopedHandle token(token_handle);
+ CheckToken(token_handle, ::TokenImpersonation, security_capabilities,
+ restricted);
+}
+
+// Check for LPAC using an access check. We could query for a security attribute
+// but that's undocumented and has the potential to change.
+void CheckLpacToken(HANDLE process) {
+ HANDLE token_handle;
+ ASSERT_TRUE(::OpenProcessToken(process, TOKEN_ALL_ACCESS, &token_handle));
+ base::win::ScopedHandle token(token_handle);
+ ASSERT_TRUE(
+ ::DuplicateToken(token.Get(), ::SecurityImpersonation, &token_handle));
+ token.Set(token_handle);
+ PSECURITY_DESCRIPTOR security_desc_ptr;
+ // AC is AllPackages, S-1-15-2-2 is AllRestrictedPackages. An LPAC token
+ // will get granted access of 2, where as a normal AC token will get 3.
+ ASSERT_TRUE(::ConvertStringSecurityDescriptorToSecurityDescriptor(
+ L"O:SYG:SYD:(A;;0x3;;;WD)(A;;0x1;;;AC)(A;;0x2;;;S-1-15-2-2)",
+ SDDL_REVISION_1, &security_desc_ptr, nullptr));
+ std::unique_ptr<void, LocalFreeDeleter> security_desc(security_desc_ptr);
+ GENERIC_MAPPING generic_mapping = {};
+ PRIVILEGE_SET priv_set = {};
+ DWORD priv_set_length = sizeof(PRIVILEGE_SET);
+ DWORD granted_access;
+ BOOL access_status;
+ ASSERT_TRUE(::AccessCheck(security_desc_ptr, token.Get(), MAXIMUM_ALLOWED,
+ &generic_mapping, &priv_set, &priv_set_length,
+ &granted_access, &access_status));
+ ASSERT_TRUE(access_status);
+ ASSERT_EQ(DWORD{2}, granted_access);
+}
+
+class AppContainerProfileTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return;
+ package_name_ = GenerateRandomPackageName();
+ broker_services_ = GetBroker();
+ policy_ = broker_services_->CreatePolicy();
+ ASSERT_EQ(SBOX_ALL_OK,
+ policy_->SetProcessMitigations(MITIGATION_HEAP_TERMINATE));
+ ASSERT_EQ(SBOX_ALL_OK,
+ policy_->AddAppContainerProfile(package_name_.c_str(), true));
+ // For testing purposes we known the base class so cast directly.
+ profile_ = static_cast<AppContainerProfileBase*>(
+ policy_->GetAppContainerProfile().get());
+ }
+
+ void TearDown() override {
+ if (scoped_process_info_.IsValid())
+ ::TerminateProcess(scoped_process_info_.process_handle(), 0);
+ if (profile_)
+ AppContainerProfileBase::Delete(package_name_.c_str());
+ }
+
+ protected:
+ void CreateProcess() {
+ // Get the path to the sandboxed app.
+ wchar_t prog_name[MAX_PATH] = {};
+ ASSERT_NE(DWORD{0}, ::GetModuleFileNameW(nullptr, prog_name, MAX_PATH));
+
+ PROCESS_INFORMATION process_info = {};
+ ResultCode last_warning = SBOX_ALL_OK;
+ DWORD last_error = 0;
+ ResultCode result = broker_services_->SpawnTarget(
+ prog_name, prog_name, policy_, &last_warning, &last_error,
+ &process_info);
+ ASSERT_EQ(SBOX_ALL_OK, result) << "Last Error: " << last_error;
+ scoped_process_info_.Set(process_info);
+ }
+
+ std::wstring package_name_;
+ BrokerServices* broker_services_;
+ scoped_refptr<AppContainerProfileBase> profile_;
+ scoped_refptr<TargetPolicy> policy_;
+ base::win::ScopedProcessInformation scoped_process_info_;
+};
+
+} // namespace
+
+
+TEST(AppContainerTest, DenyOpenEventForLowBox) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return;
+
+ TestRunner runner(JOB_UNPROTECTED, USER_UNPROTECTED, USER_UNPROTECTED);
+
+ EXPECT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetLowBox(kAppContainerSid));
+ // Run test once, this ensures the app container directory exists, we
+ // ignore the result.
+ runner.RunTest(L"Event_Open f test");
+ std::wstring event_name = L"AppContainerNamedObjects\\";
+ event_name += kAppContainerSid;
+ event_name += L"\\test";
+
+ base::win::ScopedHandle event(
+ ::CreateEvent(nullptr, false, false, event_name.c_str()));
+ ASSERT_TRUE(event.IsValid());
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test"));
+}
+
+TEST_F(AppContainerProfileTest, CheckIncompatibleOptions) {
+ if (!profile_)
+ return;
+ EXPECT_EQ(SBOX_ERROR_BAD_PARAMS,
+ policy_->SetIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED));
+ EXPECT_EQ(SBOX_ERROR_BAD_PARAMS, policy_->SetLowBox(kAppContainerSid));
+
+ MitigationFlags expected_mitigations = 0;
+ MitigationFlags expected_delayed = MITIGATION_HEAP_TERMINATE;
+ sandbox::ResultCode expected_result = SBOX_ERROR_BAD_PARAMS;
+
+ if (base::win::GetVersion() >= base::win::Version::WIN10_RS5) {
+ expected_mitigations = MITIGATION_HEAP_TERMINATE;
+ expected_delayed = 0;
+ expected_result = SBOX_ALL_OK;
+ }
+
+ EXPECT_EQ(expected_mitigations, policy_->GetProcessMitigations());
+ EXPECT_EQ(expected_delayed, policy_->GetDelayedProcessMitigations());
+ EXPECT_EQ(expected_result,
+ policy_->SetProcessMitigations(MITIGATION_HEAP_TERMINATE));
+}
+
+TEST_F(AppContainerProfileTest, NoCapabilities) {
+ if (!profile_)
+ return;
+
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), FALSE);
+}
+
+TEST_F(AppContainerProfileTest, NoCapabilitiesRestricted) {
+ if (!profile_)
+ return;
+
+ policy_->SetTokenLevel(USER_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), TRUE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), TRUE);
+}
+
+TEST_F(AppContainerProfileTest, WithCapabilities) {
+ if (!profile_)
+ return;
+
+ profile_->AddCapability(kInternetClient);
+ profile_->AddCapability(kInternetClientServer);
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), FALSE);
+}
+
+TEST_F(AppContainerProfileTest, WithCapabilitiesRestricted) {
+ if (!profile_)
+ return;
+
+ profile_->AddCapability(kInternetClient);
+ profile_->AddCapability(kInternetClientServer);
+ policy_->SetTokenLevel(USER_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), TRUE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), TRUE);
+}
+
+TEST_F(AppContainerProfileTest, WithImpersonationCapabilities) {
+ if (!profile_)
+ return;
+
+ profile_->AddCapability(kInternetClient);
+ profile_->AddCapability(kInternetClientServer);
+ profile_->AddImpersonationCapability(kPrivateNetworkClientServer);
+ profile_->AddImpersonationCapability(kPicturesLibrary);
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ SecurityCapabilities impersonation_security_capabilities(
+ profile_->GetPackageSid(), profile_->GetImpersonationCapabilities());
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ &impersonation_security_capabilities, FALSE);
+}
+
+TEST_F(AppContainerProfileTest, NoCapabilitiesLPAC) {
+ if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
+ return;
+
+ profile_->SetEnableLowPrivilegeAppContainer(true);
+ policy_->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ policy_->SetJobLevel(JOB_NONE, 0);
+
+ CreateProcess();
+ auto security_capabilities = profile_->GetSecurityCapabilities();
+
+ CheckProcessToken(scoped_process_info_.process_handle(),
+ security_capabilities.get(), FALSE);
+ CheckThreadToken(scoped_process_info_.thread_handle(),
+ security_capabilities.get(), FALSE);
+ CheckLpacToken(scoped_process_info_.process_handle());
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.cc b/security/sandbox/chromium/sandbox/win/src/broker_services.cc
new file mode 100644
index 0000000000..0ba71bbd5d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/broker_services.cc
@@ -0,0 +1,748 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/broker_services.h"
+
+#include <aclapi.h>
+
+#include <stddef.h>
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/platform_thread.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/app_container_profile.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/sandbox_policy_diagnostic.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/win2k_threadpool.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// Utility function to associate a completion port to a job object.
+bool AssociateCompletionPort(HANDLE job, HANDLE port, void* key) {
+ JOBOBJECT_ASSOCIATE_COMPLETION_PORT job_acp = {key, port};
+ return ::SetInformationJobObject(job,
+ JobObjectAssociateCompletionPortInformation,
+ &job_acp, sizeof(job_acp))
+ ? true
+ : false;
+}
+
+// Utility function to do the cleanup necessary when something goes wrong
+// while in SpawnTarget and we must terminate the target process.
+sandbox::ResultCode SpawnCleanup(sandbox::TargetProcess* target) {
+ target->Terminate();
+ delete target;
+ return sandbox::SBOX_ERROR_GENERIC;
+}
+
+// the different commands that you can send to the worker thread that
+// executes TargetEventsThread().
+enum {
+ THREAD_CTRL_NONE,
+ THREAD_CTRL_NEW_JOB_TRACKER,
+ THREAD_CTRL_NEW_PROCESS_TRACKER,
+ THREAD_CTRL_PROCESS_SIGNALLED,
+ THREAD_CTRL_GET_POLICY_INFO,
+ THREAD_CTRL_QUIT,
+ THREAD_CTRL_LAST,
+};
+
+// Helper structure that allows the Broker to associate a job notification
+// with a job object and with a policy.
+struct JobTracker {
+ JobTracker(base::win::ScopedHandle job,
+ scoped_refptr<sandbox::PolicyBase> policy,
+ DWORD process_id)
+ : job(std::move(job)), policy(policy), process_id(process_id) {}
+ ~JobTracker() { FreeResources(); }
+
+ // Releases the Job and notifies the associated Policy object to release its
+ // resources as well.
+ void FreeResources();
+
+ base::win::ScopedHandle job;
+ scoped_refptr<sandbox::PolicyBase> policy;
+ DWORD process_id;
+};
+
+void JobTracker::FreeResources() {
+ if (policy) {
+ bool res = ::TerminateJobObject(job.Get(), sandbox::SBOX_ALL_OK);
+ DCHECK(res);
+ // Closing the job causes the target process to be destroyed so this needs
+ // to happen before calling OnJobEmpty().
+ HANDLE stale_job_handle = job.Get();
+ job.Close();
+
+ // In OnJobEmpty() we don't actually use the job handle directly.
+ policy->OnJobEmpty(stale_job_handle);
+ policy = nullptr;
+ }
+}
+
+// tracks processes that are not in jobs
+struct ProcessTracker {
+ ProcessTracker(scoped_refptr<sandbox::PolicyBase> policy,
+ DWORD process_id,
+ base::win::ScopedHandle process)
+ : policy(policy), process_id(process_id), process(std::move(process)) {}
+ ~ProcessTracker() { FreeResources(); }
+
+ void FreeResources();
+
+ scoped_refptr<sandbox::PolicyBase> policy;
+ DWORD process_id;
+ base::win::ScopedHandle process;
+ // Used to UnregisterWait. Not a real handle so cannot CloseHandle().
+ HANDLE wait_handle;
+ // IOCP that is tracking this non-job process
+ HANDLE iocp;
+};
+
+void ProcessTracker::FreeResources() {
+ if (policy) {
+ policy->OnJobEmpty(nullptr);
+ policy = nullptr;
+ }
+}
+
+// Helper redispatches process events to tracker thread.
+void WINAPI ProcessEventCallback(PVOID param, BOOLEAN ignored) {
+ // This callback should do very little, and must be threadpool safe.
+ ProcessTracker* tracker = reinterpret_cast<ProcessTracker*>(param);
+ // If this fails we can do nothing... we will leak the policy.
+ ::PostQueuedCompletionStatus(tracker->iocp, 0, THREAD_CTRL_PROCESS_SIGNALLED,
+ reinterpret_cast<LPOVERLAPPED>(tracker));
+}
+
+// Helper class to send policy lists
+class PolicyDiagnosticList final : public sandbox::PolicyList {
+ public:
+ PolicyDiagnosticList() {}
+ ~PolicyDiagnosticList() override {}
+ void push_back(std::unique_ptr<sandbox::PolicyInfo> info) {
+ internal_list_.push_back(std::move(info));
+ }
+ std::vector<std::unique_ptr<sandbox::PolicyInfo>>::iterator begin() override {
+ return internal_list_.begin();
+ }
+ std::vector<std::unique_ptr<sandbox::PolicyInfo>>::iterator end() override {
+ return internal_list_.end();
+ }
+ size_t size() const override { return internal_list_.size(); }
+
+ private:
+ std::vector<std::unique_ptr<sandbox::PolicyInfo>> internal_list_;
+};
+
+} // namespace
+
+namespace sandbox {
+
+BrokerServicesBase::BrokerServicesBase() {}
+
+// The broker uses a dedicated worker thread that services the job completion
+// port to perform policy notifications and associated cleanup tasks.
+ResultCode BrokerServicesBase::Init() {
+ if (job_port_.IsValid() || thread_pool_)
+ return SBOX_ERROR_UNEXPECTED_CALL;
+
+ ::InitializeCriticalSection(&lock_);
+
+ job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0));
+ if (!job_port_.IsValid())
+ return SBOX_ERROR_CANNOT_INIT_BROKERSERVICES;
+
+ no_targets_.Set(::CreateEventW(nullptr, true, false, nullptr));
+
+ job_thread_.Set(::CreateThread(nullptr, 0, // Default security and stack.
+ TargetEventsThread, this, 0, nullptr));
+ if (!job_thread_.IsValid())
+ return SBOX_ERROR_CANNOT_INIT_BROKERSERVICES;
+
+ if (!SharedMemIPCServer::CreateBrokerAliveMutex())
+ return SBOX_ERROR_CANNOT_INIT_BROKERSERVICES;
+
+ return SBOX_ALL_OK;
+}
+
+// The destructor should only be called when the Broker process is terminating.
+// Since BrokerServicesBase is a singleton, this is called from the CRT
+// termination handlers, if this code lives on a DLL it is called during
+// DLL_PROCESS_DETACH in other words, holding the loader lock, so we cannot
+// wait for threads here.
+BrokerServicesBase::~BrokerServicesBase() {
+ // If there is no port Init() was never called successfully.
+ if (!job_port_.IsValid())
+ return;
+
+ // Closing the port causes, that no more Job notifications are delivered to
+ // the worker thread and also causes the thread to exit. This is what we
+ // want to do since we are going to close all outstanding Jobs and notifying
+ // the policy objects ourselves.
+ ::PostQueuedCompletionStatus(job_port_.Get(), 0, THREAD_CTRL_QUIT, nullptr);
+
+ if (job_thread_.IsValid() &&
+ WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_.Get(), 1000)) {
+ // Cannot clean broker services.
+ NOTREACHED();
+ return;
+ }
+ thread_pool_.reset();
+ ::DeleteCriticalSection(&lock_);
+}
+
+scoped_refptr<TargetPolicy> BrokerServicesBase::CreatePolicy() {
+ // If you change the type of the object being created here you must also
+ // change the downcast to it in SpawnTarget().
+ scoped_refptr<TargetPolicy> policy(new PolicyBase);
+ // PolicyBase starts with refcount 1.
+ policy->Release();
+ return policy;
+}
+
+// The worker thread stays in a loop waiting for asynchronous notifications
+// from the job objects. Right now we only care about knowing when the last
+// process on a job terminates, but in general this is the place to tell
+// the policy about events.
+DWORD WINAPI BrokerServicesBase::TargetEventsThread(PVOID param) {
+ if (!param)
+ return 1;
+
+ base::PlatformThread::SetName("BrokerEvent");
+
+ BrokerServicesBase* broker = reinterpret_cast<BrokerServicesBase*>(param);
+ HANDLE port = broker->job_port_.Get();
+ HANDLE no_targets = broker->no_targets_.Get();
+
+ std::set<DWORD> child_process_ids;
+ std::list<std::unique_ptr<JobTracker>> jobs;
+ std::list<std::unique_ptr<ProcessTracker>> processes;
+ int target_counter = 0;
+ int untracked_target_counter = 0;
+ ::ResetEvent(no_targets);
+
+ while (true) {
+ DWORD events = 0;
+ ULONG_PTR key = 0;
+ LPOVERLAPPED ovl = nullptr;
+
+ if (!::GetQueuedCompletionStatus(port, &events, &key, &ovl, INFINITE)) {
+ // this call fails if the port has been closed before we have a
+ // chance to service the last packet which is 'exit' anyway so
+ // this is not an error.
+ return 1;
+ }
+
+ if (key > THREAD_CTRL_LAST) {
+ // The notification comes from a job object. There are nine notifications
+ // that jobs can send and some of them depend on the job attributes set.
+ JobTracker* tracker = reinterpret_cast<JobTracker*>(key);
+
+ // Processes may be added to a job after the process count has
+ // reached zero, leading us to manipulate a freed JobTracker
+ // object or job handle (as the key is no longer valid). We
+ // therefore check if the tracker has already been deleted.
+ if (std::find_if(jobs.begin(), jobs.end(), [&](auto&& p) -> bool {
+ return p.get() == tracker;
+ }) == jobs.end()) {
+ CHECK(false);
+ }
+
+ switch (events) {
+ case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: {
+ // The job object has signaled that the last process associated
+ // with it has terminated. It is safe to free the tracker
+ // and release its reference to the associated policy object
+ // which will Close the job handle.
+ HANDLE job_handle = tracker->job.Get();
+
+ // Erase by comparing with the job handle.
+ jobs.erase(std::remove_if(jobs.begin(), jobs.end(),
+ [&](auto&& p) -> bool {
+ return p->job.Get() == job_handle;
+ }),
+ jobs.end());
+ break;
+ }
+
+ case JOB_OBJECT_MSG_NEW_PROCESS: {
+ // Child process created from sandboxed process.
+ DWORD process_id =
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl));
+ size_t count = child_process_ids.count(process_id);
+ if (count == 0)
+ untracked_target_counter++;
+ ++target_counter;
+ if (1 == target_counter) {
+ ::ResetEvent(no_targets);
+ }
+ break;
+ }
+
+ case JOB_OBJECT_MSG_EXIT_PROCESS:
+ case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
+ {
+ AutoLock lock(&broker->lock_);
+ broker->active_targets_.erase(
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
+ }
+ size_t erase_result = child_process_ids.erase(
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
+ if (erase_result != 1U) {
+ // The process was untracked e.g. a child process of the target.
+ --untracked_target_counter;
+ DCHECK(untracked_target_counter >= 0);
+ }
+ --target_counter;
+ if (0 == target_counter)
+ ::SetEvent(no_targets);
+
+ DCHECK(target_counter >= 0);
+ break;
+ }
+
+ case JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT: {
+ // A child process attempted and failed to create a child process.
+ // Windows does not reveal the process id.
+ untracked_target_counter++;
+ target_counter++;
+ break;
+ }
+
+ case JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT: {
+ bool res = ::TerminateJobObject(tracker->job.Get(),
+ SBOX_FATAL_MEMORY_EXCEEDED);
+ DCHECK(res);
+ break;
+ }
+
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+ } else if (THREAD_CTRL_NEW_JOB_TRACKER == key) {
+ std::unique_ptr<JobTracker> tracker;
+ tracker.reset(reinterpret_cast<JobTracker*>(ovl));
+ DCHECK(tracker->job.IsValid());
+
+ child_process_ids.insert(tracker->process_id);
+ jobs.push_back(std::move(tracker));
+
+ } else if (THREAD_CTRL_NEW_PROCESS_TRACKER == key) {
+ std::unique_ptr<ProcessTracker> tracker;
+ tracker.reset(reinterpret_cast<ProcessTracker*>(ovl));
+
+ if (child_process_ids.empty()) {
+ ::SetEvent(broker->no_targets_.Get());
+ }
+
+ tracker->iocp = port;
+ if (!::RegisterWaitForSingleObject(&(tracker->wait_handle),
+ tracker->process.Get(),
+ ProcessEventCallback, tracker.get(),
+ INFINITE, WT_EXECUTEONLYONCE)) {
+ // Failed. Invalidate the wait_handle and store anyway.
+ tracker->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ processes.push_back(std::move(tracker));
+
+ } else if (THREAD_CTRL_PROCESS_SIGNALLED == key) {
+ ProcessTracker* tracker =
+ static_cast<ProcessTracker*>(reinterpret_cast<void*>(ovl));
+
+ {
+ AutoLock lock(&broker->lock_);
+ broker->active_targets_.erase(tracker->process_id);
+ }
+
+ ::UnregisterWait(tracker->wait_handle);
+ tracker->wait_handle = INVALID_HANDLE_VALUE;
+ // Copy process_id so that we can legally reference it even after we have
+ // found the ProcessTracker object to delete.
+ const DWORD process_id = tracker->process_id;
+ // PID is unique until the process handle is closed in dtor.
+ processes.erase(std::remove_if(processes.begin(), processes.end(),
+ [&](auto&& p) -> bool {
+ return p->process_id == process_id;
+ }),
+ processes.end());
+ } else if (THREAD_CTRL_GET_POLICY_INFO == key) {
+ // Clone the policies for sandbox diagnostics.
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver;
+ receiver.reset(static_cast<PolicyDiagnosticsReceiver*>(
+ reinterpret_cast<void*>(ovl)));
+ // The PollicyInfo ctor copies essential information from the trackers.
+ auto policy_list = std::make_unique<PolicyDiagnosticList>();
+ for (auto&& process_tracker : processes) {
+ if (process_tracker->policy) {
+ policy_list->push_back(std::make_unique<PolicyDiagnostic>(
+ process_tracker->policy.get()));
+ }
+ }
+ for (auto&& job_tracker : jobs) {
+ if (job_tracker->policy) {
+ policy_list->push_back(
+ std::make_unique<PolicyDiagnostic>(job_tracker->policy.get()));
+ }
+ }
+ // Receiver should return quickly.
+ receiver->ReceiveDiagnostics(std::move(policy_list));
+
+ } else if (THREAD_CTRL_QUIT == key) {
+ // The broker object is being destroyed so the thread needs to exit.
+ for (auto&& tracker : processes) {
+ ::UnregisterWait(tracker->wait_handle);
+ tracker->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ // After this point, so further calls to ProcessEventCallback can
+ // occur. Other tracked objects are destroyed as this thread ends.
+ return 0;
+ } else {
+ // We have not implemented more commands.
+ NOTREACHED();
+ }
+ }
+
+ NOTREACHED();
+ return 0;
+}
+
+// SpawnTarget does all the interesting sandbox setup and creates the target
+// process inside the sandbox.
+ResultCode BrokerServicesBase::SpawnTarget(const wchar_t* exe_path,
+ const wchar_t* command_line,
+ base::EnvironmentMap& env_map,
+ scoped_refptr<TargetPolicy> policy,
+ ResultCode* last_warning,
+ DWORD* last_error,
+ PROCESS_INFORMATION* target_info) {
+ if (!exe_path)
+ return SBOX_ERROR_BAD_PARAMS;
+
+ if (!policy)
+ return SBOX_ERROR_BAD_PARAMS;
+
+ // Even though the resources touched by SpawnTarget can be accessed in
+ // multiple threads, the method itself cannot be called from more than one
+ // thread. This is to protect the global variables used while setting up the
+ // child process, and to make sure launcher thread mitigations are applied
+ // correctly.
+ static DWORD thread_id = ::GetCurrentThreadId();
+ DCHECK(thread_id == ::GetCurrentThreadId());
+ *last_warning = SBOX_ALL_OK;
+
+ // Launcher thread only needs to be opted out of ACG once. Do this on the
+ // first child process being spawned.
+ static bool launcher_thread_opted_out = false;
+
+ if (!launcher_thread_opted_out) {
+ // Soft fail this call. It will fail if ACG is not enabled for this process.
+ sandbox::ApplyMitigationsToCurrentThread(
+ sandbox::MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD);
+ launcher_thread_opted_out = true;
+ }
+
+ // This downcast is safe as long as we control CreatePolicy()
+ scoped_refptr<PolicyBase> policy_base(static_cast<PolicyBase*>(policy.get()));
+
+ // Construct the tokens and the job object that we are going to associate
+ // with the soon to be created target process.
+ base::win::ScopedHandle initial_token;
+ base::win::ScopedHandle lockdown_token;
+ base::win::ScopedHandle lowbox_token;
+ ResultCode result = SBOX_ALL_OK;
+
+ result =
+ policy_base->MakeTokens(&initial_token, &lockdown_token, &lowbox_token);
+ if (SBOX_ALL_OK != result)
+ return result;
+ if (lowbox_token.IsValid() &&
+ base::win::GetVersion() < base::win::Version::WIN8) {
+ // We don't allow lowbox_token below Windows 8.
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+
+ base::win::ScopedHandle job;
+ result = policy_base->MakeJobObject(&job);
+ if (SBOX_ALL_OK != result)
+ return result;
+
+ // Initialize the startup information from the policy.
+ base::win::StartupInformation startup_info;
+
+ // We don't want any child processes causing the IDC_APPSTARTING cursor.
+ startup_info.startup_info()->dwFlags |= STARTF_FORCEOFFFEEDBACK;
+
+ // The liftime of |mitigations|, |inherit_handle_list| and
+ // |child_process_creation| have to be at least as long as
+ // |startup_info| because |UpdateProcThreadAttribute| requires that
+ // its |lpValue| parameter persist until |DeleteProcThreadAttributeList| is
+ // called; StartupInformation's destructor makes such a call.
+ DWORD64 mitigations[2];
+ std::vector<HANDLE> inherited_handle_list;
+ DWORD child_process_creation = PROCESS_CREATION_CHILD_PROCESS_RESTRICTED;
+
+ std::wstring desktop = policy_base->GetAlternateDesktop();
+ if (!desktop.empty()) {
+ startup_info.startup_info()->lpDesktop =
+ const_cast<wchar_t*>(desktop.c_str());
+ }
+
+ bool inherit_handles = false;
+
+ int attribute_count = 0;
+
+ size_t mitigations_size;
+ ConvertProcessMitigationsToPolicy(policy_base->GetProcessMitigations(),
+ &mitigations[0], &mitigations_size);
+ if (mitigations[0] || mitigations[1])
+ ++attribute_count;
+
+ bool restrict_child_process_creation = false;
+ if (base::win::GetVersion() >= base::win::Version::WIN10_TH2 &&
+ policy_base->GetJobLevel() <= JOB_LIMITED_USER) {
+ restrict_child_process_creation = true;
+ ++attribute_count;
+ }
+
+ HANDLE stdout_handle = policy_base->GetStdoutHandle();
+ HANDLE stderr_handle = policy_base->GetStderrHandle();
+
+ if (stdout_handle != INVALID_HANDLE_VALUE)
+ inherited_handle_list.push_back(stdout_handle);
+
+ // Handles in the list must be unique.
+ if (stderr_handle != stdout_handle && stderr_handle != INVALID_HANDLE_VALUE)
+ inherited_handle_list.push_back(stderr_handle);
+
+ const auto& policy_handle_list = policy_base->GetHandlesBeingShared();
+
+ for (HANDLE handle : policy_handle_list)
+ inherited_handle_list.push_back(handle);
+
+ if (inherited_handle_list.size())
+ ++attribute_count;
+
+ scoped_refptr<AppContainerProfileBase> profile =
+ policy_base->GetAppContainerProfileBase();
+ if (profile) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return SBOX_ERROR_BAD_PARAMS;
+ ++attribute_count;
+ if (profile->GetEnableLowPrivilegeAppContainer()) {
+ // LPAC first supported in RS1.
+ if (base::win::GetVersion() < base::win::Version::WIN10_RS1)
+ return SBOX_ERROR_BAD_PARAMS;
+ ++attribute_count;
+ }
+ }
+
+ if (!startup_info.InitializeProcThreadAttributeList(attribute_count))
+ return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+
+ if (mitigations[0] || mitigations[1]) {
+ if (!startup_info.UpdateProcThreadAttribute(
+ PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mitigations[0],
+ mitigations_size)) {
+ return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+ }
+ }
+
+ if (restrict_child_process_creation) {
+ if (!startup_info.UpdateProcThreadAttribute(
+ PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY, &child_process_creation,
+ sizeof(child_process_creation))) {
+ return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+ }
+ }
+
+ if (inherited_handle_list.size()) {
+ if (!startup_info.UpdateProcThreadAttribute(
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &inherited_handle_list[0],
+ sizeof(HANDLE) * inherited_handle_list.size())) {
+ return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+ }
+ startup_info.startup_info()->dwFlags |= STARTF_USESTDHANDLES;
+ startup_info.startup_info()->hStdInput = INVALID_HANDLE_VALUE;
+ startup_info.startup_info()->hStdOutput = stdout_handle;
+ startup_info.startup_info()->hStdError = stderr_handle;
+ // Allowing inheritance of handles is only secure now that we
+ // have limited which handles will be inherited.
+ inherit_handles = true;
+ }
+
+ // Declared here to ensure they stay in scope until after process creation.
+ std::unique_ptr<SecurityCapabilities> security_capabilities;
+ DWORD all_applications_package_policy =
+ PROCESS_CREATION_ALL_APPLICATION_PACKAGES_OPT_OUT;
+
+ if (profile) {
+ security_capabilities = profile->GetSecurityCapabilities();
+ if (!startup_info.UpdateProcThreadAttribute(
+ PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
+ security_capabilities.get(), sizeof(SECURITY_CAPABILITIES))) {
+ return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+ }
+ if (profile->GetEnableLowPrivilegeAppContainer()) {
+ if (!startup_info.UpdateProcThreadAttribute(
+ PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY,
+ &all_applications_package_policy,
+ sizeof(all_applications_package_policy))) {
+ return SBOX_ERROR_PROC_THREAD_ATTRIBUTES;
+ }
+ }
+ }
+
+ // Construct the thread pool here in case it is expensive.
+ // The thread pool is shared by all the targets
+ if (!thread_pool_)
+ thread_pool_ = std::make_unique<Win2kThreadPool>();
+
+ // Create the TargetProcess object and spawn the target suspended. Note that
+ // Brokerservices does not own the target object. It is owned by the Policy.
+ base::win::ScopedProcessInformation process_info;
+ TargetProcess* target = new TargetProcess(
+ std::move(initial_token), std::move(lockdown_token), job.Get(),
+ thread_pool_.get(),
+ profile ? profile->GetImpersonationCapabilities() : std::vector<Sid>());
+
+ result = target->Create(exe_path, command_line, inherit_handles, startup_info,
+ &process_info, env_map, last_error);
+
+ if (result != SBOX_ALL_OK) {
+ SpawnCleanup(target);
+ return result;
+ }
+
+ if (lowbox_token.IsValid()) {
+ *last_warning = target->AssignLowBoxToken(lowbox_token);
+ // If this fails we continue, but report the error as a warning.
+ // This is due to certain configurations causing the setting of the
+ // token to fail post creation, and we'd rather continue if possible.
+ if (*last_warning != SBOX_ALL_OK)
+ *last_error = ::GetLastError();
+ }
+
+ // Now the policy is the owner of the target.
+ result = policy_base->AddTarget(target);
+
+ if (result != SBOX_ALL_OK) {
+ *last_error = ::GetLastError();
+ SpawnCleanup(target);
+ return result;
+ }
+
+ if (job.IsValid()) {
+ JobTracker* tracker =
+ new JobTracker(std::move(job), policy_base, process_info.process_id());
+
+ // Post the tracker to the tracking thread, then associate the job with
+ // the tracker. The worker thread takes ownership of these objects.
+ CHECK(::PostQueuedCompletionStatus(
+ job_port_.Get(), 0, THREAD_CTRL_NEW_JOB_TRACKER,
+ reinterpret_cast<LPOVERLAPPED>(tracker)));
+ // There is no obvious recovery after failure here. Previous version with
+ // SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639
+ CHECK(
+ AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), tracker));
+
+ AutoLock lock(&lock_);
+ active_targets_.insert(process_info.process_id());
+ } else {
+ result = AddTargetPeerInternal(process_info.process_handle(),
+ process_info.process_id(),
+ policy_base, last_error);
+ if (result != SBOX_ALL_OK) {
+ // This may fail in the same way as Job associated processes.
+ // crbug.com/480639.
+ target->Terminate();
+ return result;
+ }
+ }
+
+ *target_info = process_info.Take();
+ return result;
+}
+
+ResultCode BrokerServicesBase::WaitForAllTargets() {
+ ::WaitForSingleObject(no_targets_.Get(), INFINITE);
+ return SBOX_ALL_OK;
+}
+
+bool BrokerServicesBase::IsSafeDuplicationTarget(DWORD process_id) {
+ AutoLock lock(&lock_);
+ return active_targets_.find(process_id) != active_targets_.end();
+}
+
+ResultCode BrokerServicesBase::AddTargetPeerInternal(
+ HANDLE peer_process_handle,
+ DWORD peer_process_id,
+ scoped_refptr<PolicyBase> policy_base,
+ DWORD* last_error) {
+ // Duplicate the process handle to give the tracking machinery
+ // something valid to wait on in the tracking thread.
+ HANDLE tmp_process_handle = INVALID_HANDLE_VALUE;
+ if (!::DuplicateHandle(::GetCurrentProcess(), peer_process_handle,
+ ::GetCurrentProcess(), &tmp_process_handle,
+ SYNCHRONIZE, false, 0 /*no options*/)) {
+ *last_error = ::GetLastError();
+ return SBOX_ERROR_CANNOT_DUPLICATE_PROCESS_HANDLE;
+ }
+ base::win::ScopedHandle dup_process_handle(tmp_process_handle);
+ ProcessTracker* tracker = new ProcessTracker(
+ policy_base, peer_process_id, std::move(dup_process_handle));
+ // The tracker and policy will leak if this call fails.
+ ::PostQueuedCompletionStatus(job_port_.Get(), 0,
+ THREAD_CTRL_NEW_PROCESS_TRACKER,
+ reinterpret_cast<LPOVERLAPPED>(tracker));
+
+ AutoLock lock(&lock_);
+ active_targets_.insert(peer_process_id);
+
+ return SBOX_ALL_OK;
+}
+
+ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
+ DWORD last_error;
+ return AddTargetPeerInternal(peer_process, ::GetProcessId(peer_process),
+ nullptr, &last_error);
+}
+
+ResultCode BrokerServicesBase::GetPolicyDiagnostics(
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver) {
+ CHECK(job_thread_.IsValid());
+ // Post to the job thread.
+ if (!::PostQueuedCompletionStatus(
+ job_port_.Get(), 0, THREAD_CTRL_GET_POLICY_INFO,
+ reinterpret_cast<LPOVERLAPPED>(receiver.get()))) {
+ receiver->OnError(SBOX_ERROR_GENERIC);
+ return SBOX_ERROR_GENERIC;
+ }
+
+ // Ownership has passed to tracker thread.
+ receiver.release();
+ return SBOX_ALL_OK;
+}
+
+bool BrokerServicesBase::DeriveCapabilitySidFromName(const wchar_t* name,
+ PSID derived_sid,
+ DWORD sid_buffer_length) {
+ return ::CopySid(sid_buffer_length, derived_sid,
+ Sid::FromNamedCapability(name).GetPSID());
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.h b/security/sandbox/chromium/sandbox/win/src/broker_services.h
new file mode 100644
index 0000000000..64dc6d66e5
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/broker_services.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_BROKER_SERVICES_H_
+#define SANDBOX_WIN_SRC_BROKER_SERVICES_H_
+
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "base/environment.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/job.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+#include "sandbox/win/src/win2k_threadpool.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+// BrokerServicesBase ---------------------------------------------------------
+// Broker implementation version 0
+//
+// This is an implementation of the interface BrokerServices and
+// of the associated TargetProcess interface. In this implementation
+// TargetProcess is a friend of BrokerServices where the later manages a
+// collection of the former.
+class BrokerServicesBase final : public BrokerServices,
+ public SingletonBase<BrokerServicesBase> {
+ public:
+ BrokerServicesBase();
+
+ ~BrokerServicesBase();
+
+ // BrokerServices interface.
+ ResultCode Init() override;
+ scoped_refptr<TargetPolicy> CreatePolicy() override;
+ ResultCode SpawnTarget(const wchar_t* exe_path,
+ const wchar_t* command_line,
+ base::EnvironmentMap& env_map,
+ scoped_refptr<TargetPolicy> policy,
+ ResultCode* last_warning,
+ DWORD* last_error,
+ PROCESS_INFORMATION* target) override;
+ ResultCode WaitForAllTargets() override;
+ ResultCode AddTargetPeer(HANDLE peer_process) override;
+
+ // Checks if the supplied process ID matches one of the broker's active
+ // target processes. We use this method for the specific purpose of
+ // checking if we can safely duplicate a handle to the supplied process
+ // in DuplicateHandleProxyAction.
+ bool IsSafeDuplicationTarget(DWORD process_id);
+
+ ResultCode GetPolicyDiagnostics(
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver) override;
+
+ bool DeriveCapabilitySidFromName(const wchar_t* name, PSID derived_sid,
+ DWORD sid_buffer_length) override;
+
+ private:
+ // The routine that the worker thread executes. It is in charge of
+ // notifications and cleanup-related tasks.
+ static DWORD WINAPI TargetEventsThread(PVOID param);
+
+ // The completion port used by the job objects to communicate events to
+ // the worker thread.
+ base::win::ScopedHandle job_port_;
+
+ // Handle to a manual-reset event that is signaled when the total target
+ // process count reaches zero.
+ base::win::ScopedHandle no_targets_;
+
+ // Handle to the worker thread that reacts to job notifications.
+ base::win::ScopedHandle job_thread_;
+
+ // Provides a pool of threads that are used to wait on the IPC calls.
+ std::unique_ptr<ThreadProvider> thread_pool_;
+
+ // The set representing the broker's active target processes including
+ // both sandboxed and unsandboxed peer processes.
+ std::set<DWORD> active_targets_;
+
+ // Lock used to protect active_targets_ from being simultaneously accessed
+ // by multiple threads.
+ CRITICAL_SECTION lock_;
+
+ ResultCode AddTargetPeerInternal(HANDLE peer_process_handle,
+ DWORD peer_process_id,
+ scoped_refptr<PolicyBase> policy_base,
+ DWORD* last_error);
+
+ DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_BROKER_SERVICES_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/crosscall_client.h b/security/sandbox/chromium/sandbox/win/src/crosscall_client.h
new file mode 100644
index 0000000000..a346aeb753
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/crosscall_client.h
@@ -0,0 +1,509 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_CROSSCALL_CLIENT_H_
+#define SANDBOX_SRC_CROSSCALL_CLIENT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/sandbox.h"
+
+// This header defines the CrossCall(..) family of templated functions
+// Their purpose is to simulate the syntax of regular call but to generate
+// and IPC from the client-side.
+//
+// The basic pattern is to
+// 1) use template argument deduction to compute the size of each
+// parameter and the appropriate copy method
+// 2) pack the parameters in the appropriate ActualCallParams< > object
+// 3) call the IPC interface IPCProvider::DoCall( )
+//
+// The general interface of CrossCall is:
+// ResultCode CrossCall(IPCProvider& ipc_provider,
+// uint32_t tag,
+// const Par1& p1, const Par2& p2,...pn
+// CrossCallReturn* answer)
+//
+// where:
+// ipc_provider: is a specific implementation of the ipc transport see
+// sharedmem_ipc_server.h for an example.
+// tag : is the unique id for this IPC call. Is used to route the call to
+// the appropriate service.
+// p1, p2,.. pn : The input parameters of the IPC. Use only simple types
+// and wide strings (can add support for others).
+// answer : If the IPC was successful. The server-side answer is here. The
+// interpretation of the answer is private to client and server.
+//
+// The return value is ALL_OK if the IPC was delivered to the server, other
+// return codes indicate that the IPC transport failed to deliver it.
+namespace sandbox {
+
+enum class IpcTag;
+
+// The copy helper uses templates to deduce the appropriate copy function to
+// copy the input parameters in the buffer that is going to be send across the
+// IPC. These template facility can be made more sophisticated as need arises.
+
+// The default copy helper. It catches the general case where no other
+// specialized template matches better. We set the type to UINT32_TYPE, so this
+// only works with objects whose size is 32 bits.
+template <typename T>
+class CopyHelper {
+ public:
+ CopyHelper(const T& t) : t_(t) {}
+
+ // Returns the pointer to the start of the input.
+ const void* GetStart() const { return &t_; }
+
+ // Update the stored value with the value in the buffer. This is not
+ // supported for this type.
+ bool Update(void* buffer) {
+ // Not supported;
+ return true;
+ }
+
+ // Returns the size of the input in bytes.
+ uint32_t GetSize() const { return sizeof(T); }
+
+ // Returns true if the current type is used as an In or InOut parameter.
+ bool IsInOut() { return false; }
+
+ // Returns this object's type.
+ ArgType GetType() {
+ static_assert(sizeof(T) == sizeof(uint32_t), "specialization needed");
+ return UINT32_TYPE;
+ }
+
+ private:
+ const T& t_;
+};
+
+// This copy helper template specialization if for the void pointer
+// case both 32 and 64 bit.
+template <>
+class CopyHelper<void*> {
+ public:
+ CopyHelper(void* t) : t_(t) {}
+
+ // Returns the pointer to the start of the input.
+ const void* GetStart() const { return &t_; }
+
+ // Update the stored value with the value in the buffer. This is not
+ // supported for this type.
+ bool Update(void* buffer) {
+ // Not supported;
+ return true;
+ }
+
+ // Returns the size of the input in bytes.
+ uint32_t GetSize() const { return sizeof(t_); }
+
+ // Returns true if the current type is used as an In or InOut parameter.
+ bool IsInOut() { return false; }
+
+ // Returns this object's type.
+ ArgType GetType() { return VOIDPTR_TYPE; }
+
+ private:
+ const void* t_;
+};
+
+// This copy helper template specialization catches the cases where the
+// parameter is a pointer to a string.
+template <>
+class CopyHelper<const wchar_t*> {
+ public:
+ CopyHelper(const wchar_t* t) : t_(t) {}
+
+ // Returns the pointer to the start of the string.
+ const void* GetStart() const { return t_; }
+
+ // Update the stored value with the value in the buffer. This is not
+ // supported for this type.
+ bool Update(void* buffer) {
+ // Not supported;
+ return true;
+ }
+
+ // Returns the size of the string in bytes. We define a nullptr string to
+ // be of zero length.
+ uint32_t GetSize() const {
+ __try {
+ return (!t_) ? 0
+ : static_cast<uint32_t>(StringLength(t_) * sizeof(t_[0]));
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ return UINT32_MAX;
+ }
+ }
+
+ // Returns true if the current type is used as an In or InOut parameter.
+ bool IsInOut() { return false; }
+
+ ArgType GetType() { return WCHAR_TYPE; }
+
+ private:
+ // We provide our not very optimized version of wcslen(), since we don't
+ // want to risk having the linker use the version in the CRT since the CRT
+ // might not be present when we do an early IPC call.
+ static size_t CDECL StringLength(const wchar_t* wcs) {
+ const wchar_t* eos = wcs;
+ while (*eos++)
+ ;
+ return static_cast<size_t>(eos - wcs - 1);
+ }
+
+ const wchar_t* t_;
+};
+
+// Specialization for non-const strings. We just reuse the implementation of the
+// const string specialization.
+template <>
+class CopyHelper<wchar_t*> : public CopyHelper<const wchar_t*> {
+ public:
+ typedef CopyHelper<const wchar_t*> Base;
+ CopyHelper(wchar_t* t) : Base(t) {}
+
+ const void* GetStart() const { return Base::GetStart(); }
+
+ bool Update(void* buffer) { return Base::Update(buffer); }
+
+ uint32_t GetSize() const { return Base::GetSize(); }
+
+ bool IsInOut() { return Base::IsInOut(); }
+
+ ArgType GetType() { return Base::GetType(); }
+};
+
+// Specialization for wchar_t arrays strings. We just reuse the implementation
+// of the const string specialization.
+template <size_t n>
+class CopyHelper<const wchar_t[n]> : public CopyHelper<const wchar_t*> {
+ public:
+ typedef const wchar_t array[n];
+ typedef CopyHelper<const wchar_t*> Base;
+ CopyHelper(array t) : Base(t) {}
+
+ const void* GetStart() const { return Base::GetStart(); }
+
+ bool Update(void* buffer) { return Base::Update(buffer); }
+
+ uint32_t GetSize() const { return Base::GetSize(); }
+
+ bool IsInOut() { return Base::IsInOut(); }
+
+ ArgType GetType() { return Base::GetType(); }
+};
+
+// Generic encapsulation class containing a pointer to a buffer and the
+// size of the buffer. It is used by the IPC to be able to pass in/out
+// parameters.
+class InOutCountedBuffer : public CountedBuffer {
+ public:
+ InOutCountedBuffer(void* buffer, uint32_t size)
+ : CountedBuffer(buffer, size) {}
+};
+
+// This copy helper template specialization catches the cases where the
+// parameter is a an input buffer.
+template <>
+class CopyHelper<CountedBuffer> {
+ public:
+ CopyHelper(const CountedBuffer t) : t_(t) {}
+
+ // Returns the pointer to the start of the string.
+ const void* GetStart() const { return t_.Buffer(); }
+
+ // Update not required so just return true;
+ bool Update(void* buffer) { return true; }
+
+ // Returns the size of the string in bytes. We define a nullptr string to
+ // be of zero length.
+ uint32_t GetSize() const { return t_.Size(); }
+
+ // Returns true if the current type is used as an In or InOut parameter.
+ bool IsInOut() { return false; }
+
+ ArgType GetType() { return INPTR_TYPE; }
+
+ private:
+ const CountedBuffer t_;
+};
+
+// This copy helper template specialization catches the cases where the
+// parameter is a an input/output buffer.
+template <>
+class CopyHelper<InOutCountedBuffer> {
+ public:
+ CopyHelper(const InOutCountedBuffer t) : t_(t) {}
+
+ // Returns the pointer to the start of the string.
+ const void* GetStart() const { return t_.Buffer(); }
+
+ // Updates the buffer with the value from the new buffer in parameter.
+ bool Update(void* buffer) {
+ // We are touching user memory, this has to be done from inside a try
+ // except.
+ __try {
+ memcpy_wrapper(t_.Buffer(), buffer, t_.Size());
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ return false;
+ }
+ return true;
+ }
+
+ // Returns the size of the string in bytes. We define a nullptr string to
+ // be of zero length.
+ uint32_t GetSize() const { return t_.Size(); }
+
+ // Returns true if the current type is used as an In or InOut parameter.
+ bool IsInOut() { return true; }
+
+ ArgType GetType() { return INOUTPTR_TYPE; }
+
+ private:
+ const InOutCountedBuffer t_;
+};
+
+// The following two macros make it less error prone the generation
+// of CrossCall functions with ever more input parameters.
+
+#define XCALL_GEN_PARAMS_OBJ(num, params) \
+ typedef ActualCallParams<num, kIPCChannelSize> ActualParams; \
+ void* raw_mem = ipc_provider.GetBuffer(); \
+ if (!raw_mem) \
+ return SBOX_ERROR_NO_SPACE; \
+ ActualParams* params = new (raw_mem) ActualParams(tag);
+
+#define XCALL_GEN_COPY_PARAM(num, params) \
+ static_assert(kMaxIpcParams >= num, "too many parameters"); \
+ CopyHelper<Par##num> ch##num(p##num); \
+ if (!params->CopyParamIn(num - 1, ch##num.GetStart(), ch##num.GetSize(), \
+ ch##num.IsInOut(), ch##num.GetType())) \
+ return SBOX_ERROR_NO_SPACE;
+
+#define XCALL_GEN_UPDATE_PARAM(num, params) \
+ if (!ch##num.Update(params->GetParamPtr(num - 1))) { \
+ ipc_provider.FreeBuffer(raw_mem); \
+ return SBOX_ERROR_BAD_PARAMS; \
+ }
+
+#define XCALL_GEN_FREE_CHANNEL() ipc_provider.FreeBuffer(raw_mem);
+
+// CrossCall template with one input parameter
+template <typename IPCProvider, typename Par1>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ IpcTag tag,
+ const Par1& p1,
+ CrossCallReturn* answer) {
+ XCALL_GEN_PARAMS_OBJ(1, call_params);
+ XCALL_GEN_COPY_PARAM(1, call_params);
+
+ ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+ if (SBOX_ERROR_CHANNEL_ERROR != result) {
+ XCALL_GEN_UPDATE_PARAM(1, call_params);
+ XCALL_GEN_FREE_CHANNEL();
+ }
+
+ return result;
+}
+
+// CrossCall template with two input parameters.
+template <typename IPCProvider, typename Par1, typename Par2>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ IpcTag tag,
+ const Par1& p1,
+ const Par2& p2,
+ CrossCallReturn* answer) {
+ XCALL_GEN_PARAMS_OBJ(2, call_params);
+ XCALL_GEN_COPY_PARAM(1, call_params);
+ XCALL_GEN_COPY_PARAM(2, call_params);
+
+ ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+ if (SBOX_ERROR_CHANNEL_ERROR != result) {
+ XCALL_GEN_UPDATE_PARAM(1, call_params);
+ XCALL_GEN_UPDATE_PARAM(2, call_params);
+ XCALL_GEN_FREE_CHANNEL();
+ }
+ return result;
+}
+
+// CrossCall template with three input parameters.
+template <typename IPCProvider, typename Par1, typename Par2, typename Par3>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ IpcTag tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ CrossCallReturn* answer) {
+ XCALL_GEN_PARAMS_OBJ(3, call_params);
+ XCALL_GEN_COPY_PARAM(1, call_params);
+ XCALL_GEN_COPY_PARAM(2, call_params);
+ XCALL_GEN_COPY_PARAM(3, call_params);
+
+ ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+ if (SBOX_ERROR_CHANNEL_ERROR != result) {
+ XCALL_GEN_UPDATE_PARAM(1, call_params);
+ XCALL_GEN_UPDATE_PARAM(2, call_params);
+ XCALL_GEN_UPDATE_PARAM(3, call_params);
+ XCALL_GEN_FREE_CHANNEL();
+ }
+ return result;
+}
+
+// CrossCall template with four input parameters.
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
+ typename Par4>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ IpcTag tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
+ CrossCallReturn* answer) {
+ XCALL_GEN_PARAMS_OBJ(4, call_params);
+ XCALL_GEN_COPY_PARAM(1, call_params);
+ XCALL_GEN_COPY_PARAM(2, call_params);
+ XCALL_GEN_COPY_PARAM(3, call_params);
+ XCALL_GEN_COPY_PARAM(4, call_params);
+
+ ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+ if (SBOX_ERROR_CHANNEL_ERROR != result) {
+ XCALL_GEN_UPDATE_PARAM(1, call_params);
+ XCALL_GEN_UPDATE_PARAM(2, call_params);
+ XCALL_GEN_UPDATE_PARAM(3, call_params);
+ XCALL_GEN_UPDATE_PARAM(4, call_params);
+ XCALL_GEN_FREE_CHANNEL();
+ }
+ return result;
+}
+
+// CrossCall template with five input parameters.
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
+ typename Par4,
+ typename Par5>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ IpcTag tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
+ const Par5& p5,
+ CrossCallReturn* answer) {
+ XCALL_GEN_PARAMS_OBJ(5, call_params);
+ XCALL_GEN_COPY_PARAM(1, call_params);
+ XCALL_GEN_COPY_PARAM(2, call_params);
+ XCALL_GEN_COPY_PARAM(3, call_params);
+ XCALL_GEN_COPY_PARAM(4, call_params);
+ XCALL_GEN_COPY_PARAM(5, call_params);
+
+ ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+ if (SBOX_ERROR_CHANNEL_ERROR != result) {
+ XCALL_GEN_UPDATE_PARAM(1, call_params);
+ XCALL_GEN_UPDATE_PARAM(2, call_params);
+ XCALL_GEN_UPDATE_PARAM(3, call_params);
+ XCALL_GEN_UPDATE_PARAM(4, call_params);
+ XCALL_GEN_UPDATE_PARAM(5, call_params);
+ XCALL_GEN_FREE_CHANNEL();
+ }
+ return result;
+}
+
+// CrossCall template with six input parameters.
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
+ typename Par4,
+ typename Par5,
+ typename Par6>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ IpcTag tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
+ const Par5& p5,
+ const Par6& p6,
+ CrossCallReturn* answer) {
+ XCALL_GEN_PARAMS_OBJ(6, call_params);
+ XCALL_GEN_COPY_PARAM(1, call_params);
+ XCALL_GEN_COPY_PARAM(2, call_params);
+ XCALL_GEN_COPY_PARAM(3, call_params);
+ XCALL_GEN_COPY_PARAM(4, call_params);
+ XCALL_GEN_COPY_PARAM(5, call_params);
+ XCALL_GEN_COPY_PARAM(6, call_params);
+
+ ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+ if (SBOX_ERROR_CHANNEL_ERROR != result) {
+ XCALL_GEN_UPDATE_PARAM(1, call_params);
+ XCALL_GEN_UPDATE_PARAM(2, call_params);
+ XCALL_GEN_UPDATE_PARAM(3, call_params);
+ XCALL_GEN_UPDATE_PARAM(4, call_params);
+ XCALL_GEN_UPDATE_PARAM(5, call_params);
+ XCALL_GEN_UPDATE_PARAM(6, call_params);
+ XCALL_GEN_FREE_CHANNEL();
+ }
+ return result;
+}
+
+// CrossCall template with seven input parameters.
+template <typename IPCProvider,
+ typename Par1,
+ typename Par2,
+ typename Par3,
+ typename Par4,
+ typename Par5,
+ typename Par6,
+ typename Par7>
+ResultCode CrossCall(IPCProvider& ipc_provider,
+ IpcTag tag,
+ const Par1& p1,
+ const Par2& p2,
+ const Par3& p3,
+ const Par4& p4,
+ const Par5& p5,
+ const Par6& p6,
+ const Par7& p7,
+ CrossCallReturn* answer) {
+ XCALL_GEN_PARAMS_OBJ(7, call_params);
+ XCALL_GEN_COPY_PARAM(1, call_params);
+ XCALL_GEN_COPY_PARAM(2, call_params);
+ XCALL_GEN_COPY_PARAM(3, call_params);
+ XCALL_GEN_COPY_PARAM(4, call_params);
+ XCALL_GEN_COPY_PARAM(5, call_params);
+ XCALL_GEN_COPY_PARAM(6, call_params);
+ XCALL_GEN_COPY_PARAM(7, call_params);
+
+ ResultCode result = ipc_provider.DoCall(call_params, answer);
+
+ if (SBOX_ERROR_CHANNEL_ERROR != result) {
+ XCALL_GEN_UPDATE_PARAM(1, call_params);
+ XCALL_GEN_UPDATE_PARAM(2, call_params);
+ XCALL_GEN_UPDATE_PARAM(3, call_params);
+ XCALL_GEN_UPDATE_PARAM(4, call_params);
+ XCALL_GEN_UPDATE_PARAM(5, call_params);
+ XCALL_GEN_UPDATE_PARAM(6, call_params);
+ XCALL_GEN_UPDATE_PARAM(7, call_params);
+ XCALL_GEN_FREE_CHANNEL();
+ }
+ return result;
+}
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_CROSSCALL_CLIENT_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/crosscall_params.h b/security/sandbox/chromium/sandbox/win/src/crosscall_params.h
new file mode 100644
index 0000000000..6971b55cb7
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/crosscall_params.h
@@ -0,0 +1,315 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_CROSSCALL_PARAMS_H__
+#define SANDBOX_SRC_CROSSCALL_PARAMS_H__
+
+#if !defined(SANDBOX_FUZZ_TARGET)
+#include <windows.h>
+
+#include <lmaccess.h>
+#else
+#include "sandbox/win/fuzzer/fuzzer_types.h"
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/win/src/internal_types.h"
+#if !defined(SANDBOX_FUZZ_TARGET)
+#include "sandbox/win/src/sandbox_nt_types.h"
+#endif
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+// This header is part of CrossCall: the sandbox inter-process communication.
+// This header defines the basic types used both in the client IPC and in the
+// server IPC code. CrossCallParams and ActualCallParams model the input
+// parameters of an IPC call and CrossCallReturn models the output params and
+// the return value.
+//
+// An IPC call is defined by its 'tag' which is a (uint32_t) unique identifier
+// that is used to route the IPC call to the proper server. Every tag implies
+// a complete call signature including the order and type of each parameter.
+//
+// Like most IPC systems. CrossCall is designed to take as inputs 'simple'
+// types such as integers and strings. Classes, generic arrays or pointers to
+// them are not supported.
+//
+// Another limitation of CrossCall is that the return value and output
+// parameters can only be uint32_t integers. Returning complex structures or
+// strings is not supported.
+
+namespace sandbox {
+
+// this is the assumed channel size. This can be overridden in a given
+// IPC implementation.
+const uint32_t kIPCChannelSize = 1024;
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+namespace {
+
+// Increases |value| until there is no need for padding given an int64_t
+// alignment. Returns the increased value.
+inline uint32_t Align(uint32_t value) {
+ uint32_t alignment = sizeof(int64_t);
+ return ((value + alignment - 1) / alignment) * alignment;
+}
+
+inline void* memcpy_wrapper(void* dest, const void* src, size_t count) {
+ if (g_nt.memcpy)
+ return g_nt.memcpy(dest, src, count);
+ return memcpy(dest, src, count);
+}
+
+} // namespace
+
+// max number of extended return parameters. See CrossCallReturn
+const size_t kExtendedReturnCount = 8;
+
+// Union of multiple types to be used as extended results
+// in the CrossCallReturn.
+union MultiType {
+ uint32_t unsigned_int;
+ void* pointer;
+ HANDLE handle;
+ ULONG_PTR ulong_ptr;
+};
+
+// Maximum number of IPC parameters currently supported.
+// To increase this value, we have to:
+// - Add another Callback typedef to Dispatcher.
+// - Add another case to the switch on SharedMemIPCServer::InvokeCallback.
+// - Add another case to the switch in GetActualAndMaxBufferSize
+// - Add another case to the switch in GetMinDeclaredActualCallParamsSize
+const int kMaxIpcParams = 9;
+
+// Contains the information about a parameter in the ipc buffer.
+struct ParamInfo {
+ ArgType type_;
+ uint32_t offset_;
+ uint32_t size_;
+};
+
+// Models the return value and the return parameters of an IPC call
+// currently limited to one status code and eight generic return values
+// which cannot be pointers to other data. For x64 ports this structure
+// might have to use other integer types.
+struct CrossCallReturn {
+ // the IPC tag. It should match the original IPC tag.
+ uint32_t tag;
+ // The result of the IPC operation itself.
+ ResultCode call_outcome;
+ // the result of the IPC call as executed in the server. The interpretation
+ // of this value depends on the specific service.
+ union {
+ NTSTATUS nt_status;
+ DWORD win32_result;
+ };
+ // Number of extended return values.
+ uint32_t extended_count;
+ // for calls that should return a windows handle. It is found here.
+ HANDLE handle;
+ // The array of extended values.
+ MultiType extended[kExtendedReturnCount];
+};
+
+// CrossCallParams base class that models the input params all packed in a
+// single compact memory blob. The representation can vary but in general a
+// given child of this class is meant to represent all input parameters
+// necessary to make a IPC call.
+//
+// This class cannot have virtual members because its assumed the IPC
+// parameters start from the 'this' pointer to the end, which is defined by
+// one of the subclasses
+//
+// Objects of this class cannot be constructed directly. Only derived
+// classes have the proper knowledge to construct it.
+class CrossCallParams {
+ public:
+ // Returns the tag (ipc unique id) associated with this IPC.
+ IpcTag GetTag() const { return tag_; }
+
+ // Returns the beggining of the buffer where the IPC params can be stored.
+ // prior to an IPC call
+ const void* GetBuffer() const { return this; }
+
+ // Returns how many parameter this IPC call should have.
+ uint32_t GetParamsCount() const { return params_count_; }
+
+ // Returns a pointer to the CrossCallReturn structure.
+ CrossCallReturn* GetCallReturn() { return &call_return; }
+
+ // Returns true if this call contains InOut parameters.
+ bool IsInOut() const { return (1 == is_in_out_); }
+
+ // Tells the CrossCall object if it contains InOut parameters.
+ void SetIsInOut(bool value) {
+ if (value)
+ is_in_out_ = 1;
+ else
+ is_in_out_ = 0;
+ }
+
+ protected:
+ // constructs the IPC call params. Called only from the derived classes
+ CrossCallParams(IpcTag tag, uint32_t params_count)
+ : tag_(tag), is_in_out_(0), params_count_(params_count) {}
+
+ private:
+ IpcTag tag_;
+ uint32_t is_in_out_;
+ CrossCallReturn call_return;
+ const uint32_t params_count_;
+ DISALLOW_COPY_AND_ASSIGN(CrossCallParams);
+};
+
+// ActualCallParams models an specific IPC call parameters with respect to the
+// storage allocation that the packed parameters should need.
+// NUMBER_PARAMS: the number of parameters, valid from 1 to N
+// BLOCK_SIZE: the total storage that the NUMBER_PARAMS parameters can take,
+// typically the block size is defined by the channel size of the underlying
+// ipc mechanism.
+// In practice this class is used to levergage C++ capacity to properly
+// calculate sizes and displacements given the possibility of the packed params
+// blob to be complex.
+//
+// As is, this class assumes that the layout of the blob is as follows. Assume
+// that NUMBER_PARAMS = 2 and a 32-bit build:
+//
+// [ tag 4 bytes]
+// [ IsOnOut 4 bytes]
+// [ call return 52 bytes]
+// [ params count 4 bytes]
+// [ parameter 0 type 4 bytes]
+// [ parameter 0 offset 4 bytes] ---delta to ---\
+// [ parameter 0 size 4 bytes] |
+// [ parameter 1 type 4 bytes] |
+// [ parameter 1 offset 4 bytes] ---------------|--\
+// [ parameter 1 size 4 bytes] | |
+// [ parameter 2 type 4 bytes] | |
+// [ parameter 2 offset 4 bytes] ----------------------\
+// [ parameter 2 size 4 bytes] | | |
+// |---------------------------| | | |
+// | value 0 (x bytes) | <--------------/ | |
+// | value 1 (y bytes) | <-----------------/ |
+// | | |
+// | end of buffer | <---------------------/
+// |---------------------------|
+//
+// Note that the actual number of params is NUMBER_PARAMS + 1
+// so that the size of each actual param can be computed from the difference
+// between one parameter and the next down. The offset of the last param
+// points to the end of the buffer and the type and size are undefined.
+//
+template <size_t NUMBER_PARAMS, size_t BLOCK_SIZE>
+class ActualCallParams : public CrossCallParams {
+ public:
+ // constructor. Pass the ipc unique tag as input
+ explicit ActualCallParams(IpcTag tag) : CrossCallParams(tag, NUMBER_PARAMS) {
+ param_info_[0].offset_ =
+ static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
+ }
+
+ // Testing-only constructor. Allows setting the |number_params| to a
+ // wrong value.
+ ActualCallParams(IpcTag tag, uint32_t number_params)
+ : CrossCallParams(tag, number_params) {
+ param_info_[0].offset_ =
+ static_cast<uint32_t>(parameters_ - reinterpret_cast<char*>(this));
+ }
+
+ static constexpr size_t MaxParamsSize() {
+ return sizeof(
+ ActualCallParams<NUMBER_PARAMS, kIPCChannelSize>::parameters_);
+ }
+
+ // Testing-only method. Allows setting the apparent size to a wrong value.
+ // returns the previous size.
+ uint32_t OverrideSize(uint32_t new_size) {
+ uint32_t previous_size = param_info_[NUMBER_PARAMS].offset_;
+ param_info_[NUMBER_PARAMS].offset_ = new_size;
+ return previous_size;
+ }
+
+ // Copies each paramter into the internal buffer. For each you must supply:
+ // index: 0 for the first param, 1 for the next an so on
+ bool CopyParamIn(uint32_t index,
+ const void* parameter_address,
+ uint32_t size,
+ bool is_in_out,
+ ArgType type) {
+ if (index >= NUMBER_PARAMS) {
+ return false;
+ }
+
+ if (UINT32_MAX == size) {
+ // Memory error while getting the size.
+ return false;
+ }
+
+ if (size && !parameter_address) {
+ return false;
+ }
+
+ if ((size > sizeof(*this)) ||
+ (param_info_[index].offset_ > (sizeof(*this) - size))) {
+ // It does not fit, abort copy.
+ return false;
+ }
+
+ char* dest = reinterpret_cast<char*>(this) + param_info_[index].offset_;
+
+ // We might be touching user memory, this has to be done from inside a try
+ // except.
+ __try {
+ memcpy_wrapper(dest, parameter_address, size);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ return false;
+ }
+
+ // Set the flag to tell the broker to update the buffer once the call is
+ // made.
+ if (is_in_out)
+ SetIsInOut(true);
+
+ param_info_[index + 1].offset_ = Align(param_info_[index].offset_ + size);
+ param_info_[index].size_ = size;
+ param_info_[index].type_ = type;
+ return true;
+ }
+
+ // Returns a pointer to a parameter in the memory section.
+ void* GetParamPtr(size_t index) {
+ return reinterpret_cast<char*>(this) + param_info_[index].offset_;
+ }
+
+ // Returns the total size of the buffer. Only valid once all the paramters
+ // have been copied in with CopyParamIn.
+ uint32_t GetSize() const { return param_info_[NUMBER_PARAMS].offset_; }
+
+ protected:
+ ActualCallParams() : CrossCallParams(IpcTag::UNUSED, NUMBER_PARAMS) {}
+
+ private:
+ ParamInfo param_info_[NUMBER_PARAMS + 1];
+ char parameters_[BLOCK_SIZE - sizeof(CrossCallParams) -
+ sizeof(ParamInfo) * (NUMBER_PARAMS + 1)];
+ DISALLOW_COPY_AND_ASSIGN(ActualCallParams);
+
+ friend uint32_t GetMinDeclaredActualCallParamsSize(uint32_t param_count);
+};
+
+static_assert(sizeof(ActualCallParams<1, 1024>) == 1024, "bad size buffer");
+static_assert(sizeof(ActualCallParams<2, 1024>) == 1024, "bad size buffer");
+static_assert(sizeof(ActualCallParams<3, 1024>) == 1024, "bad size buffer");
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_CROSSCALL_PARAMS_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/crosscall_server.cc b/security/sandbox/chromium/sandbox/win/src/crosscall_server.cc
new file mode 100644
index 0000000000..27bfdfbd65
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/crosscall_server.cc
@@ -0,0 +1,345 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/crosscall_server.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <atomic>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/crosscall_params.h"
+
+// See comment in atomicops.h. This is needed any time windows.h is included
+// after atomicops.h.
+#undef MemoryBarrier
+
+// This code performs the ipc message validation. Potential security flaws
+// on the ipc are likelier to be found in this code than in the rest of
+// the ipc code.
+
+namespace {
+
+// The buffer for a message must match the max channel size.
+const size_t kMaxBufferSize = sandbox::kIPCChannelSize;
+
+} // namespace
+
+namespace sandbox {
+
+// The template types are used to calculate the maximum expected size.
+typedef ActualCallParams<0, kMaxBufferSize> ActualCP0;
+typedef ActualCallParams<1, kMaxBufferSize> ActualCP1;
+typedef ActualCallParams<2, kMaxBufferSize> ActualCP2;
+typedef ActualCallParams<3, kMaxBufferSize> ActualCP3;
+typedef ActualCallParams<4, kMaxBufferSize> ActualCP4;
+typedef ActualCallParams<5, kMaxBufferSize> ActualCP5;
+typedef ActualCallParams<6, kMaxBufferSize> ActualCP6;
+typedef ActualCallParams<7, kMaxBufferSize> ActualCP7;
+typedef ActualCallParams<8, kMaxBufferSize> ActualCP8;
+typedef ActualCallParams<9, kMaxBufferSize> ActualCP9;
+
+// Returns the actual size for the parameters in an IPC buffer. Returns
+// zero if the |param_count| is zero or too big.
+uint32_t GetActualBufferSize(uint32_t param_count, void* buffer_base) {
+ // Retrieve the actual size and the maximum size of the params buffer.
+ switch (param_count) {
+ case 0:
+ return 0;
+ case 1:
+ return reinterpret_cast<ActualCP1*>(buffer_base)->GetSize();
+ case 2:
+ return reinterpret_cast<ActualCP2*>(buffer_base)->GetSize();
+ case 3:
+ return reinterpret_cast<ActualCP3*>(buffer_base)->GetSize();
+ case 4:
+ return reinterpret_cast<ActualCP4*>(buffer_base)->GetSize();
+ case 5:
+ return reinterpret_cast<ActualCP5*>(buffer_base)->GetSize();
+ case 6:
+ return reinterpret_cast<ActualCP6*>(buffer_base)->GetSize();
+ case 7:
+ return reinterpret_cast<ActualCP7*>(buffer_base)->GetSize();
+ case 8:
+ return reinterpret_cast<ActualCP8*>(buffer_base)->GetSize();
+ case 9:
+ return reinterpret_cast<ActualCP9*>(buffer_base)->GetSize();
+ default:
+ return 0;
+ }
+}
+
+// Returns the minimum size for the parameters in an IPC buffer. Returns
+// zero if the |param_count| is less than zero or too big.
+uint32_t GetMinDeclaredActualCallParamsSize(uint32_t param_count) {
+ switch (param_count) {
+ case 0:
+ return offsetof(ActualCP0, parameters_);
+ case 1:
+ return offsetof(ActualCP1, parameters_);
+ case 2:
+ return offsetof(ActualCP2, parameters_);
+ case 3:
+ return offsetof(ActualCP3, parameters_);
+ case 4:
+ return offsetof(ActualCP4, parameters_);
+ case 5:
+ return offsetof(ActualCP5, parameters_);
+ case 6:
+ return offsetof(ActualCP6, parameters_);
+ case 7:
+ return offsetof(ActualCP7, parameters_);
+ case 8:
+ return offsetof(ActualCP8, parameters_);
+ case 9:
+ return offsetof(ActualCP9, parameters_);
+ default:
+ return 0;
+ }
+}
+
+// Verifies that the declared sizes of an IPC buffer are within range.
+bool IsSizeWithinRange(uint32_t buffer_size,
+ uint32_t min_declared_size,
+ uint32_t declared_size) {
+ if ((buffer_size < min_declared_size) ||
+ (sizeof(CrossCallParamsEx) > min_declared_size)) {
+ // Minimal computed size bigger than existing buffer or param_count
+ // integer overflow.
+ return false;
+ }
+
+ if ((declared_size > buffer_size) || (declared_size < min_declared_size)) {
+ // Declared size is bigger than buffer or smaller than computed size
+ // or param_count is equal to 0 or bigger than 9.
+ return false;
+ }
+
+ return true;
+}
+
+CrossCallParamsEx::CrossCallParamsEx() : CrossCallParams(IpcTag::UNUSED, 0) {}
+
+// We override the delete operator because the object's backing memory
+// is hand allocated in CreateFromBuffer. We don't override the new operator
+// because the constructors are private so there is no way to mismatch
+// new & delete.
+void CrossCallParamsEx::operator delete(void* raw_memory) throw() {
+ if (!raw_memory) {
+ // C++ standard allows 'delete 0' behavior.
+ return;
+ }
+ delete[] reinterpret_cast<char*>(raw_memory);
+}
+
+// This function uses a SEH try block so cannot use C++ objects that
+// have destructors or else you get Compiler Error C2712. So no DCHECKs
+// inside this function.
+CrossCallParamsEx* CrossCallParamsEx::CreateFromBuffer(void* buffer_base,
+ uint32_t buffer_size,
+ uint32_t* output_size) {
+ // IMPORTANT: Everything inside buffer_base and derived from it such
+ // as param_count and declared_size is untrusted.
+ if (!buffer_base)
+ return nullptr;
+ if (buffer_size < sizeof(CrossCallParams))
+ return nullptr;
+ if (buffer_size > kMaxBufferSize)
+ return nullptr;
+
+ char* backing_mem = nullptr;
+ uint32_t param_count = 0;
+ uint32_t declared_size;
+ uint32_t min_declared_size;
+ CrossCallParamsEx* copied_params = nullptr;
+
+ // Touching the untrusted buffer is done under a SEH try block. This
+ // will catch memory access violations so we don't crash.
+ __try {
+ CrossCallParams* call_params =
+ reinterpret_cast<CrossCallParams*>(buffer_base);
+
+ // Check against the minimum size given the number of stated params
+ // if too small we bail out.
+ param_count = call_params->GetParamsCount();
+ min_declared_size = GetMinDeclaredActualCallParamsSize(param_count);
+
+ // Initial check for the buffer being big enough to determine the actual
+ // buffer size.
+ if (buffer_size < min_declared_size)
+ return nullptr;
+
+ // Retrieve the declared size which if it fails returns 0.
+ declared_size = GetActualBufferSize(param_count, buffer_base);
+
+ if (!IsSizeWithinRange(buffer_size, min_declared_size, declared_size))
+ return nullptr;
+
+ // Now we copy the actual amount of the message.
+ *output_size = declared_size;
+ backing_mem = new char[declared_size];
+ copied_params = reinterpret_cast<CrossCallParamsEx*>(backing_mem);
+ memcpy(backing_mem, call_params, declared_size);
+
+ // Avoid compiler optimizations across this point. Any value stored in
+ // memory should be stored for real, and values previously read from memory
+ // should be actually read.
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+
+ min_declared_size = GetMinDeclaredActualCallParamsSize(param_count);
+
+ // Check that the copied buffer is still valid.
+ if (copied_params->GetParamsCount() != param_count ||
+ GetActualBufferSize(param_count, backing_mem) != declared_size ||
+ !IsSizeWithinRange(buffer_size, min_declared_size, declared_size)) {
+ delete[] backing_mem;
+ return nullptr;
+ }
+
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ // In case of a windows exception we know it occurred while touching the
+ // untrusted buffer so we bail out as is.
+ delete[] backing_mem;
+ return nullptr;
+ }
+
+ // Here and below we're making use of uintptr_t to have well-defined integer
+ // overflow when doing pointer arithmetic.
+ auto backing_mem_ptr = reinterpret_cast<uintptr_t>(backing_mem);
+ auto last_byte = reinterpret_cast<uintptr_t>(&backing_mem[declared_size]);
+ auto first_byte =
+ reinterpret_cast<uintptr_t>(&backing_mem[min_declared_size]);
+
+ // Verify here that all and each parameters make sense. This is done in the
+ // local copy.
+ for (uint32_t ix = 0; ix != param_count; ++ix) {
+ uint32_t size = 0;
+ ArgType type;
+ auto address = reinterpret_cast<uintptr_t>(
+ copied_params->GetRawParameter(ix, &size, &type));
+ if ((!address) || // No null params.
+ (INVALID_TYPE >= type) || (LAST_TYPE <= type) || // Unknown type.
+ (address < backing_mem_ptr) || // Start cannot point before buffer.
+ (address < first_byte) || // Start cannot point too low.
+ (address > last_byte) || // Start cannot point past buffer.
+ ((address + size) < address) || // Invalid size.
+ ((address + size) > last_byte)) { // End cannot point past buffer.
+ // Malformed.
+ delete[] backing_mem;
+ return nullptr;
+ }
+ }
+ // The parameter buffer looks good.
+ return copied_params;
+}
+
+// Accessors to the parameters in the raw buffer.
+void* CrossCallParamsEx::GetRawParameter(uint32_t index,
+ uint32_t* size,
+ ArgType* type) {
+ if (index >= GetParamsCount())
+ return nullptr;
+ // The size is always computed from the parameter minus the next
+ // parameter, this works because the message has an extra parameter slot
+ *size = param_info_[index].size_;
+ *type = param_info_[index].type_;
+
+ return param_info_[index].offset_ + reinterpret_cast<char*>(this);
+}
+
+// Covers common case for 32 bit integers.
+bool CrossCallParamsEx::GetParameter32(uint32_t index, uint32_t* param) {
+ uint32_t size = 0;
+ ArgType type;
+ void* start = GetRawParameter(index, &size, &type);
+ if (!start || (4 != size) || (UINT32_TYPE != type))
+ return false;
+ // Copy the 4 bytes.
+ *(reinterpret_cast<uint32_t*>(param)) = *(reinterpret_cast<uint32_t*>(start));
+ return true;
+}
+
+bool CrossCallParamsEx::GetParameterVoidPtr(uint32_t index, void** param) {
+ uint32_t size = 0;
+ ArgType type;
+ void* start = GetRawParameter(index, &size, &type);
+ if (!start || (sizeof(void*) != size) || (VOIDPTR_TYPE != type))
+ return false;
+ *param = *(reinterpret_cast<void**>(start));
+ return true;
+}
+
+// Covers the common case of reading a string. Note that the string is not
+// scanned for invalid characters.
+bool CrossCallParamsEx::GetParameterStr(uint32_t index, std::wstring* string) {
+ DCHECK(string->empty());
+ uint32_t size = 0;
+ ArgType type;
+ void* start = GetRawParameter(index, &size, &type);
+ if (WCHAR_TYPE != type)
+ return false;
+
+ // Check if this is an empty string.
+ if (size == 0) {
+ *string = std::wstring();
+ return true;
+ }
+
+ if (!start || ((size % sizeof(wchar_t)) != 0))
+ return false;
+
+ string->assign(reinterpret_cast<const wchar_t*>(start),
+ size / sizeof(wchar_t));
+ return true;
+}
+
+bool CrossCallParamsEx::GetParameterPtr(uint32_t index,
+ uint32_t expected_size,
+ void** pointer) {
+ uint32_t size = 0;
+ ArgType type;
+ void* start = GetRawParameter(index, &size, &type);
+
+ if ((size != expected_size) || (INOUTPTR_TYPE != type && INPTR_TYPE != type))
+ return false;
+
+ if (!start)
+ return false;
+
+ *pointer = start;
+ return true;
+}
+
+void SetCallError(ResultCode error, CrossCallReturn* call_return) {
+ call_return->call_outcome = error;
+ call_return->extended_count = 0;
+}
+
+void SetCallSuccess(CrossCallReturn* call_return) {
+ call_return->call_outcome = SBOX_ALL_OK;
+}
+
+Dispatcher* Dispatcher::OnMessageReady(IPCParams* ipc,
+ CallbackGeneric* callback) {
+ DCHECK(callback);
+ std::vector<IPCCall>::iterator it = ipc_calls_.begin();
+ for (; it != ipc_calls_.end(); ++it) {
+ if (it->params.Matches(ipc)) {
+ *callback = it->callback;
+ return this;
+ }
+ }
+ return nullptr;
+}
+
+Dispatcher::Dispatcher() {}
+
+Dispatcher::~Dispatcher() {}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/crosscall_server.h b/security/sandbox/chromium/sandbox/win/src/crosscall_server.h
new file mode 100644
index 0000000000..aed7f99aae
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/crosscall_server.h
@@ -0,0 +1,261 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_CROSSCALL_SERVER_H_
+#define SANDBOX_SRC_CROSSCALL_SERVER_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/ipc_tags.h"
+
+// This is the IPC server interface for CrossCall: The IPC for the Sandbox
+// On the server, CrossCall needs two things:
+// 1) threads: Or better said, someone to provide them, that is what the
+// ThreadProvider interface is defined for. These thread(s) are
+// the ones that will actually execute the IPC data retrieval.
+//
+// 2) a dispatcher: This interface represents the way to route and process
+// an IPC call given the IPC tag.
+//
+// The other class included here CrossCallParamsEx is the server side version
+// of the CrossCallParams class of /sandbox/crosscall_params.h The difference
+// is that the sever version is paranoid about the correctness of the IPC
+// message and will do all sorts of verifications.
+//
+// A general diagram of the interaction is as follows:
+//
+// ------------
+// | |
+// ThreadProvider <--(1)Register--| IPC |
+// | | Implemen |
+// | | -tation |
+// (2) | | OnMessage
+// IPC fired --callback ------>| |--(3)---> Dispatcher
+// | |
+// ------------
+//
+// The IPC implementation sits as a middleman between the handling of the
+// specifics of scheduling a thread to service the IPC and the multiple
+// entities that can potentially serve each particular IPC.
+namespace sandbox {
+
+class InterceptionManager;
+
+// This function signature is required as the callback when an IPC call fires.
+// context: a user-defined pointer that was set using ThreadProvider
+// reason: 0 if the callback was fired because of a timeout.
+// 1 if the callback was fired because of an event.
+typedef void(__stdcall* CrossCallIPCCallback)(void* context,
+ unsigned char reason);
+
+// ThreadProvider models a thread factory. The idea is to decouple thread
+// creation and lifetime from the inner guts of the IPC. The contract is
+// simple:
+// - the IPC implementation calls RegisterWait with a waitable object that
+// becomes signaled when an IPC arrives and needs to be serviced.
+// - when the waitable object becomes signaled, the thread provider conjures
+// a thread that calls the callback (CrossCallIPCCallback) function
+// - the callback function tries its best not to block and return quickly
+// and should not assume that the next callback will use the same thread
+// - when the callback returns the ThreadProvider owns again the thread
+// and can destroy it or keep it around.
+class ThreadProvider {
+ public:
+ // Registers a waitable object with the thread provider.
+ // client: A number to associate with all the RegisterWait calls, typically
+ // this is the address of the caller object. This parameter cannot
+ // be zero.
+ // waitable_object : a kernel object that can be waited on
+ // callback: a function pointer which is the function that will be called
+ // when the waitable object fires
+ // context: a user-provider pointer that is passed back to the callback
+ // when its called
+ virtual bool RegisterWait(const void* client,
+ HANDLE waitable_object,
+ CrossCallIPCCallback callback,
+ void* context) = 0;
+
+ // Removes all the registrations done with the same cookie parameter.
+ // This frees internal thread pool resources.
+ virtual bool UnRegisterWaits(void* cookie) = 0;
+ virtual ~ThreadProvider() {}
+};
+
+// Models the server-side of the original input parameters.
+// Provides IPC buffer validation and it is capable of reading the parameters
+// out of the IPC buffer.
+class CrossCallParamsEx : public CrossCallParams {
+ public:
+ // Factory constructor. Pass an IPCbuffer (and buffer size) that contains a
+ // pending IPCcall. This constructor will:
+ // 1) validate the IPC buffer. returns nullptr is the IPCbuffer is malformed.
+ // 2) make a copy of the IPCbuffer (parameter capture)
+ static CrossCallParamsEx* CreateFromBuffer(void* buffer_base,
+ uint32_t buffer_size,
+ uint32_t* output_size);
+
+ // Provides IPCinput parameter raw access:
+ // index : the parameter to read; 0 is the first parameter
+ // returns nullptr if the parameter is non-existent. If it exists it also
+ // returns the size in *size
+ void* GetRawParameter(uint32_t index, uint32_t* size, ArgType* type);
+
+ // Gets a parameter that is four bytes in size.
+ // Returns false if the parameter does not exist or is not 32 bits wide.
+ bool GetParameter32(uint32_t index, uint32_t* param);
+
+ // Gets a parameter that is void pointer in size.
+ // Returns false if the parameter does not exist or is not void pointer sized.
+ bool GetParameterVoidPtr(uint32_t index, void** param);
+
+ // Gets a parameter that is a string. Returns false if the parameter does not
+ // exist.
+ bool GetParameterStr(uint32_t index, std::wstring* string);
+
+ // Gets a parameter that is an in/out buffer. Returns false is the parameter
+ // does not exist or if the size of the actual parameter is not equal to the
+ // expected size.
+ bool GetParameterPtr(uint32_t index, uint32_t expected_size, void** pointer);
+
+ // Frees the memory associated with the IPC parameters.
+ static void operator delete(void* raw_memory) throw();
+
+ private:
+ // Only the factory method CreateFromBuffer can construct these objects.
+ CrossCallParamsEx();
+
+ ParamInfo param_info_[1];
+ DISALLOW_COPY_AND_ASSIGN(CrossCallParamsEx);
+};
+
+// Simple helper function that sets the members of CrossCallReturn
+// to the proper state to signal a basic error.
+void SetCallError(ResultCode error, CrossCallReturn* call_return);
+
+// Sets the internal status of call_return to signify the that IPC call
+// completed successfully.
+void SetCallSuccess(CrossCallReturn* call_return);
+
+// Represents the client process that initiated the IPC which boils down to the
+// process handle and the job object handle that contains the client process.
+struct ClientInfo {
+ HANDLE process;
+ DWORD process_id;
+};
+
+// All IPC-related information to be passed to the IPC handler.
+struct IPCInfo {
+ IpcTag ipc_tag;
+ const ClientInfo* client_info;
+ CrossCallReturn return_info;
+};
+
+// This structure identifies IPC signatures.
+struct IPCParams {
+ IpcTag ipc_tag;
+ ArgType args[kMaxIpcParams];
+
+ bool Matches(IPCParams* other) const {
+ return !memcmp(this, other, sizeof(*other));
+ }
+};
+
+// Models an entity that can process an IPC message or it can route to another
+// one that could handle it. When an IPC arrives the IPC implementation will:
+// 1) call OnMessageReady() with the tag of the pending IPC. If the dispatcher
+// returns nullptr it means that it cannot handle this IPC but if it returns
+// non-null, it must be the pointer to a dispatcher that can handle it.
+// 2) When the IPC finally obtains a valid Dispatcher the IPC
+// implementation creates a CrossCallParamsEx from the raw IPC buffer.
+// 3) It calls the returned callback, with the IPC info and arguments.
+class Dispatcher {
+ public:
+ // Called from the IPC implementation to handle a specific IPC message.
+ typedef bool (Dispatcher::*CallbackGeneric)();
+ typedef bool (Dispatcher::*Callback0)(IPCInfo* ipc);
+ typedef bool (Dispatcher::*Callback1)(IPCInfo* ipc, void* p1);
+ typedef bool (Dispatcher::*Callback2)(IPCInfo* ipc, void* p1, void* p2);
+ typedef bool (Dispatcher::*Callback3)(IPCInfo* ipc,
+ void* p1,
+ void* p2,
+ void* p3);
+ typedef bool (Dispatcher::*Callback4)(IPCInfo* ipc,
+ void* p1,
+ void* p2,
+ void* p3,
+ void* p4);
+ typedef bool (Dispatcher::*Callback5)(IPCInfo* ipc,
+ void* p1,
+ void* p2,
+ void* p3,
+ void* p4,
+ void* p5);
+ typedef bool (Dispatcher::*Callback6)(IPCInfo* ipc,
+ void* p1,
+ void* p2,
+ void* p3,
+ void* p4,
+ void* p5,
+ void* p6);
+ typedef bool (Dispatcher::*Callback7)(IPCInfo* ipc,
+ void* p1,
+ void* p2,
+ void* p3,
+ void* p4,
+ void* p5,
+ void* p6,
+ void* p7);
+ typedef bool (Dispatcher::*Callback8)(IPCInfo* ipc,
+ void* p1,
+ void* p2,
+ void* p3,
+ void* p4,
+ void* p5,
+ void* p6,
+ void* p7,
+ void* p8);
+ typedef bool (Dispatcher::*Callback9)(IPCInfo* ipc,
+ void* p1,
+ void* p2,
+ void* p3,
+ void* p4,
+ void* p5,
+ void* p6,
+ void* p7,
+ void* p8,
+ void* p9);
+
+ // Called from the IPC implementation when an IPC message is ready override
+ // on a derived class to handle a set of IPC messages. Return nullptr if your
+ // subclass does not handle the message or return the pointer to the subclass
+ // that can handle it.
+ virtual Dispatcher* OnMessageReady(IPCParams* ipc, CallbackGeneric* callback);
+
+ // Called when a target proces is created, to setup the interceptions related
+ // with the given service (IPC).
+ virtual bool SetupService(InterceptionManager* manager, IpcTag service) = 0;
+
+ Dispatcher();
+ virtual ~Dispatcher();
+
+ protected:
+ // Structure that defines an IPC Call with all the parameters and the handler.
+ struct IPCCall {
+ IPCParams params;
+ CallbackGeneric callback;
+ };
+
+ // List of IPC Calls supported by the class.
+ std::vector<IPCCall> ipc_calls_;
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_CROSSCALL_SERVER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/eat_resolver.cc b/security/sandbox/chromium/sandbox/win/src/eat_resolver.cc
new file mode 100644
index 0000000000..f9551ed4b2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/eat_resolver.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/eat_resolver.h"
+
+#include <stddef.h>
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+NTSTATUS EatResolverThunk::Setup(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) {
+ NTSTATUS ret =
+ Init(target_module, interceptor_module, target_name, interceptor_name,
+ interceptor_entry_point, thunk_storage, storage_bytes);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ if (!eat_entry_)
+ return STATUS_INVALID_PARAMETER;
+
+#if defined(_WIN64)
+ // We have two thunks, in order: the return path and the forward path.
+ if (!SetInternalThunk(thunk_storage, storage_bytes, nullptr, target_))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ size_t thunk_bytes = GetInternalThunkSize();
+ storage_bytes -= thunk_bytes;
+ thunk_storage = reinterpret_cast<char*>(thunk_storage) + thunk_bytes;
+#endif
+
+ if (!SetInternalThunk(thunk_storage, storage_bytes, target_, interceptor_))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ AutoProtectMemory memory;
+ ret = memory.ChangeProtection(eat_entry_, sizeof(DWORD), PAGE_READWRITE);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ // Perform the patch.
+ *eat_entry_ = static_cast<DWORD>(reinterpret_cast<uintptr_t>(thunk_storage)) -
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(target_module));
+
+ if (storage_used)
+ *storage_used = GetThunkSize();
+
+ return ret;
+}
+
+NTSTATUS EatResolverThunk::ResolveTarget(const void* module,
+ const char* function_name,
+ void** address) {
+ DCHECK_NT(address);
+ if (!module)
+ return STATUS_INVALID_PARAMETER;
+
+ base::win::PEImage pe(module);
+ if (!pe.VerifyMagic())
+ return STATUS_INVALID_IMAGE_FORMAT;
+
+ eat_entry_ = pe.GetExportEntry(function_name);
+
+ if (!eat_entry_)
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ *address = pe.RVAToAddr(*eat_entry_);
+
+ return STATUS_SUCCESS;
+}
+
+size_t EatResolverThunk::GetThunkSize() const {
+#if defined(_WIN64)
+ return GetInternalThunkSize() * 2;
+#else
+ return GetInternalThunkSize();
+#endif
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/eat_resolver.h b/security/sandbox/chromium/sandbox/win/src/eat_resolver.h
new file mode 100644
index 0000000000..cbc5516f8c
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/eat_resolver.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_EAT_RESOLVER_H__
+#define SANDBOX_SRC_EAT_RESOLVER_H__
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/resolver.h"
+
+namespace sandbox {
+
+// This is the concrete resolver used to perform exports table interceptions.
+class EatResolverThunk : public ResolverThunk {
+ public:
+ EatResolverThunk() : eat_entry_(nullptr) {}
+ ~EatResolverThunk() override {}
+
+ // Implementation of Resolver::Setup.
+ NTSTATUS Setup(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) override;
+
+ // Implementation of Resolver::ResolveTarget.
+ NTSTATUS ResolveTarget(const void* module,
+ const char* function_name,
+ void** address) override;
+
+ // Implementation of Resolver::GetThunkSize.
+ size_t GetThunkSize() const override;
+
+ private:
+ // The entry to patch.
+ DWORD* eat_entry_;
+
+ DISALLOW_COPY_AND_ASSIGN(EatResolverThunk);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_EAT_RESOLVER_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/file_policy_test.cc b/security/sandbox/chromium/sandbox/win/src/file_policy_test.cc
new file mode 100644
index 0000000000..4989ab308f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/file_policy_test.cc
@@ -0,0 +1,705 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <algorithm>
+#include <cctype>
+
+#include <windows.h>
+#include <winioctl.h>
+
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "sandbox/win/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define BINDNTDLL(name) \
+ name##Function name = reinterpret_cast<name##Function>( \
+ ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
+
+namespace sandbox {
+
+const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
+
+// Creates a file using different desired access. Returns if the call succeeded
+// or not. The first argument in argv is the filename. The second argument
+// determines the type of access and the dispositino of the file.
+SBOX_TESTS_COMMAND int File_Create(int argc, wchar_t** argv) {
+ if (argc != 2)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ std::wstring operation(argv[0]);
+
+ if (operation == L"Read") {
+ base::win::ScopedHandle file1(CreateFile(
+ argv[1], GENERIC_READ, kSharing, nullptr, OPEN_EXISTING, 0, nullptr));
+ base::win::ScopedHandle file2(CreateFile(
+ argv[1], FILE_EXECUTE, kSharing, nullptr, OPEN_EXISTING, 0, nullptr));
+
+ if (file1.IsValid() == file2.IsValid())
+ return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+ return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
+
+ } else if (operation == L"Write") {
+ base::win::ScopedHandle file1(CreateFile(
+ argv[1], GENERIC_ALL, kSharing, nullptr, OPEN_EXISTING, 0, nullptr));
+ base::win::ScopedHandle file2(
+ CreateFile(argv[1], GENERIC_READ | FILE_WRITE_DATA, kSharing, nullptr,
+ OPEN_EXISTING, 0, nullptr));
+
+ if (file1.IsValid() == file2.IsValid())
+ return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+ return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
+
+ } else if (operation == L"ReadCreate") {
+ base::win::ScopedHandle file2(CreateFile(argv[1], GENERIC_READ, kSharing,
+ nullptr, CREATE_NEW, 0, nullptr));
+ base::win::ScopedHandle file1(CreateFile(
+ argv[1], GENERIC_READ, kSharing, nullptr, CREATE_ALWAYS, 0, nullptr));
+
+ if (file1.IsValid() == file2.IsValid())
+ return file1.IsValid() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+ return file1.IsValid() ? SBOX_TEST_FIRST_ERROR : SBOX_TEST_SECOND_ERROR;
+ }
+
+ return SBOX_TEST_INVALID_PARAMETER;
+}
+
+SBOX_TESTS_COMMAND int File_Win32Create(int argc, wchar_t** argv) {
+ if (argc != 1) {
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ }
+
+ std::wstring full_path = MakePathToSys(argv[0], false);
+ if (full_path.empty()) {
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ }
+
+ HANDLE file =
+ ::CreateFileW(full_path.c_str(), GENERIC_READ, kSharing, nullptr,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+
+ if (INVALID_HANDLE_VALUE != file) {
+ ::CloseHandle(file);
+ return SBOX_TEST_SUCCEEDED;
+ } else {
+ if (ERROR_ACCESS_DENIED == ::GetLastError()) {
+ return SBOX_TEST_DENIED;
+ } else {
+ return SBOX_TEST_FAILED;
+ }
+ }
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Creates the file in parameter using the NtCreateFile api and returns if the
+// call succeeded or not.
+SBOX_TESTS_COMMAND int File_CreateSys32(int argc, wchar_t** argv) {
+ BINDNTDLL(NtCreateFile);
+ BINDNTDLL(RtlInitUnicodeString);
+ if (!NtCreateFile || !RtlInitUnicodeString)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ std::wstring file(argv[0]);
+ if (0 != _wcsnicmp(file.c_str(), kNTDevicePrefix, kNTDevicePrefixLen))
+ file = MakePathToSys(argv[0], true);
+
+ UNICODE_STRING object_name;
+ RtlInitUnicodeString(&object_name, file.c_str());
+
+ OBJECT_ATTRIBUTES obj_attributes = {};
+ InitializeObjectAttributes(&obj_attributes, &object_name,
+ OBJ_CASE_INSENSITIVE, nullptr, nullptr);
+
+ HANDLE handle;
+ IO_STATUS_BLOCK io_block = {};
+ NTSTATUS status =
+ NtCreateFile(&handle, FILE_READ_DATA, &obj_attributes, &io_block, nullptr,
+ 0, kSharing, FILE_OPEN, 0, nullptr, 0);
+ if (NT_SUCCESS(status)) {
+ ::CloseHandle(handle);
+ return SBOX_TEST_SUCCEEDED;
+ } else if (STATUS_ACCESS_DENIED == status) {
+ return SBOX_TEST_DENIED;
+ } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
+ return SBOX_TEST_NOT_FOUND;
+ }
+ return SBOX_TEST_FAILED;
+}
+
+// Opens the file in parameter using the NtOpenFile api and returns if the
+// call succeeded or not.
+SBOX_TESTS_COMMAND int File_OpenSys32(int argc, wchar_t** argv) {
+ BINDNTDLL(NtOpenFile);
+ BINDNTDLL(RtlInitUnicodeString);
+ if (!NtOpenFile || !RtlInitUnicodeString)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ std::wstring file = MakePathToSys(argv[0], true);
+ UNICODE_STRING object_name;
+ RtlInitUnicodeString(&object_name, file.c_str());
+
+ OBJECT_ATTRIBUTES obj_attributes = {};
+ InitializeObjectAttributes(&obj_attributes, &object_name,
+ OBJ_CASE_INSENSITIVE, nullptr, nullptr);
+
+ HANDLE handle;
+ IO_STATUS_BLOCK io_block = {};
+ NTSTATUS status = NtOpenFile(&handle, FILE_READ_DATA, &obj_attributes,
+ &io_block, kSharing, 0);
+ if (NT_SUCCESS(status)) {
+ ::CloseHandle(handle);
+ return SBOX_TEST_SUCCEEDED;
+ } else if (STATUS_ACCESS_DENIED == status) {
+ return SBOX_TEST_DENIED;
+ } else if (STATUS_OBJECT_NAME_NOT_FOUND == status) {
+ return SBOX_TEST_NOT_FOUND;
+ }
+ return SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int File_GetDiskSpace(int argc, wchar_t** argv) {
+ std::wstring sys_path = MakePathToSys(L"", false);
+ if (sys_path.empty()) {
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ }
+ ULARGE_INTEGER free_user = {};
+ ULARGE_INTEGER total = {};
+ ULARGE_INTEGER free_total = {};
+ if (::GetDiskFreeSpaceExW(sys_path.c_str(), &free_user, &total,
+ &free_total)) {
+ if ((total.QuadPart != 0) && (free_total.QuadPart != 0)) {
+ return SBOX_TEST_SUCCEEDED;
+ }
+ } else {
+ if (ERROR_ACCESS_DENIED == ::GetLastError()) {
+ return SBOX_TEST_DENIED;
+ } else {
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ }
+ }
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Move a file using the MoveFileEx api and returns if the call succeeded or
+// not.
+SBOX_TESTS_COMMAND int File_Rename(int argc, wchar_t** argv) {
+ if (argc != 2)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (::MoveFileEx(argv[0], argv[1], 0))
+ return SBOX_TEST_SUCCEEDED;
+
+ if (::GetLastError() != ERROR_ACCESS_DENIED)
+ return SBOX_TEST_FAILED;
+
+ return SBOX_TEST_DENIED;
+}
+
+// Query the attributes of file in parameter using the NtQueryAttributesFile api
+// and NtQueryFullAttributesFile and returns if the call succeeded or not. The
+// second argument in argv is "d" or "f" telling if we expect the attributes to
+// specify a file or a directory. The expected attribute has to match the real
+// attributes for the call to be successful.
+SBOX_TESTS_COMMAND int File_QueryAttributes(int argc, wchar_t** argv) {
+ BINDNTDLL(NtQueryAttributesFile);
+ BINDNTDLL(NtQueryFullAttributesFile);
+ BINDNTDLL(RtlInitUnicodeString);
+ if (!NtQueryAttributesFile || !NtQueryFullAttributesFile ||
+ !RtlInitUnicodeString)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (argc != 2)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ bool expect_directory = (L'd' == argv[1][0]);
+
+ UNICODE_STRING object_name;
+ std::wstring file = MakePathToSys(argv[0], true);
+ RtlInitUnicodeString(&object_name, file.c_str());
+
+ OBJECT_ATTRIBUTES obj_attributes = {};
+ InitializeObjectAttributes(&obj_attributes, &object_name,
+ OBJ_CASE_INSENSITIVE, nullptr, nullptr);
+
+ FILE_BASIC_INFORMATION info = {};
+ FILE_NETWORK_OPEN_INFORMATION full_info = {};
+ NTSTATUS status1 = NtQueryAttributesFile(&obj_attributes, &info);
+ NTSTATUS status2 = NtQueryFullAttributesFile(&obj_attributes, &full_info);
+
+ if (status1 != status2)
+ return SBOX_TEST_FAILED;
+
+ if (NT_SUCCESS(status1)) {
+ if (info.FileAttributes != full_info.FileAttributes)
+ return SBOX_TEST_FAILED;
+
+ bool is_directory1 = (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ if (expect_directory == is_directory1)
+ return SBOX_TEST_SUCCEEDED;
+ } else if (STATUS_ACCESS_DENIED == status1) {
+ return SBOX_TEST_DENIED;
+ } else if (STATUS_OBJECT_NAME_NOT_FOUND == status1) {
+ return SBOX_TEST_NOT_FOUND;
+ }
+
+ return SBOX_TEST_FAILED;
+}
+
+// Tries to create a backup of calc.exe in system32 folder. This should fail
+// with ERROR_ACCESS_DENIED if everything is working as expected.
+SBOX_TESTS_COMMAND int File_CopyFile(int argc, wchar_t** argv) {
+ std::wstring calc_path = MakePathToSys(L"calc.exe", false);
+ std::wstring calc_backup_path = MakePathToSys(L"calc.exe.bak", false);
+
+ if (::CopyFile(calc_path.c_str(), calc_backup_path.c_str(), FALSE))
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (::GetLastError() != ERROR_ACCESS_DENIED)
+ return SBOX_TEST_FAILED;
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(FilePolicyTest, DenyNtCreateCalc) {
+ TestRunner runner;
+ EXPECT_TRUE(
+ runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L"calc.exe"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+}
+
+TEST(FilePolicyTest, AllowNtCreateCalc) {
+ TestRunner runner;
+ EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"calc.exe"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CreateSys32 calc.exe"));
+}
+
+TEST(FilePolicyTest, AllowNtCreateWithNativePath) {
+ std::wstring calc = MakePathToSys(L"calc.exe", false);
+ std::wstring nt_path;
+ ASSERT_TRUE(GetNtPathFromWin32Path(calc, &nt_path));
+ TestRunner runner;
+ runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, nt_path.c_str());
+
+ wchar_t buff[MAX_PATH];
+ ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str());
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff));
+
+ for (wchar_t& c : nt_path)
+ c = std::tolower(c);
+ ::wsprintfW(buff, L"File_CreateSys32 %s", nt_path.c_str());
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(buff));
+}
+
+TEST(FilePolicyTest, AllowReadOnly) {
+ TestRunner runner;
+
+ // Create a temp file because we need write access to it.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t temp_file_name[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+ EXPECT_TRUE(
+ runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, temp_file_name));
+
+ wchar_t command_read[MAX_PATH + 20] = {};
+ wsprintf(command_read, L"File_Create Read \"%ls\"", temp_file_name);
+ wchar_t command_read_create[MAX_PATH + 20] = {};
+ wsprintf(command_read_create, L"File_Create ReadCreate \"%ls\"",
+ temp_file_name);
+ wchar_t command_write[MAX_PATH + 20] = {};
+ wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
+
+ // Verify that we cannot create the file after revert.
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_read_create));
+
+ // Verify that we don't have write access after revert.
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write));
+
+ // Verify that we have read access after revert.
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_read));
+
+ // Verify that we really have write access to the file.
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write));
+
+ DeleteFile(temp_file_name);
+}
+
+// Tests support of "\\\\.\\DeviceName" kind of paths.
+TEST(FilePolicyTest, AllowImplicitDeviceName) {
+ TestRunner runner;
+
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t temp_file_name[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+ std::wstring path(temp_file_name);
+ EXPECT_TRUE(ConvertToLongPath(&path));
+ EXPECT_TRUE(GetNtPathFromWin32Path(path, &path));
+ path = path.substr(sandbox::kNTDevicePrefixLen);
+
+ wchar_t command[MAX_PATH + 20] = {};
+ wsprintf(command, L"File_Create Read \"\\\\.\\%ls\"", path.c_str());
+ path = std::wstring(kNTPrefix) + path;
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+ EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, path.c_str()));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
+
+ DeleteFile(temp_file_name);
+}
+
+TEST(FilePolicyTest, AllowWildcard) {
+ TestRunner runner;
+
+ // Create a temp file because we need write access to it.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t temp_file_name[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+ wcscat_s(temp_directory, MAX_PATH, L"*");
+ EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_directory));
+
+ wchar_t command_write[MAX_PATH + 20] = {};
+ wsprintf(command_write, L"File_Create Write \"%ls\"", temp_file_name);
+
+ // Verify that we have write access after revert.
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write));
+
+ DeleteFile(temp_file_name);
+}
+
+TEST(FilePolicyTest, AllowNtCreatePatternRule) {
+ TestRunner runner;
+ EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"App*.dll"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_OpenSys32 apphelp.dll"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_OpenSys32 appwiz.cpl"));
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_OpenSys32 apphelp.dll"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_OpenSys32 appwiz.cpl"));
+}
+
+TEST(FilePolicyTest, CheckNotFound) {
+ TestRunner runner;
+ EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"n*.dll"));
+
+ EXPECT_EQ(SBOX_TEST_NOT_FOUND,
+ runner.RunTest(L"File_OpenSys32 notfound.dll"));
+}
+
+TEST(FilePolicyTest, CheckNoLeak) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_CreateSys32 notfound.exe"));
+}
+
+TEST(FilePolicyTest, TestQueryAttributesFile) {
+ TestRunner runner;
+ EXPECT_TRUE(
+ runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"apphelp.dll"));
+ EXPECT_TRUE(
+ runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"notfound.exe"));
+ EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"drivers"));
+ EXPECT_TRUE(
+ runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_QUERY, L"ipconfig.exe"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_QueryAttributes drivers d"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_QueryAttributes apphelp.dll f"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_QueryAttributes ipconfig.exe f"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"File_QueryAttributes ftp.exe f"));
+
+ EXPECT_EQ(SBOX_TEST_NOT_FOUND,
+ runner.RunTest(L"File_QueryAttributes notfound.exe f"));
+}
+
+// Makes sure that we don't leak information when there is not policy to allow
+// a path.
+TEST(FilePolicyTest, TestQueryAttributesFileNoPolicy) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"File_QueryAttributes ftp.exe f"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"File_QueryAttributes notfound.exe f"));
+}
+
+TEST(FilePolicyTest, TestRename) {
+ TestRunner runner;
+
+ // Give access to the temp directory.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t temp_file_name1[MAX_PATH];
+ wchar_t temp_file_name2[MAX_PATH];
+ wchar_t temp_file_name3[MAX_PATH];
+ wchar_t temp_file_name4[MAX_PATH];
+ wchar_t temp_file_name5[MAX_PATH];
+ wchar_t temp_file_name6[MAX_PATH];
+ wchar_t temp_file_name7[MAX_PATH];
+ wchar_t temp_file_name8[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name1), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name2), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name3), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name4), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name5), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name6), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name7), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name8), 0u);
+
+ // Add rules to make file1->file2 succeed.
+ ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name1));
+ ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name2));
+
+ // Add rules to make file3->file4 fail.
+ ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name3));
+ ASSERT_TRUE(
+ runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, temp_file_name4));
+
+ // Add rules to make file5->file6 fail.
+ ASSERT_TRUE(
+ runner.AddFsRule(TargetPolicy::FILES_ALLOW_READONLY, temp_file_name5));
+ ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name6));
+
+ // Add rules to make file7->no_pol_file fail.
+ ASSERT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY, temp_file_name7));
+
+ // Delete the files where the files are going to be renamed to.
+ ::DeleteFile(temp_file_name2);
+ ::DeleteFile(temp_file_name4);
+ ::DeleteFile(temp_file_name6);
+ ::DeleteFile(temp_file_name8);
+
+ wchar_t command[MAX_PATH * 2 + 20] = {};
+ wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name1,
+ temp_file_name2);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command));
+
+ wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name3,
+ temp_file_name4);
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+
+ wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name5,
+ temp_file_name6);
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+
+ wsprintf(command, L"File_Rename \"%ls\" \"%ls\"", temp_file_name7,
+ temp_file_name8);
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command));
+
+ // Delete all the files in case they are still there.
+ ::DeleteFile(temp_file_name1);
+ ::DeleteFile(temp_file_name2);
+ ::DeleteFile(temp_file_name3);
+ ::DeleteFile(temp_file_name4);
+ ::DeleteFile(temp_file_name5);
+ ::DeleteFile(temp_file_name6);
+ ::DeleteFile(temp_file_name7);
+ ::DeleteFile(temp_file_name8);
+}
+
+TEST(FilePolicyTest, OpenSys32FilesDenyBecauseOfDir) {
+ TestRunner runner;
+ EXPECT_TRUE(
+ runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L"notepad.exe"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe"));
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_Win32Create notepad.exe"));
+}
+
+TEST(FilePolicyTest, OpenSys32FilesAllowNotepad) {
+ TestRunner runner;
+ EXPECT_TRUE(
+ runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_ANY, L"notepad.exe"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_Win32Create notepad.exe"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create calc.exe"));
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"File_Win32Create notepad.exe"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_Win32Create calc.exe"));
+}
+
+TEST(FilePolicyTest, FileGetDiskSpace) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_GetDiskSpace"));
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
+
+ // Add an 'allow' rule in the windows\system32 such that GetDiskFreeSpaceEx
+ // succeeds (it does an NtOpenFile) but windows\system32\notepad.exe is
+ // denied since there is no wild card in the rule.
+ EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L""));
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
+
+ runner.SetTestState(AFTER_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_GetDiskSpace"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"File_Win32Create notepad.exe"));
+}
+
+TEST(FilePolicyTest, TestReparsePoint) {
+ TestRunner runner;
+
+ // Create a temp file because we need write access to it.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t temp_file_name[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, temp_file_name), 0u);
+
+ // Delete the file and create a directory instead.
+ ASSERT_TRUE(::DeleteFile(temp_file_name));
+ ASSERT_TRUE(::CreateDirectory(temp_file_name, nullptr));
+
+ // Create a temporary file in the subfolder.
+ std::wstring subfolder = temp_file_name;
+ std::wstring temp_file_title = subfolder.substr(subfolder.rfind(L"\\") + 1);
+ std::wstring temp_file = subfolder + L"\\file_" + temp_file_title;
+
+ HANDLE file = ::CreateFile(temp_file.c_str(), FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+ CREATE_ALWAYS, 0, nullptr);
+ ASSERT_TRUE(INVALID_HANDLE_VALUE != file);
+ ASSERT_TRUE(::CloseHandle(file));
+
+ // Create a temporary file in the temp directory.
+ std::wstring temp_dir = temp_directory;
+ std::wstring temp_file_in_temp = temp_dir + L"file_" + temp_file_title;
+ file = ::CreateFile(temp_file_in_temp.c_str(), FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+ CREATE_ALWAYS, 0, nullptr);
+ ASSERT_TRUE(INVALID_HANDLE_VALUE != file);
+ ASSERT_TRUE(::CloseHandle(file));
+
+ // Give write access to the temp directory.
+ std::wstring temp_dir_wildcard = temp_dir + L"*";
+ EXPECT_TRUE(runner.AddFsRule(TargetPolicy::FILES_ALLOW_ANY,
+ temp_dir_wildcard.c_str()));
+
+ // Prepare the command to execute.
+ std::wstring command_write;
+ command_write += L"File_Create Write \"";
+ command_write += temp_file;
+ command_write += L"\"";
+
+ // Verify that we have write access to the original file
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command_write.c_str()));
+
+ // Replace the subfolder by a reparse point to %temp%.
+ ::DeleteFile(temp_file.c_str());
+ HANDLE dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ EXPECT_TRUE(INVALID_HANDLE_VALUE != dir);
+
+ std::wstring temp_dir_nt;
+ temp_dir_nt += L"\\??\\";
+ temp_dir_nt += temp_dir;
+ EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str()));
+ EXPECT_TRUE(::CloseHandle(dir));
+
+ // Try to open the file again.
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(command_write.c_str()));
+
+ // Remove the reparse point.
+ dir = ::CreateFile(subfolder.c_str(), FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ nullptr);
+ EXPECT_TRUE(INVALID_HANDLE_VALUE != dir);
+ EXPECT_TRUE(DeleteReparsePoint(dir));
+ EXPECT_TRUE(::CloseHandle(dir));
+
+ // Cleanup.
+ EXPECT_TRUE(::DeleteFile(temp_file_in_temp.c_str()));
+ EXPECT_TRUE(::RemoveDirectory(subfolder.c_str()));
+}
+
+TEST(FilePolicyTest, CheckExistingNTPrefixEscape) {
+ std::wstring name = L"\\??\\NAME";
+
+ std::wstring result = FixNTPrefixForMatch(name);
+
+ EXPECT_STREQ(result.c_str(), L"\\/?/?\\NAME");
+}
+
+TEST(FilePolicyTest, CheckEscapedNTPrefixNoEscape) {
+ std::wstring name = L"\\/?/?\\NAME";
+
+ std::wstring result = FixNTPrefixForMatch(name);
+
+ EXPECT_STREQ(result.c_str(), name.c_str());
+}
+
+TEST(FilePolicyTest, CheckMissingNTPrefixEscape) {
+ std::wstring name = L"C:\\NAME";
+
+ std::wstring result = FixNTPrefixForMatch(name);
+
+ EXPECT_STREQ(result.c_str(), L"\\/?/?\\C:\\NAME");
+}
+
+TEST(FilePolicyTest, TestCopyFile) {
+ // Check if the test is running Win8 or newer since
+ // MITIGATION_STRICT_HANDLE_CHECKS is not supported on older systems.
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return;
+
+ TestRunner runner;
+ runner.SetTimeout(2000);
+
+ // Allow read access to calc.exe, this should be on all Windows versions.
+ ASSERT_TRUE(
+ runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_READONLY, L"calc.exe"));
+
+ sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+ // Set proper mitigation.
+ EXPECT_EQ(
+ policy->SetDelayedProcessMitigations(MITIGATION_STRICT_HANDLE_CHECKS),
+ SBOX_ALL_OK);
+
+ ASSERT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"File_CopyFile"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
new file mode 100644
index 0000000000..c0f1de07fb
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
@@ -0,0 +1,302 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/filesystem_dispatcher.h"
+
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/filesystem_interception.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+FilesystemDispatcher::FilesystemDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall create_params = {
+ {IpcTag::NTCREATEFILE,
+ {WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE,
+ UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&FilesystemDispatcher::NtCreateFile)};
+
+ static const IPCCall open_file = {
+ {IpcTag::NTOPENFILE,
+ {WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&FilesystemDispatcher::NtOpenFile)};
+
+ static const IPCCall attribs = {
+ {IpcTag::NTQUERYATTRIBUTESFILE, {WCHAR_TYPE, UINT32_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &FilesystemDispatcher::NtQueryAttributesFile)};
+
+ static const IPCCall full_attribs = {
+ {IpcTag::NTQUERYFULLATTRIBUTESFILE,
+ {WCHAR_TYPE, UINT32_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &FilesystemDispatcher::NtQueryFullAttributesFile)};
+
+ static const IPCCall set_info = {
+ {IpcTag::NTSETINFO_RENAME,
+ {VOIDPTR_TYPE, INOUTPTR_TYPE, INOUTPTR_TYPE, UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &FilesystemDispatcher::NtSetInformationFile)};
+
+ ipc_calls_.push_back(create_params);
+ ipc_calls_.push_back(open_file);
+ ipc_calls_.push_back(attribs);
+ ipc_calls_.push_back(full_attribs);
+ ipc_calls_.push_back(set_info);
+}
+
+bool FilesystemDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ switch (service) {
+ case IpcTag::NTCREATEFILE:
+ return INTERCEPT_NT(manager, NtCreateFile, CREATE_FILE_ID, 48);
+
+ case IpcTag::NTOPENFILE:
+ return INTERCEPT_NT(manager, NtOpenFile, OPEN_FILE_ID, 28);
+
+ case IpcTag::NTQUERYATTRIBUTESFILE:
+ return INTERCEPT_NT(manager, NtQueryAttributesFile, QUERY_ATTRIB_FILE_ID,
+ 12);
+
+ case IpcTag::NTQUERYFULLATTRIBUTESFILE:
+ return INTERCEPT_NT(manager, NtQueryFullAttributesFile,
+ QUERY_FULL_ATTRIB_FILE_ID, 12);
+
+ case IpcTag::NTSETINFO_RENAME:
+ return INTERCEPT_NT(manager, NtSetInformationFile, SET_INFO_FILE_ID, 24);
+
+ default:
+ return false;
+ }
+}
+
+bool FilesystemDispatcher::NtCreateFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options) {
+ if (!PreProcessName(name)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ const wchar_t* filename = name->c_str();
+
+ uint32_t broker = BROKER_TRUE;
+ CountedParameterSet<OpenFile> params;
+ params[OpenFile::NAME] = ParamPickerMake(filename);
+ params[OpenFile::ACCESS] = ParamPickerMake(desired_access);
+ params[OpenFile::DISPOSITION] = ParamPickerMake(create_disposition);
+ params[OpenFile::OPTIONS] = ParamPickerMake(create_options);
+ params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+ // To evaluate the policy we need to call back to the policy object. We
+ // are just middlemen in the operation since is the FileSystemPolicy which
+ // knows what to do.
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::NTCREATEFILE, params.GetBase());
+ HANDLE handle;
+ ULONG_PTR io_information = 0;
+ NTSTATUS nt_status;
+ if (!FileSystemPolicy::CreateFileAction(
+ result, *ipc->client_info, *name, attributes, desired_access,
+ file_attributes, share_access, create_disposition, create_options,
+ &handle, &nt_status, &io_information)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ // Return operation status on the IPC.
+ ipc->return_info.extended[0].ulong_ptr = io_information;
+ ipc->return_info.nt_status = nt_status;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool FilesystemDispatcher::NtOpenFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t share_access,
+ uint32_t open_options) {
+ if (!PreProcessName(name)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ const wchar_t* filename = name->c_str();
+
+ uint32_t broker = BROKER_TRUE;
+ uint32_t create_disposition = FILE_OPEN;
+ CountedParameterSet<OpenFile> params;
+ params[OpenFile::NAME] = ParamPickerMake(filename);
+ params[OpenFile::ACCESS] = ParamPickerMake(desired_access);
+ params[OpenFile::DISPOSITION] = ParamPickerMake(create_disposition);
+ params[OpenFile::OPTIONS] = ParamPickerMake(open_options);
+ params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+ // To evaluate the policy we need to call back to the policy object. We
+ // are just middlemen in the operation since is the FileSystemPolicy which
+ // knows what to do.
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::NTOPENFILE, params.GetBase());
+ HANDLE handle;
+ ULONG_PTR io_information = 0;
+ NTSTATUS nt_status;
+ if (!FileSystemPolicy::OpenFileAction(
+ result, *ipc->client_info, *name, attributes, desired_access,
+ share_access, open_options, &handle, &nt_status, &io_information)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ // Return operation status on the IPC.
+ ipc->return_info.extended[0].ulong_ptr = io_information;
+ ipc->return_info.nt_status = nt_status;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool FilesystemDispatcher::NtQueryAttributesFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ CountedBuffer* info) {
+ if (sizeof(FILE_BASIC_INFORMATION) != info->Size())
+ return false;
+
+ if (!PreProcessName(name)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ uint32_t broker = BROKER_TRUE;
+ const wchar_t* filename = name->c_str();
+ CountedParameterSet<FileName> params;
+ params[FileName::NAME] = ParamPickerMake(filename);
+ params[FileName::BROKER] = ParamPickerMake(broker);
+
+ // To evaluate the policy we need to call back to the policy object. We
+ // are just middlemen in the operation since is the FileSystemPolicy which
+ // knows what to do.
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::NTQUERYATTRIBUTESFILE, params.GetBase());
+
+ FILE_BASIC_INFORMATION* information =
+ reinterpret_cast<FILE_BASIC_INFORMATION*>(info->Buffer());
+ NTSTATUS nt_status;
+ if (!FileSystemPolicy::QueryAttributesFileAction(result, *ipc->client_info,
+ *name, attributes,
+ information, &nt_status)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ // Return operation status on the IPC.
+ ipc->return_info.nt_status = nt_status;
+ return true;
+}
+
+bool FilesystemDispatcher::NtQueryFullAttributesFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ CountedBuffer* info) {
+ if (sizeof(FILE_NETWORK_OPEN_INFORMATION) != info->Size())
+ return false;
+
+ if (!PreProcessName(name)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ uint32_t broker = BROKER_TRUE;
+ const wchar_t* filename = name->c_str();
+ CountedParameterSet<FileName> params;
+ params[FileName::NAME] = ParamPickerMake(filename);
+ params[FileName::BROKER] = ParamPickerMake(broker);
+
+ // To evaluate the policy we need to call back to the policy object. We
+ // are just middlemen in the operation since is the FileSystemPolicy which
+ // knows what to do.
+ EvalResult result = policy_base_->EvalPolicy(
+ IpcTag::NTQUERYFULLATTRIBUTESFILE, params.GetBase());
+
+ FILE_NETWORK_OPEN_INFORMATION* information =
+ reinterpret_cast<FILE_NETWORK_OPEN_INFORMATION*>(info->Buffer());
+ NTSTATUS nt_status;
+ if (!FileSystemPolicy::QueryFullAttributesFileAction(
+ result, *ipc->client_info, *name, attributes, information,
+ &nt_status)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ // Return operation status on the IPC.
+ ipc->return_info.nt_status = nt_status;
+ return true;
+}
+
+bool FilesystemDispatcher::NtSetInformationFile(IPCInfo* ipc,
+ HANDLE handle,
+ CountedBuffer* status,
+ CountedBuffer* info,
+ uint32_t length,
+ uint32_t info_class) {
+ if (sizeof(IO_STATUS_BLOCK) != status->Size())
+ return false;
+ if (length != info->Size())
+ return false;
+
+ FILE_RENAME_INFORMATION* rename_info =
+ reinterpret_cast<FILE_RENAME_INFORMATION*>(info->Buffer());
+
+ if (!IsSupportedRenameCall(rename_info, length, info_class))
+ return false;
+
+ std::wstring name;
+ name.assign(rename_info->FileName,
+ rename_info->FileNameLength / sizeof(rename_info->FileName[0]));
+ if (!PreProcessName(&name)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ uint32_t broker = BROKER_TRUE;
+ const wchar_t* filename = name.c_str();
+ CountedParameterSet<FileName> params;
+ params[FileName::NAME] = ParamPickerMake(filename);
+ params[FileName::BROKER] = ParamPickerMake(broker);
+
+ // To evaluate the policy we need to call back to the policy object. We
+ // are just middlemen in the operation since is the FileSystemPolicy which
+ // knows what to do.
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::NTSETINFO_RENAME, params.GetBase());
+
+ IO_STATUS_BLOCK* io_status =
+ reinterpret_cast<IO_STATUS_BLOCK*>(status->Buffer());
+ NTSTATUS nt_status;
+ if (!FileSystemPolicy::SetInformationFileAction(
+ result, *ipc->client_info, handle, rename_info, length, info_class,
+ io_status, &nt_status)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ // Return operation status on the IPC.
+ ipc->return_info.nt_status = nt_status;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.h
new file mode 100644
index 0000000000..5551656e62
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_FILESYSTEM_DISPATCHER_H__
+#define SANDBOX_SRC_FILESYSTEM_DISPATCHER_H__
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles file system-related IPC calls.
+class FilesystemDispatcher : public Dispatcher {
+ public:
+ explicit FilesystemDispatcher(PolicyBase* policy_base);
+ ~FilesystemDispatcher() override {}
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to NtCreateFile in the target.
+ bool NtCreateFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options);
+
+ // Processes IPC requests coming from calls to NtOpenFile in the target.
+ bool NtOpenFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t share_access,
+ uint32_t create_options);
+
+ // Processes IPC requests coming from calls to NtQueryAttributesFile in the
+ // target.
+ bool NtQueryAttributesFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ CountedBuffer* info);
+
+ // Processes IPC requests coming from calls to NtQueryFullAttributesFile in
+ // the target.
+ bool NtQueryFullAttributesFile(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ CountedBuffer* info);
+
+ // Processes IPC requests coming from calls to NtSetInformationFile with the
+ // rename information class.
+ bool NtSetInformationFile(IPCInfo* ipc,
+ HANDLE handle,
+ CountedBuffer* status,
+ CountedBuffer* info,
+ uint32_t length,
+ uint32_t info_class);
+
+ PolicyBase* policy_base_;
+ DISALLOW_COPY_AND_ASSIGN(FilesystemDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_FILESYSTEM_DISPATCHER_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
new file mode 100644
index 0000000000..200dd1f63d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
@@ -0,0 +1,412 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/filesystem_interception.h"
+
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+
+// This status occurs when trying to access a network share on the machine from
+// which it is shared.
+#define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS)0xC0000201L)
+
+namespace sandbox {
+
+NTSTATUS WINAPI TargetNtCreateFile(NtCreateFileFunction orig_CreateFile,
+ PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ PLARGE_INTEGER allocation_size,
+ ULONG file_attributes,
+ ULONG sharing,
+ ULONG disposition,
+ ULONG options,
+ PVOID ea_buffer,
+ ULONG ea_length) {
+ // Check if the process can open it first.
+ NTSTATUS status = orig_CreateFile(
+ file, desired_access, object_attributes, io_status, allocation_size,
+ file_attributes, sharing, disposition, options, ea_buffer, ea_length);
+ if (STATUS_ACCESS_DENIED != status &&
+ STATUS_NETWORK_OPEN_RESTRICTION != status)
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtCreateFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(file, sizeof(HANDLE), WRITE))
+ break;
+ if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes = 0;
+ NTSTATUS ret =
+ AllocAndCopyName(object_attributes, &name, &attributes, nullptr);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ uint32_t desired_access_uint32 = desired_access;
+ uint32_t options_uint32 = options;
+ uint32_t disposition_uint32 = disposition;
+ uint32_t broker = BROKER_FALSE;
+ CountedParameterSet<OpenFile> params;
+ const wchar_t* name_ptr = name.get();
+ params[OpenFile::NAME] = ParamPickerMake(name_ptr);
+ params[OpenFile::ACCESS] = ParamPickerMake(desired_access_uint32);
+ params[OpenFile::DISPOSITION] = ParamPickerMake(disposition_uint32);
+ params[OpenFile::OPTIONS] = ParamPickerMake(options_uint32);
+ params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+ if (!QueryBroker(IpcTag::NTCREATEFILE, params.GetBase()))
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ // The following call must match in the parameters with
+ // FilesystemDispatcher::ProcessNtCreateFile.
+ ResultCode code =
+ CrossCall(ipc, IpcTag::NTCREATEFILE, name.get(), attributes,
+ desired_access_uint32, file_attributes, sharing, disposition,
+ options_uint32, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ status = answer.nt_status;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ break;
+
+ __try {
+ *file = answer.handle;
+ io_status->Status = answer.nt_status;
+ io_status->Information = answer.extended[0].ulong_ptr;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ mozilla::sandboxing::LogAllowed("NtCreateFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI TargetNtOpenFile(NtOpenFileFunction orig_OpenFile,
+ PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ ULONG sharing,
+ ULONG options) {
+ // Check if the process can open it first.
+ NTSTATUS status = orig_OpenFile(file, desired_access, object_attributes,
+ io_status, sharing, options);
+ if (STATUS_ACCESS_DENIED != status &&
+ STATUS_NETWORK_OPEN_RESTRICTION != status)
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtOpenFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(file, sizeof(HANDLE), WRITE))
+ break;
+ if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes;
+ NTSTATUS ret =
+ AllocAndCopyName(object_attributes, &name, &attributes, nullptr);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ uint32_t desired_access_uint32 = desired_access;
+ uint32_t options_uint32 = options;
+ uint32_t disposition_uint32 = FILE_OPEN;
+ uint32_t broker = BROKER_FALSE;
+ const wchar_t* name_ptr = name.get();
+ CountedParameterSet<OpenFile> params;
+ params[OpenFile::NAME] = ParamPickerMake(name_ptr);
+ params[OpenFile::ACCESS] = ParamPickerMake(desired_access_uint32);
+ params[OpenFile::DISPOSITION] = ParamPickerMake(disposition_uint32);
+ params[OpenFile::OPTIONS] = ParamPickerMake(options_uint32);
+ params[OpenFile::BROKER] = ParamPickerMake(broker);
+
+ if (!QueryBroker(IpcTag::NTOPENFILE, params.GetBase()))
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code =
+ CrossCall(ipc, IpcTag::NTOPENFILE, name.get(), attributes,
+ desired_access_uint32, sharing, options_uint32, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ status = answer.nt_status;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ break;
+
+ __try {
+ *file = answer.handle;
+ io_status->Status = answer.nt_status;
+ io_status->Information = answer.extended[0].ulong_ptr;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ mozilla::sandboxing::LogAllowed("NtOpenFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI
+TargetNtQueryAttributesFile(NtQueryAttributesFileFunction orig_QueryAttributes,
+ POBJECT_ATTRIBUTES object_attributes,
+ PFILE_BASIC_INFORMATION file_attributes) {
+ // Check if the process can query it first.
+ NTSTATUS status = orig_QueryAttributes(object_attributes, file_attributes);
+ if (STATUS_ACCESS_DENIED != status &&
+ STATUS_NETWORK_OPEN_RESTRICTION != status)
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtQueryAttributesFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(file_attributes, sizeof(FILE_BASIC_INFORMATION), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes = 0;
+ NTSTATUS ret =
+ AllocAndCopyName(object_attributes, &name, &attributes, nullptr);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ InOutCountedBuffer file_info(file_attributes,
+ sizeof(FILE_BASIC_INFORMATION));
+
+ uint32_t broker = BROKER_FALSE;
+ CountedParameterSet<FileName> params;
+ const wchar_t* name_ptr = name.get();
+ params[FileName::NAME] = ParamPickerMake(name_ptr);
+ params[FileName::BROKER] = ParamPickerMake(broker);
+
+ if (!QueryBroker(IpcTag::NTQUERYATTRIBUTESFILE, params.GetBase()))
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::NTQUERYATTRIBUTESFILE, name.get(),
+ attributes, file_info, &answer);
+
+ if (SBOX_ALL_OK != code)
+ break;
+
+ status = answer.nt_status;
+
+ mozilla::sandboxing::LogAllowed("NtQueryAttributesFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI TargetNtQueryFullAttributesFile(
+ NtQueryFullAttributesFileFunction orig_QueryFullAttributes,
+ POBJECT_ATTRIBUTES object_attributes,
+ PFILE_NETWORK_OPEN_INFORMATION file_attributes) {
+ // Check if the process can query it first.
+ NTSTATUS status =
+ orig_QueryFullAttributes(object_attributes, file_attributes);
+ if (STATUS_ACCESS_DENIED != status &&
+ STATUS_NETWORK_OPEN_RESTRICTION != status)
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtQueryFullAttributesFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(file_attributes, sizeof(FILE_NETWORK_OPEN_INFORMATION),
+ WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes = 0;
+ NTSTATUS ret =
+ AllocAndCopyName(object_attributes, &name, &attributes, nullptr);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ InOutCountedBuffer file_info(file_attributes,
+ sizeof(FILE_NETWORK_OPEN_INFORMATION));
+
+ uint32_t broker = BROKER_FALSE;
+ CountedParameterSet<FileName> params;
+ const wchar_t* name_ptr = name.get();
+ params[FileName::NAME] = ParamPickerMake(name_ptr);
+ params[FileName::BROKER] = ParamPickerMake(broker);
+
+ if (!QueryBroker(IpcTag::NTQUERYFULLATTRIBUTESFILE, params.GetBase()))
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::NTQUERYFULLATTRIBUTESFILE,
+ name.get(), attributes, file_info, &answer);
+
+ if (SBOX_ALL_OK != code)
+ break;
+
+ status = answer.nt_status;
+
+ mozilla::sandboxing::LogAllowed("NtQueryFullAttributesFile",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI
+TargetNtSetInformationFile(NtSetInformationFileFunction orig_SetInformationFile,
+ HANDLE file,
+ PIO_STATUS_BLOCK io_status,
+ PVOID file_info,
+ ULONG length,
+ FILE_INFORMATION_CLASS file_info_class) {
+ // Check if the process can open it first.
+ NTSTATUS status = orig_SetInformationFile(file, io_status, file_info, length,
+ file_info_class);
+ if (STATUS_ACCESS_DENIED != status)
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtSetInformationFile");
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
+ break;
+
+ if (!ValidParameter(file_info, length, READ))
+ break;
+
+ FILE_RENAME_INFORMATION* file_rename_info =
+ reinterpret_cast<FILE_RENAME_INFORMATION*>(file_info);
+ OBJECT_ATTRIBUTES object_attributes;
+ UNICODE_STRING object_name;
+ InitializeObjectAttributes(&object_attributes, &object_name, 0, nullptr,
+ nullptr);
+
+ __try {
+ if (!IsSupportedRenameCall(file_rename_info, length, file_info_class))
+ break;
+
+ object_attributes.RootDirectory = file_rename_info->RootDirectory;
+ object_name.Buffer = file_rename_info->FileName;
+ object_name.Length = object_name.MaximumLength =
+ static_cast<USHORT>(file_rename_info->FileNameLength);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ NTSTATUS ret =
+ AllocAndCopyName(&object_attributes, &name, nullptr, nullptr);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ uint32_t broker = BROKER_FALSE;
+ CountedParameterSet<FileName> params;
+ const wchar_t* name_ptr = name.get();
+ params[FileName::NAME] = ParamPickerMake(name_ptr);
+ params[FileName::BROKER] = ParamPickerMake(broker);
+
+ if (!QueryBroker(IpcTag::NTSETINFO_RENAME, params.GetBase()))
+ break;
+
+ InOutCountedBuffer io_status_buffer(io_status, sizeof(IO_STATUS_BLOCK));
+ // This is actually not an InOut buffer, only In, but using InOut facility
+ // really helps to simplify the code.
+ InOutCountedBuffer file_info_buffer(file_info, length);
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code =
+ CrossCall(ipc, IpcTag::NTSETINFO_RENAME, file, io_status_buffer,
+ file_info_buffer, length, file_info_class, &answer);
+
+ if (SBOX_ALL_OK != code)
+ break;
+
+ status = answer.nt_status;
+ mozilla::sandboxing::LogAllowed("NtSetInformationFile");
+ } while (false);
+
+ return status;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.h b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.h
new file mode 100644
index 0000000000..d9d92f7fa4
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_FILESYSTEM_INTERCEPTION_H_
+#define SANDBOX_WIN_SRC_FILESYSTEM_INTERCEPTION_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtCreateFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateFile(NtCreateFileFunction orig_CreateFile,
+ PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ PLARGE_INTEGER allocation_size,
+ ULONG file_attributes,
+ ULONG sharing,
+ ULONG disposition,
+ ULONG options,
+ PVOID ea_buffer,
+ ULONG ea_length);
+
+// Interception of NtOpenFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenFile(NtOpenFileFunction orig_OpenFile,
+ PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ ULONG sharing,
+ ULONG options);
+
+// Interception of NtQueryAtttributesFile on the child process.
+// It should never be called directly.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtQueryAttributesFile(NtQueryAttributesFileFunction orig_QueryAttributes,
+ POBJECT_ATTRIBUTES object_attributes,
+ PFILE_BASIC_INFORMATION file_attributes);
+
+// Interception of NtQueryFullAtttributesFile on the child process.
+// It should never be called directly.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryFullAttributesFile(
+ NtQueryFullAttributesFileFunction orig_QueryAttributes,
+ POBJECT_ATTRIBUTES object_attributes,
+ PFILE_NETWORK_OPEN_INFORMATION file_attributes);
+
+// Interception of NtSetInformationFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtSetInformationFile(NtSetInformationFileFunction orig_SetInformationFile,
+ HANDLE file,
+ PIO_STATUS_BLOCK io_status,
+ PVOID file_information,
+ ULONG length,
+ FILE_INFORMATION_CLASS file_information_class);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_FILESYSTEM_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_policy.cc b/security/sandbox/chromium/sandbox/win/src/filesystem_policy.cc
new file mode 100644
index 0000000000..3018cad0cb
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_policy.cc
@@ -0,0 +1,443 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/filesystem_policy.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+NTSTATUS NtCreateFileInTarget(HANDLE* target_file_handle,
+ ACCESS_MASK desired_access,
+ OBJECT_ATTRIBUTES* obj_attributes,
+ IO_STATUS_BLOCK* io_status_block,
+ ULONG file_attributes,
+ ULONG share_access,
+ ULONG create_disposition,
+ ULONG create_options,
+ PVOID ea_buffer,
+ ULONG ea_length,
+ HANDLE target_process) {
+ NtCreateFileFunction NtCreateFile = nullptr;
+ ResolveNTFunctionPtr("NtCreateFile", &NtCreateFile);
+
+ HANDLE local_handle = INVALID_HANDLE_VALUE;
+ NTSTATUS status =
+ NtCreateFile(&local_handle, desired_access, obj_attributes,
+ io_status_block, nullptr, file_attributes, share_access,
+ create_disposition, create_options, ea_buffer, ea_length);
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, target_process,
+ target_file_handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ return STATUS_SUCCESS;
+}
+
+// Get an initialized anonymous level Security QOS.
+SECURITY_QUALITY_OF_SERVICE GetAnonymousQOS() {
+ SECURITY_QUALITY_OF_SERVICE security_qos = {0};
+ security_qos.Length = sizeof(security_qos);
+ security_qos.ImpersonationLevel = SecurityAnonymous;
+ // Set dynamic tracking so that a pipe doesn't capture the broker's token
+ security_qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+ security_qos.EffectiveOnly = true;
+
+ return security_qos;
+}
+
+} // namespace.
+
+namespace sandbox {
+
+bool FileSystemPolicy::GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ std::wstring mod_name(name);
+ if (mod_name.empty()) {
+ return false;
+ }
+
+ // Don't pre-process the path name and check for reparse points if it is the
+ // special case of allowing read access to all paths.
+ if (!(semantics == TargetPolicy::FILES_ALLOW_READONLY
+ && mod_name.compare(L"*") == 0)
+ && !PreProcessName(&mod_name)) {
+ // The path to be added might contain a reparse point.
+ NOTREACHED();
+ return false;
+ }
+
+ // TODO(cpu) bug 32224: This prefix add is a hack because we don't have the
+ // infrastructure to normalize names. In any case we need to escape the
+ // question marks.
+ if (_wcsnicmp(mod_name.c_str(), kNTDevicePrefix, kNTDevicePrefixLen)) {
+ mod_name = FixNTPrefixForMatch(mod_name);
+ name = mod_name.c_str();
+ }
+
+ EvalResult result = ASK_BROKER;
+
+ // List of supported calls for the filesystem.
+ const unsigned kCallNtCreateFile = 0x1;
+ const unsigned kCallNtOpenFile = 0x2;
+ const unsigned kCallNtQueryAttributesFile = 0x4;
+ const unsigned kCallNtQueryFullAttributesFile = 0x8;
+ const unsigned kCallNtSetInfoRename = 0x10;
+
+ DWORD rule_to_add = kCallNtOpenFile | kCallNtCreateFile |
+ kCallNtQueryAttributesFile |
+ kCallNtQueryFullAttributesFile | kCallNtSetInfoRename;
+
+ PolicyRule create(result);
+ PolicyRule open(result);
+ PolicyRule query(result);
+ PolicyRule query_full(result);
+ PolicyRule rename(result);
+
+ switch (semantics) {
+ case TargetPolicy::FILES_ALLOW_DIR_ANY: {
+ open.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
+ create.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
+ break;
+ }
+ case TargetPolicy::FILES_ALLOW_READONLY: {
+ // We consider all flags that are not known to be readonly as potentially
+ // used for write.
+ DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES |
+ FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE |
+ GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
+ DWORD restricted_flags = ~allowed_flags;
+ open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
+ open.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL);
+ create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
+ create.AddNumberMatch(IF, OpenFile::DISPOSITION, FILE_OPEN, EQUAL);
+
+ // Read only access don't work for rename.
+ rule_to_add &= ~kCallNtSetInfoRename;
+ break;
+ }
+ case TargetPolicy::FILES_ALLOW_QUERY: {
+ // Here we don't want to add policy for the open or the create.
+ rule_to_add &=
+ ~(kCallNtOpenFile | kCallNtCreateFile | kCallNtSetInfoRename);
+ break;
+ }
+ case TargetPolicy::FILES_ALLOW_ANY: {
+ break;
+ }
+ default: {
+ NOTREACHED();
+ return false;
+ }
+ }
+
+ if ((rule_to_add & kCallNtCreateFile) &&
+ (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+ !policy->AddRule(IpcTag::NTCREATEFILE, &create))) {
+ return false;
+ }
+
+ if ((rule_to_add & kCallNtOpenFile) &&
+ (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
+ !policy->AddRule(IpcTag::NTOPENFILE, &open))) {
+ return false;
+ }
+
+ if ((rule_to_add & kCallNtQueryAttributesFile) &&
+ (!query.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
+ !policy->AddRule(IpcTag::NTQUERYATTRIBUTESFILE, &query))) {
+ return false;
+ }
+
+ if ((rule_to_add & kCallNtQueryFullAttributesFile) &&
+ (!query_full.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
+ !policy->AddRule(IpcTag::NTQUERYFULLATTRIBUTESFILE, &query_full))) {
+ return false;
+ }
+
+ if ((rule_to_add & kCallNtSetInfoRename) &&
+ (!rename.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
+ !policy->AddRule(IpcTag::NTSETINFO_RENAME, &rename))) {
+ return false;
+ }
+
+ return true;
+}
+
+// Right now we insert two rules, to be evaluated before any user supplied rule:
+// - go to the broker if the path doesn't look like the paths that we push on
+// the policy (namely \??\something).
+// - go to the broker if it looks like this is a short-name path.
+//
+// It is possible to add a rule to go to the broker in any case; it would look
+// something like:
+// rule = new PolicyRule(ASK_BROKER);
+// rule->AddNumberMatch(IF_NOT, FileName::BROKER, true, AND);
+// policy->AddRule(service, rule);
+bool FileSystemPolicy::SetInitialRules(LowLevelPolicy* policy) {
+ PolicyRule format(ASK_BROKER);
+ PolicyRule short_name(ASK_BROKER);
+
+ bool rv = format.AddNumberMatch(IF_NOT, FileName::BROKER, BROKER_TRUE, AND);
+ rv &= format.AddStringMatch(IF_NOT, FileName::NAME, L"\\/?/?\\*",
+ CASE_SENSITIVE);
+
+ rv &= short_name.AddNumberMatch(IF_NOT, FileName::BROKER, BROKER_TRUE, AND);
+ rv &= short_name.AddStringMatch(IF, FileName::NAME, L"*~*", CASE_SENSITIVE);
+
+ if (!rv || !policy->AddRule(IpcTag::NTCREATEFILE, &format))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTCREATEFILE, &short_name))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTOPENFILE, &format))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTOPENFILE, &short_name))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTQUERYATTRIBUTESFILE, &format))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTQUERYATTRIBUTESFILE, &short_name))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTQUERYFULLATTRIBUTESFILE, &format))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTQUERYFULLATTRIBUTESFILE, &short_name))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTSETINFO_RENAME, &format))
+ return false;
+
+ if (!policy->AddRule(IpcTag::NTSETINFO_RENAME, &short_name))
+ return false;
+
+ return true;
+}
+
+bool FileSystemPolicy::CreateFileAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ HANDLE* handle,
+ NTSTATUS* nt_status,
+ ULONG_PTR* io_information) {
+ *handle = nullptr;
+ // The only action supported is ASK_BROKER which means create the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+ IO_STATUS_BLOCK io_block = {};
+ UNICODE_STRING uni_name = {};
+ OBJECT_ATTRIBUTES obj_attributes = {};
+ SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+ InitObjectAttribs(file, attributes, nullptr, &obj_attributes, &uni_name,
+ IsPipe(file) ? &security_qos : nullptr);
+ *nt_status =
+ NtCreateFileInTarget(handle, desired_access, &obj_attributes, &io_block,
+ file_attributes, share_access, create_disposition,
+ create_options, nullptr, 0, client_info.process);
+
+ *io_information = io_block.Information;
+ return true;
+}
+
+bool FileSystemPolicy::OpenFileAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t share_access,
+ uint32_t open_options,
+ HANDLE* handle,
+ NTSTATUS* nt_status,
+ ULONG_PTR* io_information) {
+ *handle = nullptr;
+ // The only action supported is ASK_BROKER which means open the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+ // An NtOpen is equivalent to an NtCreate with FileAttributes = 0 and
+ // CreateDisposition = FILE_OPEN.
+ IO_STATUS_BLOCK io_block = {};
+ UNICODE_STRING uni_name = {};
+ OBJECT_ATTRIBUTES obj_attributes = {};
+ SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+ InitObjectAttribs(file, attributes, nullptr, &obj_attributes, &uni_name,
+ IsPipe(file) ? &security_qos : nullptr);
+ *nt_status = NtCreateFileInTarget(
+ handle, desired_access, &obj_attributes, &io_block, 0, share_access,
+ FILE_OPEN, open_options, nullptr, 0, client_info.process);
+
+ *io_information = io_block.Information;
+ return true;
+}
+
+bool FileSystemPolicy::QueryAttributesFileAction(
+ EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ FILE_BASIC_INFORMATION* file_info,
+ NTSTATUS* nt_status) {
+ // The only action supported is ASK_BROKER which means query the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+
+ NtQueryAttributesFileFunction NtQueryAttributesFile = nullptr;
+ ResolveNTFunctionPtr("NtQueryAttributesFile", &NtQueryAttributesFile);
+
+ UNICODE_STRING uni_name = {0};
+ OBJECT_ATTRIBUTES obj_attributes = {0};
+ SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+ InitObjectAttribs(file, attributes, nullptr, &obj_attributes, &uni_name,
+ IsPipe(file) ? &security_qos : nullptr);
+ *nt_status = NtQueryAttributesFile(&obj_attributes, file_info);
+
+ return true;
+}
+
+bool FileSystemPolicy::QueryFullAttributesFileAction(
+ EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ FILE_NETWORK_OPEN_INFORMATION* file_info,
+ NTSTATUS* nt_status) {
+ // The only action supported is ASK_BROKER which means query the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+
+ NtQueryFullAttributesFileFunction NtQueryFullAttributesFile = nullptr;
+ ResolveNTFunctionPtr("NtQueryFullAttributesFile", &NtQueryFullAttributesFile);
+
+ UNICODE_STRING uni_name = {0};
+ OBJECT_ATTRIBUTES obj_attributes = {0};
+ SECURITY_QUALITY_OF_SERVICE security_qos = GetAnonymousQOS();
+
+ InitObjectAttribs(file, attributes, nullptr, &obj_attributes, &uni_name,
+ IsPipe(file) ? &security_qos : nullptr);
+ *nt_status = NtQueryFullAttributesFile(&obj_attributes, file_info);
+
+ return true;
+}
+
+bool FileSystemPolicy::SetInformationFileAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ HANDLE target_file_handle,
+ void* file_info,
+ uint32_t length,
+ uint32_t info_class,
+ IO_STATUS_BLOCK* io_block,
+ NTSTATUS* nt_status) {
+ // The only action supported is ASK_BROKER which means open the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+
+ NtSetInformationFileFunction NtSetInformationFile = nullptr;
+ ResolveNTFunctionPtr("NtSetInformationFile", &NtSetInformationFile);
+
+ HANDLE local_handle = nullptr;
+ if (!::DuplicateHandle(client_info.process, target_file_handle,
+ ::GetCurrentProcess(), &local_handle, 0, false,
+ DUPLICATE_SAME_ACCESS)) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+
+ base::win::ScopedHandle handle(local_handle);
+
+ FILE_INFORMATION_CLASS file_info_class =
+ static_cast<FILE_INFORMATION_CLASS>(info_class);
+ *nt_status = NtSetInformationFile(local_handle, io_block, file_info, length,
+ file_info_class);
+
+ return true;
+}
+
+bool PreProcessName(std::wstring* path) {
+ // We now allow symbolic links to be opened via the broker, so we can no
+ // longer rely on the same object check where we checked the path of the
+ // opened file against the original. We don't specify a root when creating
+ // OBJECT_ATTRIBUTES from file names for brokering so they must be fully
+ // qualified and we can just check for the parent directory double dot between
+ // two backslashes. NtCreateFile doesn't seem to allow it anyway, but this is
+ // just an extra precaution. It also doesn't seem to allow the forward slash,
+ // but this is also used for checking policy rules, so we just replace forward
+ // slashes with backslashes.
+ std::replace(path->begin(), path->end(), L'/', L'\\');
+ if (path->find(L"\\..\\") != std::wstring::npos) {
+ return false;
+ }
+
+ ConvertToLongPath(path);
+ return true;
+}
+
+std::wstring FixNTPrefixForMatch(const std::wstring& name) {
+ std::wstring mod_name = name;
+
+ // NT prefix escaped for rule matcher
+ const wchar_t kNTPrefixEscaped[] = L"\\/?/?\\";
+ const int kNTPrefixEscapedLen = base::size(kNTPrefixEscaped) - 1;
+
+ if (0 != mod_name.compare(0, kNTPrefixLen, kNTPrefix)) {
+ if (0 != mod_name.compare(0, kNTPrefixEscapedLen, kNTPrefixEscaped)) {
+ // TODO(nsylvain): Find a better way to do name resolution. Right now we
+ // take the name and we expand it.
+ mod_name.insert(0, kNTPrefixEscaped);
+ }
+ } else {
+ // Start of name matches NT prefix, replace with escaped format
+ // Fixes bug: 334882
+ mod_name.replace(0, kNTPrefixLen, kNTPrefixEscaped);
+ }
+
+ return mod_name;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_policy.h b/security/sandbox/chromium/sandbox/win/src/filesystem_policy.h
new file mode 100644
index 0000000000..81dd1d0d1d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_policy.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_FILESYSTEM_POLICY_H__
+#define SANDBOX_SRC_FILESYSTEM_POLICY_H__
+
+#include <stdint.h>
+
+#include <string>
+
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum IsBroker { BROKER_FALSE, BROKER_TRUE };
+
+// This class centralizes most of the knowledge related to file system policy
+class FileSystemPolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level
+ // policy rule for File IO, in particular open or create actions.
+ // 'name' is the file or directory name.
+ // 'semantics' is the desired semantics for the open or create.
+ // 'policy' is the policy generator to which the rules are going to be added.
+ static bool GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ // Add basic file system rules.
+ static bool SetInitialRules(LowLevelPolicy* policy);
+
+ // Performs the desired policy action on a create request with an
+ // API that is compatible with the IPC-received parameters.
+ // 'client_info' : the target process that is making the request.
+ // 'eval_result' : The desired policy action to accomplish.
+ // 'file' : The target file or directory.
+ static bool CreateFileAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t file_attributes,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ HANDLE* handle,
+ NTSTATUS* nt_status,
+ ULONG_PTR* io_information);
+
+ // Performs the desired policy action on an open request with an
+ // API that is compatible with the IPC-received parameters.
+ // 'client_info' : the target process that is making the request.
+ // 'eval_result' : The desired policy action to accomplish.
+ // 'file' : The target file or directory.
+ static bool OpenFileAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ uint32_t desired_access,
+ uint32_t share_access,
+ uint32_t open_options,
+ HANDLE* handle,
+ NTSTATUS* nt_status,
+ ULONG_PTR* io_information);
+
+ // Performs the desired policy action on a query request with an
+ // API that is compatible with the IPC-received parameters.
+ static bool QueryAttributesFileAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ FILE_BASIC_INFORMATION* file_info,
+ NTSTATUS* nt_status);
+
+ // Performs the desired policy action on a query request with an
+ // API that is compatible with the IPC-received parameters.
+ static bool QueryFullAttributesFileAction(
+ EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& file,
+ uint32_t attributes,
+ FILE_NETWORK_OPEN_INFORMATION* file_info,
+ NTSTATUS* nt_status);
+
+ // Performs the desired policy action on a set_info request with an
+ // API that is compatible with the IPC-received parameters.
+ static bool SetInformationFileAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ HANDLE target_file_handle,
+ void* file_info,
+ uint32_t length,
+ uint32_t info_class,
+ IO_STATUS_BLOCK* io_block,
+ NTSTATUS* nt_status);
+};
+
+// Expands the path and check if it's a reparse point. Returns false if the path
+// cannot be trusted.
+bool PreProcessName(std::wstring* path);
+
+// Corrects global paths to have a correctly escaped NT prefix at the
+// beginning. If the name has no NT prefix (either normal or escaped)
+// add the escaped form to the string
+std::wstring FixNTPrefixForMatch(const std::wstring& name);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_FILESYSTEM_POLICY_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_closer.cc b/security/sandbox/chromium/sandbox/win/src/handle_closer.cc
new file mode 100644
index 0000000000..6751151dcb
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_closer.cc
@@ -0,0 +1,185 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_closer.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/memory/free_deleter.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+template <typename T>
+T RoundUpToWordSize(T v) {
+ if (size_t mod = v % sizeof(size_t))
+ v += sizeof(size_t) - mod;
+ return v;
+}
+
+template <typename T>
+T* RoundUpToWordSize(T* v) {
+ return reinterpret_cast<T*>(RoundUpToWordSize(reinterpret_cast<size_t>(v)));
+}
+
+} // namespace
+
+namespace sandbox {
+
+// Memory buffer mapped from the parent, with the list of handles.
+SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close;
+
+HandleCloser::HandleCloser() {}
+
+HandleCloser::~HandleCloser() {}
+
+ResultCode HandleCloser::AddHandle(const wchar_t* handle_type,
+ const wchar_t* handle_name) {
+ if (!handle_type)
+ return SBOX_ERROR_BAD_PARAMS;
+
+ std::wstring resolved_name;
+ if (handle_name) {
+ resolved_name = handle_name;
+ if (handle_type == std::wstring(L"Key"))
+ if (!ResolveRegistryName(resolved_name, &resolved_name))
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+
+ HandleMap::iterator names = handles_to_close_.find(handle_type);
+ if (names == handles_to_close_.end()) { // We have no entries for this type.
+ std::pair<HandleMap::iterator, bool> result = handles_to_close_.insert(
+ HandleMap::value_type(handle_type, HandleMap::mapped_type()));
+ names = result.first;
+ if (handle_name)
+ names->second.insert(resolved_name);
+ } else if (!handle_name) { // Now we need to close all handles of this type.
+ names->second.clear();
+ } else if (!names->second.empty()) { // Add another name for this type.
+ names->second.insert(resolved_name);
+ } // If we're already closing all handles of type then we're done.
+
+ return SBOX_ALL_OK;
+}
+
+size_t HandleCloser::GetBufferSize() {
+ size_t bytes_total = offsetof(HandleCloserInfo, handle_entries);
+
+ for (HandleMap::iterator i = handles_to_close_.begin();
+ i != handles_to_close_.end(); ++i) {
+ size_t bytes_entry = offsetof(HandleListEntry, handle_type) +
+ (i->first.size() + 1) * sizeof(wchar_t);
+ for (HandleMap::mapped_type::iterator j = i->second.begin();
+ j != i->second.end(); ++j) {
+ bytes_entry += ((*j).size() + 1) * sizeof(wchar_t);
+ }
+
+ // Round up to the nearest multiple of word size.
+ bytes_entry = RoundUpToWordSize(bytes_entry);
+ bytes_total += bytes_entry;
+ }
+
+ return bytes_total;
+}
+
+bool HandleCloser::InitializeTargetHandles(TargetProcess* target) {
+ // Do nothing on an empty list (global pointer already initialized to
+ // nullptr).
+ if (handles_to_close_.empty())
+ return true;
+
+ size_t bytes_needed = GetBufferSize();
+ std::unique_ptr<size_t[]> local_buffer(
+ new size_t[bytes_needed / sizeof(size_t)]);
+
+ if (!SetupHandleList(local_buffer.get(), bytes_needed))
+ return false;
+
+ void* remote_data;
+ if (!CopyToChildMemory(target->Process(), local_buffer.get(), bytes_needed,
+ &remote_data))
+ return false;
+
+ g_handles_to_close = reinterpret_cast<HandleCloserInfo*>(remote_data);
+
+ ResultCode rc = target->TransferVariable(
+ "g_handles_to_close", &g_handles_to_close, sizeof(g_handles_to_close));
+
+ return (SBOX_ALL_OK == rc);
+}
+
+bool HandleCloser::SetupHandleList(void* buffer, size_t buffer_bytes) {
+ ::ZeroMemory(buffer, buffer_bytes);
+ HandleCloserInfo* handle_info = reinterpret_cast<HandleCloserInfo*>(buffer);
+ handle_info->record_bytes = buffer_bytes;
+ handle_info->num_handle_types = handles_to_close_.size();
+
+ wchar_t* output = reinterpret_cast<wchar_t*>(&handle_info->handle_entries[0]);
+ wchar_t* end = reinterpret_cast<wchar_t*>(reinterpret_cast<char*>(buffer) +
+ buffer_bytes);
+ for (HandleMap::iterator i = handles_to_close_.begin();
+ i != handles_to_close_.end(); ++i) {
+ if (output >= end)
+ return false;
+ HandleListEntry* list_entry = reinterpret_cast<HandleListEntry*>(output);
+ output = &list_entry->handle_type[0];
+
+ // Copy the typename and set the offset and count.
+ i->first.copy(output, i->first.size());
+ *(output += i->first.size()) = L'\0';
+ output++;
+ list_entry->offset_to_names =
+ reinterpret_cast<char*>(output) - reinterpret_cast<char*>(list_entry);
+ list_entry->name_count = i->second.size();
+
+ // Copy the handle names.
+ for (HandleMap::mapped_type::iterator j = i->second.begin();
+ j != i->second.end(); ++j) {
+ output = std::copy((*j).begin(), (*j).end(), output) + 1;
+ }
+
+ // Round up to the nearest multiple of sizeof(size_t).
+ output = RoundUpToWordSize(output);
+ list_entry->record_bytes =
+ reinterpret_cast<char*>(output) - reinterpret_cast<char*>(list_entry);
+ }
+
+ DCHECK_EQ(reinterpret_cast<size_t>(output), reinterpret_cast<size_t>(end));
+ return output <= end;
+}
+
+bool GetHandleName(HANDLE handle, std::wstring* handle_name) {
+ static NtQueryObject QueryObject = nullptr;
+ if (!QueryObject)
+ ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+ ULONG size = MAX_PATH;
+ std::unique_ptr<UNICODE_STRING, base::FreeDeleter> name;
+ NTSTATUS result;
+
+ do {
+ name.reset(static_cast<UNICODE_STRING*>(malloc(size)));
+ DCHECK(name.get());
+ result =
+ QueryObject(handle, ObjectNameInformation, name.get(), size, &size);
+ } while (result == STATUS_INFO_LENGTH_MISMATCH ||
+ result == STATUS_BUFFER_OVERFLOW);
+
+ if (NT_SUCCESS(result) && name->Buffer && name->Length)
+ handle_name->assign(name->Buffer, name->Length / sizeof(wchar_t));
+ else
+ handle_name->clear();
+
+ return NT_SUCCESS(result);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_closer.h b/security/sandbox/chromium/sandbox/win/src/handle_closer.h
new file mode 100644
index 0000000000..4f023b27b6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_closer.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_CLOSER_H_
+#define SANDBOX_SRC_HANDLE_CLOSER_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <set>
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/target_process.h"
+
+namespace sandbox {
+
+// This is a map of handle-types to names that we need to close in the
+// target process. A null set means we need to close all handles of the
+// given type.
+typedef std::map<const std::wstring, std::set<std::wstring>> HandleMap;
+
+// Type and set of corresponding handle names to close.
+struct HandleListEntry {
+ size_t record_bytes; // Rounded to sizeof(size_t) bytes.
+ size_t offset_to_names; // Nul terminated strings of name_count names.
+ size_t name_count;
+ wchar_t handle_type[1];
+};
+
+// Global parameters and a pointer to the list of entries.
+struct HandleCloserInfo {
+ size_t record_bytes; // Rounded to sizeof(size_t) bytes.
+ size_t num_handle_types;
+ struct HandleListEntry handle_entries[1];
+};
+
+SANDBOX_INTERCEPT HandleCloserInfo* g_handle_closer_info;
+
+// Adds handles to close after lockdown.
+class HandleCloser {
+ public:
+ HandleCloser();
+ ~HandleCloser();
+
+ // Adds a handle that will be closed in the target process after lockdown.
+ // A nullptr value for handle_name indicates all handles of the specified
+ // type. An empty string for handle_name indicates the handle is unnamed.
+ ResultCode AddHandle(const wchar_t* handle_type, const wchar_t* handle_name);
+
+ // Serializes and copies the closer table into the target process.
+ bool InitializeTargetHandles(TargetProcess* target);
+
+ private:
+ // Calculates the memory needed to copy the serialized handles list (rounded
+ // to the nearest machine-word size).
+ size_t GetBufferSize();
+
+ // Serializes the handle list into the target process.
+ bool SetupHandleList(void* buffer, size_t buffer_bytes);
+
+ HandleMap handles_to_close_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandleCloser);
+};
+
+// Returns the object manager's name associated with a handle
+bool GetHandleName(HANDLE handle, std::wstring* handle_name);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_HANDLE_CLOSER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_closer_agent.cc b/security/sandbox/chromium/sandbox/win/src/handle_closer_agent.cc
new file mode 100644
index 0000000000..55fe2d4689
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_closer_agent.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_closer_agent.h"
+
+#include <limits.h>
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/win/static_constants.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// Returns type infomation for an NT object. This routine is expected to be
+// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions
+// that can be generated when handle tracing is enabled.
+NTSTATUS QueryObjectTypeInformation(HANDLE handle, void* buffer, ULONG* size) {
+ static NtQueryObject QueryObject = nullptr;
+ if (!QueryObject)
+ ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ __try {
+ status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
+ } __except (GetExceptionCode() == STATUS_INVALID_HANDLE
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH) {
+ status = STATUS_INVALID_HANDLE;
+ }
+ return status;
+}
+
+} // namespace
+
+namespace sandbox {
+
+// Memory buffer mapped from the parent, with the list of handles.
+SANDBOX_INTERCEPT HandleCloserInfo* g_handles_to_close = nullptr;
+
+bool HandleCloserAgent::NeedsHandlesClosed() {
+ return !!g_handles_to_close;
+}
+
+HandleCloserAgent::HandleCloserAgent()
+ : dummy_handle_(::CreateEvent(nullptr, false, false, nullptr)) {}
+
+HandleCloserAgent::~HandleCloserAgent() {}
+
+// Attempts to stuff |closed_handle| with a duplicated handle for a dummy Event
+// with no access. This should allow the handle to be closed, to avoid
+// generating EXCEPTION_INVALID_HANDLE on shutdown, but nothing else. For now
+// the only supported |type| is Event or File.
+bool HandleCloserAgent::AttemptToStuffHandleSlot(HANDLE closed_handle,
+ const std::wstring& type) {
+ // Only attempt to stuff Files and Events at the moment.
+ if (type != L"Event" && type != L"File") {
+ return true;
+ }
+
+ if (!dummy_handle_.IsValid())
+ return false;
+
+ // This should never happen, as g_dummy is created before closing to_stuff.
+ DCHECK(dummy_handle_.Get() != closed_handle);
+
+ std::vector<HANDLE> to_close;
+
+ const DWORD original_proc_num = GetCurrentProcessorNumber();
+ DWORD proc_num = original_proc_num;
+ DWORD_PTR original_affinity_mask =
+ SetThreadAffinityMask(GetCurrentThread(), DWORD_PTR{1} << proc_num);
+ bool found_handle = false;
+ BOOL result = FALSE;
+
+ // There is per-processor based free list of handles entries. The free handle
+ // from current processor's freelist is preferred for reusing, so cycling
+ // through all possible processors to find closed_handle.
+ // Start searching from current processor which covers usual cases.
+
+ do {
+ DWORD_PTR current_mask = DWORD_PTR{1} << proc_num;
+
+ if (original_affinity_mask & current_mask) {
+ if (proc_num != original_proc_num) {
+ SetThreadAffinityMask(GetCurrentThread(), current_mask);
+ }
+
+ HANDLE dup_dummy = nullptr;
+ size_t count = 16;
+
+ do {
+ result =
+ ::DuplicateHandle(::GetCurrentProcess(), dummy_handle_.Get(),
+ ::GetCurrentProcess(), &dup_dummy, 0, false, 0);
+ if (!result) {
+ break;
+ }
+ if (dup_dummy != closed_handle) {
+ to_close.push_back(dup_dummy);
+ } else {
+ found_handle = true;
+ }
+ } while (count-- && reinterpret_cast<uintptr_t>(dup_dummy) <
+ reinterpret_cast<uintptr_t>(closed_handle));
+ }
+
+ proc_num++;
+ if (proc_num == sizeof(DWORD_PTR) * 8) {
+ proc_num = 0;
+ }
+ if (proc_num == original_proc_num) {
+ break;
+ }
+ } while (result && !found_handle);
+
+ SetThreadAffinityMask(GetCurrentThread(), original_affinity_mask);
+
+ for (HANDLE h : to_close)
+ ::CloseHandle(h);
+
+ return found_handle;
+}
+
+// Reads g_handles_to_close and creates the lookup map.
+void HandleCloserAgent::InitializeHandlesToClose(bool* is_csrss_connected) {
+ CHECK(g_handles_to_close);
+
+ // Default to connected state
+ *is_csrss_connected = true;
+
+ // Grab the header.
+ HandleListEntry* entry = g_handles_to_close->handle_entries;
+ for (size_t i = 0; i < g_handles_to_close->num_handle_types; ++i) {
+ // Set the type name.
+ wchar_t* input = entry->handle_type;
+ if (!wcscmp(input, L"ALPC Port")) {
+ *is_csrss_connected = false;
+ }
+ HandleMap::mapped_type& handle_names = handles_to_close_[input];
+ input = reinterpret_cast<wchar_t*>(reinterpret_cast<char*>(entry) +
+ entry->offset_to_names);
+ // Grab all the handle names.
+ for (size_t j = 0; j < entry->name_count; ++j) {
+ std::pair<HandleMap::mapped_type::iterator, bool> name =
+ handle_names.insert(input);
+ CHECK(name.second);
+ input += name.first->size() + 1;
+ }
+
+ // Move on to the next entry.
+ entry = reinterpret_cast<HandleListEntry*>(reinterpret_cast<char*>(entry) +
+ entry->record_bytes);
+
+ DCHECK(reinterpret_cast<wchar_t*>(entry) >= input);
+ DCHECK(reinterpret_cast<wchar_t*>(entry) - input <
+ static_cast<ptrdiff_t>(sizeof(size_t) / sizeof(wchar_t)));
+ }
+
+ // Clean up the memory we copied over.
+ ::VirtualFree(g_handles_to_close, 0, MEM_RELEASE);
+ g_handles_to_close = nullptr;
+}
+
+bool HandleCloserAgent::CloseHandles() {
+ DWORD handle_count = UINT_MAX;
+ const int kInvalidHandleThreshold = 100;
+ const size_t kHandleOffset = 4; // Handles are always a multiple of 4.
+
+ if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
+ return false;
+
+ // Skip closing these handles when Application Verifier is in use in order to
+ // avoid invalid-handle exceptions.
+ if (GetModuleHandleA(base::win::kApplicationVerifierDllName))
+ return true;
+
+ // Set up buffers for the type info and the name.
+ std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) +
+ 32 * sizeof(wchar_t));
+ OBJECT_TYPE_INFORMATION* type_info =
+ reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
+ std::wstring handle_name;
+ HANDLE handle = nullptr;
+ int invalid_count = 0;
+
+ // Keep incrementing until we hit the number of handles reported by
+ // GetProcessHandleCount(). If we hit a very long sequence of invalid
+ // handles we assume that we've run past the end of the table.
+ while (handle_count && invalid_count < kInvalidHandleThreshold) {
+ reinterpret_cast<size_t&>(handle) += kHandleOffset;
+ NTSTATUS rc;
+
+ // Get the type name, reusing the buffer.
+ ULONG size = static_cast<ULONG>(type_info_buffer.size());
+ rc = QueryObjectTypeInformation(handle, type_info, &size);
+ while (rc == STATUS_INFO_LENGTH_MISMATCH || rc == STATUS_BUFFER_OVERFLOW) {
+ type_info_buffer.resize(size + sizeof(wchar_t));
+ type_info =
+ reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
+ rc = QueryObjectTypeInformation(handle, type_info, &size);
+ // Leave padding for the nul terminator.
+ if (NT_SUCCESS(rc) && size == type_info_buffer.size())
+ rc = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ if (!NT_SUCCESS(rc) || !type_info->Name.Buffer) {
+ ++invalid_count;
+ continue;
+ }
+
+ --handle_count;
+ type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
+
+ // Check if we're looking for this type of handle.
+ HandleMap::iterator result = handles_to_close_.find(type_info->Name.Buffer);
+ if (result != handles_to_close_.end()) {
+ HandleMap::mapped_type& names = result->second;
+ // Empty set means close all handles of this type; otherwise check name.
+ if (!names.empty()) {
+ // Move on to the next handle if this name doesn't match.
+ if (!GetHandleName(handle, &handle_name) || !names.count(handle_name))
+ continue;
+ }
+
+ if (!::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0))
+ return false;
+ if (!::CloseHandle(handle))
+ return false;
+ // Attempt to stuff this handle with a new dummy Event.
+ AttemptToStuffHandleSlot(handle, result->first);
+ }
+ }
+
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_closer_agent.h b/security/sandbox/chromium/sandbox/win/src/handle_closer_agent.h
new file mode 100644
index 0000000000..91f8e74c7e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_closer_agent.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_
+#define SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/handle_closer.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+// Target process code to close the handle list copied over from the broker.
+class HandleCloserAgent {
+ public:
+ HandleCloserAgent();
+ ~HandleCloserAgent();
+
+ // Reads the serialized list from the broker and creates the lookup map.
+ // Updates is_csrss_connected based on type of handles closed.
+ void InitializeHandlesToClose(bool* is_csrss_connected);
+
+ // Closes any handles matching those in the lookup map.
+ bool CloseHandles();
+
+ // True if we have handles waiting to be closed.
+ static bool NeedsHandlesClosed();
+
+ private:
+ // Attempt to stuff a closed handle with a dummy Event.
+ bool AttemptToStuffHandleSlot(HANDLE closed_handle, const std::wstring& type);
+
+ HandleMap handles_to_close_;
+ base::win::ScopedHandle dummy_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(HandleCloserAgent);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_HANDLE_CLOSER_AGENT_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_closer_test.cc b/security/sandbox/chromium/sandbox/win/src/handle_closer_test.cc
new file mode 100644
index 0000000000..7406f77592
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_closer_test.cc
@@ -0,0 +1,297 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <limits.h>
+#include <stddef.h>
+
+#include "base/strings/stringprintf.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/handle_closer_agent.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const wchar_t* kFileExtensions[] = {L".1", L".2", L".3", L".4"};
+
+// Returns a handle to a unique marker file that can be retrieved between runs.
+HANDLE GetMarkerFile(const wchar_t* extension) {
+ wchar_t path_buffer[MAX_PATH + 1];
+ CHECK(::GetTempPath(MAX_PATH, path_buffer));
+ std::wstring marker_path = path_buffer;
+ marker_path += L"\\sbox_marker_";
+
+ // Generate a unique value from the exe's size and timestamp.
+ CHECK(::GetModuleFileName(nullptr, path_buffer, MAX_PATH));
+ base::win::ScopedHandle module(
+ ::CreateFile(path_buffer, FILE_READ_ATTRIBUTES, FILE_SHARE_READ, nullptr,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
+ CHECK(module.IsValid());
+ FILETIME timestamp;
+ CHECK(::GetFileTime(module.Get(), &timestamp, nullptr, nullptr));
+ marker_path +=
+ base::StringPrintf(L"%08x%08x%08x", ::GetFileSize(module.Get(), nullptr),
+ timestamp.dwLowDateTime, timestamp.dwHighDateTime);
+ marker_path += extension;
+
+ // Make the file delete-on-close so cleanup is automatic.
+ return CreateFile(marker_path.c_str(), FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, nullptr);
+}
+
+// Returns type infomation for an NT object. This routine is expected to be
+// called for invalid handles so it catches STATUS_INVALID_HANDLE exceptions
+// that can be generated when handle tracing is enabled.
+NTSTATUS QueryObjectTypeInformation(HANDLE handle, void* buffer, ULONG* size) {
+ static NtQueryObject QueryObject = nullptr;
+ if (!QueryObject)
+ ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ __try {
+ status = QueryObject(handle, ObjectTypeInformation, buffer, *size, size);
+ } __except (GetExceptionCode() == STATUS_INVALID_HANDLE
+ ? EXCEPTION_EXECUTE_HANDLER
+ : EXCEPTION_CONTINUE_SEARCH) {
+ status = STATUS_INVALID_HANDLE;
+ }
+ return status;
+}
+
+// Used by the thread pool tests.
+HANDLE finish_event;
+const int kWaitCount = 20;
+
+} // namespace
+
+namespace sandbox {
+
+// Checks for the presence of a list of files (in object path form).
+// Format: CheckForFileHandle (Y|N) \path\to\file1 [\path\to\file2 ...]
+// - Y or N depending if the file should exist or not.
+SBOX_TESTS_COMMAND int CheckForFileHandles(int argc, wchar_t** argv) {
+ if (argc < 2)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ bool should_find = argv[0][0] == L'Y';
+ if (argv[0][1] != L'\0' || (!should_find && argv[0][0] != L'N'))
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+ static int state = BEFORE_INIT;
+ switch (state++) {
+ case BEFORE_INIT:
+ // Create a unique marker file that is open while the test is running.
+ // The handles leak, but it will be closed by the test or on exit.
+ for (const wchar_t* kExtension : kFileExtensions)
+ CHECK_NE(GetMarkerFile(kExtension), INVALID_HANDLE_VALUE);
+ return SBOX_TEST_SUCCEEDED;
+
+ case AFTER_REVERT: {
+ // Brute force the handle table to find what we're looking for.
+ DWORD handle_count = UINT_MAX;
+ const int kInvalidHandleThreshold = 100;
+ const size_t kHandleOffset = 4; // Handles are always a multiple of 4.
+ HANDLE handle = nullptr;
+ int invalid_count = 0;
+ std::wstring handle_name;
+
+ if (!::GetProcessHandleCount(::GetCurrentProcess(), &handle_count))
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+
+ while (handle_count && invalid_count < kInvalidHandleThreshold) {
+ reinterpret_cast<size_t&>(handle) += kHandleOffset;
+ if (GetHandleName(handle, &handle_name)) {
+ for (int i = 1; i < argc; ++i) {
+ if (handle_name == argv[i])
+ return should_find ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+ }
+ --handle_count;
+ } else {
+ ++invalid_count;
+ }
+ }
+
+ return should_find ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED;
+ }
+
+ default: // Do nothing.
+ break;
+ }
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Checks that supplied handle is an Event and it's not waitable.
+// Format: CheckForEventHandles
+SBOX_TESTS_COMMAND int CheckForEventHandles(int argc, wchar_t** argv) {
+ static int state = BEFORE_INIT;
+ static std::vector<HANDLE> to_check;
+
+ switch (state++) {
+ case BEFORE_INIT:
+ // Create a unique marker file that is open while the test is running.
+ for (const wchar_t* kExtension : kFileExtensions) {
+ HANDLE handle = GetMarkerFile(kExtension);
+ CHECK_NE(handle, INVALID_HANDLE_VALUE);
+ to_check.push_back(handle);
+ }
+ return SBOX_TEST_SUCCEEDED;
+
+ case AFTER_REVERT:
+ for (HANDLE handle : to_check) {
+ // Set up buffers for the type info and the name.
+ std::vector<BYTE> type_info_buffer(sizeof(OBJECT_TYPE_INFORMATION) +
+ 32 * sizeof(wchar_t));
+ OBJECT_TYPE_INFORMATION* type_info =
+ reinterpret_cast<OBJECT_TYPE_INFORMATION*>(&(type_info_buffer[0]));
+ NTSTATUS rc;
+
+ // Get the type name, reusing the buffer.
+ ULONG size = static_cast<ULONG>(type_info_buffer.size());
+ rc = QueryObjectTypeInformation(handle, type_info, &size);
+ while (rc == STATUS_INFO_LENGTH_MISMATCH ||
+ rc == STATUS_BUFFER_OVERFLOW) {
+ type_info_buffer.resize(size + sizeof(wchar_t));
+ type_info = reinterpret_cast<OBJECT_TYPE_INFORMATION*>(
+ &(type_info_buffer[0]));
+ rc = QueryObjectTypeInformation(handle, type_info, &size);
+ // Leave padding for the nul terminator.
+ if (NT_SUCCESS(rc) && size == type_info_buffer.size())
+ rc = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ CHECK(NT_SUCCESS(rc));
+ CHECK(type_info->Name.Buffer);
+
+ type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] =
+ L'\0';
+
+ // Should be an Event now.
+ CHECK_EQ(wcslen(type_info->Name.Buffer), 5U);
+ CHECK_EQ(wcscmp(L"Event", type_info->Name.Buffer), 0);
+
+ // Should not be able to wait.
+ CHECK_EQ(WaitForSingleObject(handle, INFINITE), WAIT_FAILED);
+
+ // Should be able to close.
+ CHECK(::CloseHandle(handle));
+ }
+ return SBOX_TEST_SUCCEEDED;
+
+ default: // Do nothing.
+ break;
+ }
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(HandleCloserTest, CheckForMarkerFiles) {
+ TestRunner runner;
+ runner.SetTimeout(2000);
+ runner.SetTestState(EVERY_STATE);
+
+ std::wstring command = std::wstring(L"CheckForFileHandles Y");
+ for (const wchar_t* kExtension : kFileExtensions) {
+ std::wstring handle_name;
+ base::win::ScopedHandle marker(GetMarkerFile(kExtension));
+ CHECK(marker.IsValid());
+ CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
+ command += (L" ");
+ command += handle_name;
+ }
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str()))
+ << "Failed: " << command;
+}
+
+TEST(HandleCloserTest, CloseMarkerFiles) {
+ TestRunner runner;
+ runner.SetTimeout(2000);
+ runner.SetTestState(EVERY_STATE);
+ sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+ std::wstring command = std::wstring(L"CheckForFileHandles N");
+ for (const wchar_t* kExtension : kFileExtensions) {
+ std::wstring handle_name;
+ base::win::ScopedHandle marker(GetMarkerFile(kExtension));
+ CHECK(marker.IsValid());
+ CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
+ CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
+ SBOX_ALL_OK);
+ command += (L" ");
+ command += handle_name;
+ }
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str()))
+ << "Failed: " << command;
+}
+
+TEST(HandleCloserTest, CheckStuffedHandle) {
+ TestRunner runner;
+ runner.SetTimeout(2000);
+ runner.SetTestState(EVERY_STATE);
+ sandbox::TargetPolicy* policy = runner.GetPolicy();
+
+ for (const wchar_t* kExtension : kFileExtensions) {
+ std::wstring handle_name;
+ base::win::ScopedHandle marker(GetMarkerFile(kExtension));
+ CHECK(marker.IsValid());
+ CHECK(sandbox::GetHandleName(marker.Get(), &handle_name));
+ CHECK_EQ(policy->AddKernelObjectToClose(L"File", handle_name.c_str()),
+ SBOX_ALL_OK);
+ }
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckForEventHandles"));
+}
+
+void WINAPI ThreadPoolTask(void* event, BOOLEAN timeout) {
+ static volatile LONG waiters_remaining = kWaitCount;
+ CHECK(!timeout);
+ CHECK(::CloseHandle(event));
+ if (::InterlockedDecrement(&waiters_remaining) == 0)
+ CHECK(::SetEvent(finish_event));
+}
+
+// Run a thread pool inside a sandbox without a CSRSS connection.
+SBOX_TESTS_COMMAND int RunThreadPool(int argc, wchar_t** argv) {
+ HANDLE wait_list[20];
+ finish_event = ::CreateEvent(nullptr, true, false, nullptr);
+ CHECK(finish_event);
+
+ // Set up a bunch of waiters.
+ HANDLE pool = nullptr;
+ for (int i = 0; i < kWaitCount; ++i) {
+ HANDLE event = ::CreateEvent(nullptr, true, false, nullptr);
+ CHECK(event);
+ CHECK(::RegisterWaitForSingleObject(&pool, event, ThreadPoolTask, event,
+ INFINITE, WT_EXECUTEONLYONCE));
+ wait_list[i] = event;
+ }
+
+ // Signal all the waiters.
+ for (int i = 0; i < kWaitCount; ++i)
+ CHECK(::SetEvent(wait_list[i]));
+
+ CHECK_EQ(::WaitForSingleObject(finish_event, INFINITE), WAIT_OBJECT_0);
+ CHECK(::CloseHandle(finish_event));
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(HandleCloserTest, RunThreadPool) {
+ TestRunner runner;
+ runner.SetTimeout(2000);
+ runner.SetTestState(AFTER_REVERT);
+
+ // Sandbox policy will determine which platforms to disconnect CSRSS and when
+ // to close the CSRSS handle.
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"RunThreadPool"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc
new file mode 100644
index 0000000000..611e33d2a6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_dispatcher.h"
+
+#include <stdint.h>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/handle_interception.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+
+namespace sandbox {
+
+HandleDispatcher::HandleDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall duplicate_handle_proxy = {
+ {IpcTag::DUPLICATEHANDLEPROXY,
+ {VOIDPTR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &HandleDispatcher::DuplicateHandleProxy)};
+
+ ipc_calls_.push_back(duplicate_handle_proxy);
+}
+
+bool HandleDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ // We perform no interceptions for handles right now.
+ switch (service) {
+ case IpcTag::DUPLICATEHANDLEPROXY:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+bool HandleDispatcher::DuplicateHandleProxy(IPCInfo* ipc,
+ HANDLE source_handle,
+ uint32_t target_process_id,
+ uint32_t desired_access,
+ uint32_t options) {
+ static NtQueryObject QueryObject = NULL;
+ if (!QueryObject)
+ ResolveNTFunctionPtr("NtQueryObject", &QueryObject);
+
+ // Get a copy of the handle for use in the broker process.
+ HANDLE handle_temp;
+ if (!::DuplicateHandle(ipc->client_info->process, source_handle,
+ ::GetCurrentProcess(), &handle_temp,
+ 0, FALSE, DUPLICATE_SAME_ACCESS | options)) {
+ ipc->return_info.win32_result = ::GetLastError();
+ return false;
+ }
+ options &= ~DUPLICATE_CLOSE_SOURCE;
+ base::win::ScopedHandle handle(handle_temp);
+
+ // Get the object type (32 characters is safe; current max is 14).
+ BYTE buffer[sizeof(OBJECT_TYPE_INFORMATION) + 32 * sizeof(wchar_t)];
+ OBJECT_TYPE_INFORMATION* type_info =
+ reinterpret_cast<OBJECT_TYPE_INFORMATION*>(buffer);
+ ULONG size = sizeof(buffer) - sizeof(wchar_t);
+ NTSTATUS error =
+ QueryObject(handle.Get(), ObjectTypeInformation, type_info, size, &size);
+ if (!NT_SUCCESS(error)) {
+ ipc->return_info.nt_status = error;
+ return false;
+ }
+ type_info->Name.Buffer[type_info->Name.Length / sizeof(wchar_t)] = L'\0';
+
+ CountedParameterSet<HandleTarget> params;
+ params[HandleTarget::NAME] = ParamPickerMake(type_info->Name.Buffer);
+ params[HandleTarget::TARGET] = ParamPickerMake(target_process_id);
+
+ EvalResult eval = policy_base_->EvalPolicy(IpcTag::DUPLICATEHANDLEPROXY,
+ params.GetBase());
+ ipc->return_info.win32_result =
+ HandlePolicy::DuplicateHandleProxyAction(eval, handle.Get(),
+ target_process_id,
+ &ipc->return_info.handle,
+ desired_access, options);
+ return true;
+}
+
+} // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.h
new file mode 100644
index 0000000000..6f9adbc10b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_DISPATCHER_H_
+#define SANDBOX_SRC_HANDLE_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles handle-related IPC calls.
+class HandleDispatcher : public Dispatcher {
+ public:
+ explicit HandleDispatcher(PolicyBase* policy_base);
+ ~HandleDispatcher() override {}
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to
+ // TargetServices::DuplicateHandle() in the target.
+ bool DuplicateHandleProxy(IPCInfo* ipc,
+ HANDLE source_handle,
+ uint32_t target_process_id,
+ uint32_t desired_access,
+ uint32_t options);
+
+ PolicyBase* policy_base_;
+ DISALLOW_COPY_AND_ASSIGN(HandleDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_HANDLE_DISPATCHER_H_
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_inheritance_test.cc b/security/sandbox/chromium/sandbox/win/src/handle_inheritance_test.cc
new file mode 100644
index 0000000000..c91903c809
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_inheritance_test.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int HandleInheritanceTests_PrintToStdout(int argc,
+ wchar_t** argv) {
+ printf("Example output to stdout\n");
+ return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(HandleInheritanceTests, TestStdoutInheritance) {
+ base::ScopedTempDir temp_directory;
+ base::FilePath temp_file_name;
+ ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ CreateTemporaryFileInDir(temp_directory.GetPath(), &temp_file_name));
+
+ SECURITY_ATTRIBUTES attrs = {};
+ attrs.nLength = sizeof(attrs);
+ attrs.bInheritHandle = true;
+ base::win::ScopedHandle tmp_handle(
+ CreateFile(temp_file_name.value().c_str(), GENERIC_WRITE,
+ FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, &attrs,
+ OPEN_EXISTING, 0, nullptr));
+ ASSERT_TRUE(tmp_handle.IsValid());
+
+ TestRunner runner;
+ ASSERT_EQ(SBOX_ALL_OK, runner.GetPolicy()->SetStdoutHandle(tmp_handle.Get()));
+ int result = runner.RunTest(L"HandleInheritanceTests_PrintToStdout");
+ ASSERT_EQ(SBOX_TEST_SUCCEEDED, result);
+
+ std::string data;
+ ASSERT_TRUE(base::ReadFileToString(base::FilePath(temp_file_name), &data));
+ // Redirection uses a feature that was added in Windows Vista.
+ ASSERT_EQ("Example output to stdout\r\n", data);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_interception.cc b/security/sandbox/chromium/sandbox/win/src/handle_interception.cc
new file mode 100644
index 0000000000..53db4a8b27
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_interception.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+
+namespace sandbox {
+
+ResultCode DuplicateHandleProxy(HANDLE source_handle,
+ DWORD target_process_id,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ DWORD options) {
+ *target_handle = NULL;
+
+ void* memory = GetGlobalIPCMemory();
+ if (NULL == memory)
+ return SBOX_ERROR_NO_SPACE;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::DUPLICATEHANDLEPROXY,
+ source_handle, target_process_id,
+ desired_access, options, &answer);
+ if (SBOX_ALL_OK != code)
+ return code;
+
+ if (answer.win32_result) {
+ ::SetLastError(answer.win32_result);
+ mozilla::sandboxing::LogBlocked("DuplicateHandle");
+ return SBOX_ERROR_GENERIC;
+ }
+
+ *target_handle = answer.handle;
+ mozilla::sandboxing::LogAllowed("DuplicateHandle");
+ return SBOX_ALL_OK;
+}
+
+} // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_interception.h b/security/sandbox/chromium/sandbox/win/src/handle_interception.h
new file mode 100644
index 0000000000..6f60811f17
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_interception.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+#ifndef SANDBOX_SRC_HANDLE_INTERCEPTION_H_
+#define SANDBOX_SRC_HANDLE_INTERCEPTION_H_
+
+namespace sandbox {
+
+// TODO(jschuh) Add an interception to catch dangerous DuplicateHandle calls.
+
+ResultCode DuplicateHandleProxy(HANDLE source_handle,
+ DWORD target_process_id,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ DWORD options);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_HANDLE_INTERCEPTION_H_
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_policy.cc b/security/sandbox/chromium/sandbox/win/src/handle_policy.cc
new file mode 100644
index 0000000000..fa3295ae3f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_policy.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/handle_policy.h"
+
+#include <string>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/broker_services.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+
+namespace sandbox {
+
+bool HandlePolicy::GenerateRules(const wchar_t* type_name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ PolicyRule duplicate_rule(ASK_BROKER);
+
+ switch (semantics) {
+ case TargetPolicy::HANDLES_DUP_ANY: {
+ if (!duplicate_rule.AddNumberMatch(IF_NOT, HandleTarget::TARGET,
+ ::GetCurrentProcessId(), EQUAL)) {
+ return false;
+ }
+ break;
+ }
+
+ case TargetPolicy::HANDLES_DUP_BROKER: {
+ if (!duplicate_rule.AddNumberMatch(IF, HandleTarget::TARGET,
+ ::GetCurrentProcessId(), EQUAL)) {
+ return false;
+ }
+ break;
+ }
+
+ default:
+ return false;
+ }
+ if (!duplicate_rule.AddStringMatch(IF, HandleTarget::NAME, type_name,
+ CASE_INSENSITIVE)) {
+ return false;
+ }
+ if (!policy->AddRule(IpcTag::DUPLICATEHANDLEPROXY, &duplicate_rule)) {
+ return false;
+ }
+ return true;
+}
+
+DWORD HandlePolicy::DuplicateHandleProxyAction(EvalResult eval_result,
+ HANDLE source_handle,
+ DWORD target_process_id,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ DWORD options) {
+ // The only action supported is ASK_BROKER which means duplicate the handle.
+ if (ASK_BROKER != eval_result) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ base::win::ScopedHandle remote_target_process;
+ if (target_process_id != ::GetCurrentProcessId()) {
+ // Sandboxed children are dynamic, so we check that manually.
+ if (!BrokerServicesBase::GetInstance()->IsSafeDuplicationTarget(
+ target_process_id)) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ remote_target_process.Set(::OpenProcess(PROCESS_DUP_HANDLE, FALSE,
+ target_process_id));
+ if (!remote_target_process.IsValid())
+ return ::GetLastError();
+ }
+
+ // If the policy didn't block us and we have no valid target, then the broker
+ // (this process) is the valid target.
+ HANDLE target_process = remote_target_process.IsValid() ?
+ remote_target_process.Get() : ::GetCurrentProcess();
+ if (!::DuplicateHandle(::GetCurrentProcess(), source_handle, target_process,
+ target_handle, desired_access, FALSE,
+ options)) {
+ return ::GetLastError();
+ }
+
+ return ERROR_SUCCESS;
+}
+
+} // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_policy.h b/security/sandbox/chromium/sandbox/win/src/handle_policy.h
new file mode 100644
index 0000000000..29ce5ab666
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_policy.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_HANDLE_POLICY_H_
+#define SANDBOX_SRC_HANDLE_POLICY_H_
+
+#include <string>
+
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+enum EvalResult;
+
+// This class centralizes most of the knowledge related to handle policy.
+class HandlePolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level
+ // policy rule for handles, in particular duplicate action.
+ static bool GenerateRules(const wchar_t* type_name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ // Processes a 'TargetPolicy::DuplicateHandle()' request from the target.
+ static DWORD DuplicateHandleProxyAction(EvalResult eval_result,
+ HANDLE source_handle,
+ DWORD target_process_id,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ DWORD options);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_HANDLE_POLICY_H_
+
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_policy_test.cc b/security/sandbox/chromium/sandbox/win/src/handle_policy_test.cc
new file mode 100644
index 0000000000..11382da811
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/handle_policy_test.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Just waits for the supplied number of milliseconds.
+SBOX_TESTS_COMMAND int Handle_WaitProcess(int argc, wchar_t **argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ ::Sleep(::wcstoul(argv[0], NULL, 10));
+ return SBOX_TEST_TIMED_OUT;
+}
+
+// Attempts to duplicate an event handle into the target process.
+SBOX_TESTS_COMMAND int Handle_DuplicateEvent(int argc, wchar_t **argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ // Create a test event to use as a handle.
+ base::win::ScopedHandle test_event;
+ test_event.Set(::CreateEvent(NULL, TRUE, TRUE, NULL));
+ if (!test_event.IsValid())
+ return SBOX_TEST_FIRST_ERROR;
+
+ // Get the target process ID.
+ DWORD target_process_id = ::wcstoul(argv[0], NULL, 10);
+
+ HANDLE handle = NULL;
+ ResultCode result = SandboxFactory::GetTargetServices()->DuplicateHandle(
+ test_event.Get(), target_process_id, &handle, 0, DUPLICATE_SAME_ACCESS);
+
+ return (result == SBOX_ALL_OK) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_DENIED;
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicateHandle) {
+ TestRunner target;
+ TestRunner runner;
+
+ // Kick off an asynchronous target process for testing.
+ target.SetAsynchronous(true);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"Handle_WaitProcess 30000"));
+
+ // First test that we fail to open the event.
+ base::string16 cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d",
+ target.process_id());
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+ // Now successfully open the event after adding a duplicate handle rule.
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+ TargetPolicy::HANDLES_DUP_ANY,
+ L"Event"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicatePeerHandle) {
+ TestRunner target;
+ TestRunner runner;
+
+ // Kick off an asynchronous target process for testing.
+ target.SetAsynchronous(true);
+ target.SetUnsandboxed(true);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, target.RunTest(L"Handle_WaitProcess 30000"));
+
+ // First test that we fail to open the event.
+ base::string16 cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d",
+ target.process_id());
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+ // Now successfully open the event after adding a duplicate handle rule.
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+ TargetPolicy::HANDLES_DUP_ANY,
+ L"Event"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+}
+
+// Tests that duplicating an object works only when the policy allows it.
+TEST(HandlePolicyTest, DuplicateBrokerHandle) {
+ TestRunner runner;
+
+ // First test that we fail to open the event.
+ base::string16 cmd_line = base::StringPrintf(L"Handle_DuplicateEvent %d",
+ ::GetCurrentProcessId());
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+ // Add the peer rule and make sure we fail again.
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+ TargetPolicy::HANDLES_DUP_ANY,
+ L"Event"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(cmd_line.c_str()));
+
+
+ // Now successfully open the event after adding a broker handle rule.
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_HANDLES,
+ TargetPolicy::HANDLES_DUP_BROKER,
+ L"Event"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(cmd_line.c_str()));
+}
+
+} // namespace sandbox
+
diff --git a/security/sandbox/chromium/sandbox/win/src/heap_helper.cc b/security/sandbox/chromium/sandbox/win/src/heap_helper.cc
new file mode 100644
index 0000000000..b0f4498fea
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/heap_helper.cc
@@ -0,0 +1,124 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/heap_helper.h"
+
+#include <windows.h>
+
+#include "base/memory/ref_counted.h"
+#include "base/win/windows_version.h"
+
+namespace sandbox {
+namespace {
+#pragma pack(1)
+
+// These are undocumented, but readily found on the internet.
+constexpr DWORD kHeapClass8 = 0x00008000; // CSR port heap
+constexpr DWORD kHeapClassMask = 0x0000f000;
+
+constexpr DWORD kHeapSegmentSignature = 0xffeeffee;
+constexpr DWORD kHeapSignature = 0xeeffeeff;
+
+typedef struct _HEAP_ENTRY {
+ PVOID Data1;
+ PVOID Data2;
+} HEAP_ENTRY, *PHEAP_ENTRY;
+
+// The _HEAP struct is not documented, so char arrays are used to space out the
+// struct of the fields that are not relevant. However, this spacing is
+// different because of the different pointer widths between 32 and 64-bit.
+// So 32 and 64 bit structs are defined.
+struct _HEAP_32 {
+ HEAP_ENTRY HeapEntry;
+ DWORD SegmentSignature;
+ DWORD SegmentFlags;
+ LIST_ENTRY SegmentListEntry;
+ struct _HEAP_32* Heap;
+ char Unknown0[0x24];
+ // Offset 0x40
+ DWORD Flags;
+ // Offset 0x60
+ char Unknown1[0x1c];
+ DWORD Signature;
+ // Other stuff that is not relevant.
+};
+
+struct _HEAP_64 {
+ HEAP_ENTRY HeapEntry;
+ DWORD SegmentSignature;
+ DWORD SegmentFlags;
+ LIST_ENTRY SegmentListEntry;
+ struct _HEAP_64* Heap;
+ char Unknown0[0x40];
+ // Offset 0x70
+ DWORD Flags;
+ // Offset 0x98
+ char Unknown1[0x24];
+ DWORD Signature;
+ // Other stuff that is not relevant.
+};
+
+#if defined(_WIN64)
+using _HEAP = _HEAP_64;
+#else // defined(_WIN64)
+using _HEAP = _HEAP_32;
+#endif // defined(_WIN64)
+
+bool ValidateHeap(_HEAP* heap) {
+ if (heap->SegmentSignature != kHeapSegmentSignature)
+ return false;
+ if (heap->Heap != heap)
+ return false;
+ if (heap->Signature != kHeapSignature)
+ return false;
+ return true;
+}
+
+} // namespace
+
+bool HeapFlags(HANDLE handle, DWORD* flags) {
+ if (!handle || !flags) {
+ // This is an error.
+ return false;
+ }
+ _HEAP* heap = reinterpret_cast<_HEAP*>(handle);
+ if (!ValidateHeap(heap)) {
+ DLOG(ERROR) << "unable to validate heap";
+ return false;
+ }
+ *flags = heap->Flags;
+ return true;
+}
+
+HANDLE FindCsrPortHeap() {
+ if (base::win::GetVersion() < base::win::Version::WIN10) {
+ // This functionality has not been verified on versions before Win10.
+ return nullptr;
+ }
+ DWORD number_of_heaps = ::GetProcessHeaps(0, nullptr);
+ std::unique_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]);
+ if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps)
+ return nullptr;
+
+ // Search for the CSR port heap handle, identified purely based on flags.
+ HANDLE csr_port_heap = nullptr;
+ for (size_t i = 0; i < number_of_heaps; ++i) {
+ HANDLE handle = all_heaps[i];
+ DWORD flags = 0;
+ if (!HeapFlags(handle, &flags)) {
+ DLOG(ERROR) << "Unable to get flags for this heap";
+ continue;
+ }
+ if ((flags & kHeapClassMask) == kHeapClass8) {
+ if (csr_port_heap) {
+ DLOG(ERROR) << "Found multiple suitable CSR Port heaps";
+ return nullptr;
+ }
+ csr_port_heap = handle;
+ }
+ }
+ return csr_port_heap;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/heap_helper.h b/security/sandbox/chromium/sandbox/win/src/heap_helper.h
new file mode 100644
index 0000000000..302a3c4e29
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/heap_helper.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_HEAP_HELPER_H_
+#define SANDBOX_WIN_SRC_HEAP_HELPER_H_
+
+#include <windows.h>
+
+#include "base/win/windows_version.h"
+
+namespace sandbox {
+// These helper functions are not expected to be used generally, but are exposed
+// only to allow direct testing of this functionality.
+
+// Return the flags for this heap handle. Limited verification of the handle is
+// performed. No verification of the flags is performed.
+bool HeapFlags(HANDLE handle, DWORD* flags);
+
+// Return the handle to the CSR Port Heap, return nullptr if none or more than
+// one candidate was found.
+HANDLE FindCsrPortHeap();
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_HEAP_HELPER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/integrity_level_test.cc b/security/sandbox/chromium/sandbox/win/src/integrity_level_test.cc
new file mode 100644
index 0000000000..a4788af028
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/integrity_level_test.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include <atlsecurity.h>
+
+#include "base/process/process_info.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int CheckUntrustedIntegrityLevel(int argc, wchar_t** argv) {
+ return (base::GetCurrentProcessIntegrityLevel() == base::UNTRUSTED_INTEGRITY)
+ ? SBOX_TEST_SUCCEEDED
+ : SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int CheckLowIntegrityLevel(int argc, wchar_t** argv) {
+ return (base::GetCurrentProcessIntegrityLevel() == base::LOW_INTEGRITY)
+ ? SBOX_TEST_SUCCEEDED
+ : SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int CheckIntegrityLevel(int argc, wchar_t** argv) {
+ ATL::CAccessToken token;
+ if (!token.GetEffectiveToken(TOKEN_READ))
+ return SBOX_TEST_FAILED;
+
+ char* buffer[100];
+ DWORD buf_size = 100;
+ if (!::GetTokenInformation(token.GetHandle(), TokenIntegrityLevel,
+ reinterpret_cast<void*>(buffer), buf_size,
+ &buf_size))
+ return SBOX_TEST_FAILED;
+
+ TOKEN_MANDATORY_LABEL* label =
+ reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buffer);
+
+ PSID sid_low = nullptr;
+ if (!::ConvertStringSidToSid(L"S-1-16-4096", &sid_low))
+ return SBOX_TEST_FAILED;
+
+ bool is_low_sid = ::EqualSid(label->Label.Sid, sid_low);
+
+ ::LocalFree(sid_low);
+
+ if (is_low_sid)
+ return SBOX_TEST_SUCCEEDED;
+
+ return SBOX_TEST_DENIED;
+}
+
+TEST(IntegrityLevelTest, TestLowILReal) {
+ TestRunner runner(JOB_LOCKDOWN, USER_INTERACTIVE, USER_INTERACTIVE);
+
+ runner.SetTimeout(INFINITE);
+
+ runner.GetPolicy()->SetAlternateDesktop(true);
+ runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIntegrityLevel"));
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIntegrityLevel"));
+}
+
+TEST(DelayedIntegrityLevelTest, TestLowILDelayed) {
+ TestRunner runner(JOB_LOCKDOWN, USER_INTERACTIVE, USER_INTERACTIVE);
+
+ runner.SetTimeout(INFINITE);
+
+ runner.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_LOW);
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckIntegrityLevel"));
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"CheckIntegrityLevel"));
+}
+
+TEST(IntegrityLevelTest, TestNoILChange) {
+ TestRunner runner(JOB_LOCKDOWN, USER_INTERACTIVE, USER_INTERACTIVE);
+
+ runner.SetTimeout(INFINITE);
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"CheckIntegrityLevel"));
+}
+
+TEST(IntegrityLevelTest, TestUntrustedIL) {
+ TestRunner runner(JOB_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+ runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+ runner.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_UNTRUSTED);
+ runner.GetPolicy()->SetLockdownDefaultDacl();
+
+ runner.SetTimeout(INFINITE);
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"CheckUntrustedIntegrityLevel"));
+}
+
+TEST(IntegrityLevelTest, TestLowIL) {
+ TestRunner runner(JOB_LOCKDOWN, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+ runner.GetPolicy()->SetIntegrityLevel(INTEGRITY_LEVEL_LOW);
+ runner.GetPolicy()->SetDelayedIntegrityLevel(INTEGRITY_LEVEL_LOW);
+ runner.GetPolicy()->SetLockdownDefaultDacl();
+
+ runner.SetTimeout(INFINITE);
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"CheckLowIntegrityLevel"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/interception.cc b/security/sandbox/chromium/sandbox/win/src/interception.cc
new file mode 100644
index 0000000000..b2c0bc47ea
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interception.cc
@@ -0,0 +1,512 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// For information about interceptions as a whole see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#include "sandbox/win/src/interception.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/logging.h"
+#include "base/scoped_native_library.h"
+#include "base/win/pe_image.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_rand.h"
+#include "sandbox/win/src/service_resolver.h"
+#include "sandbox/win/src/target_interceptions.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+// Standard allocation granularity and page size for Windows.
+const size_t kAllocGranularity = 65536;
+const size_t kPageSize = 4096;
+
+} // namespace
+
+namespace internal {
+
+// Find a random offset within 64k and aligned to ceil(log2(size)).
+size_t GetGranularAlignedRandomOffset(size_t size) {
+ CHECK_LE(size, kAllocGranularity);
+ unsigned int offset;
+
+ do {
+ GetRandom(&offset);
+ offset &= (kAllocGranularity - 1);
+ } while (offset > (kAllocGranularity - size));
+
+ // Find an alignment between 64 and the page size (4096).
+ size_t align_size = kPageSize;
+ for (size_t new_size = align_size / 2; new_size >= size; new_size /= 2) {
+ align_size = new_size;
+ }
+ return offset & ~(align_size - 1);
+}
+
+} // namespace internal
+
+SANDBOX_INTERCEPT SharedMemory* g_interceptions;
+
+// Table of the unpatched functions that we intercept. Mapped from the parent.
+SANDBOX_INTERCEPT OriginalFunctions g_originals = {nullptr};
+
+// Magic constant that identifies that this function is not to be patched.
+const char kUnloadDLLDummyFunction[] = "@";
+
+InterceptionManager::InterceptionData::InterceptionData() {}
+
+InterceptionManager::InterceptionData::InterceptionData(
+ const InterceptionData& other) = default;
+
+InterceptionManager::InterceptionData::~InterceptionData() {}
+
+InterceptionManager::InterceptionManager(TargetProcess* child_process,
+ bool relaxed)
+ : child_(child_process), names_used_(false), relaxed_(relaxed) {
+ child_->AddRef();
+}
+InterceptionManager::~InterceptionManager() {
+ child_->Release();
+}
+
+bool InterceptionManager::AddToPatchedFunctions(
+ const wchar_t* dll_name,
+ const char* function_name,
+ InterceptionType interception_type,
+ const void* replacement_code_address,
+ InterceptorId id) {
+ InterceptionData function;
+ function.type = interception_type;
+ function.id = id;
+ function.dll = dll_name;
+ function.function = function_name;
+ function.interceptor_address = replacement_code_address;
+
+ interceptions_.push_back(function);
+ return true;
+}
+
+bool InterceptionManager::AddToPatchedFunctions(
+ const wchar_t* dll_name,
+ const char* function_name,
+ InterceptionType interception_type,
+ const char* replacement_function_name,
+ InterceptorId id) {
+ InterceptionData function;
+ function.type = interception_type;
+ function.id = id;
+ function.dll = dll_name;
+ function.function = function_name;
+ function.interceptor = replacement_function_name;
+ function.interceptor_address = nullptr;
+
+ interceptions_.push_back(function);
+ names_used_ = true;
+ return true;
+}
+
+bool InterceptionManager::AddToUnloadModules(const wchar_t* dll_name) {
+ InterceptionData module_to_unload;
+ module_to_unload.type = INTERCEPTION_UNLOAD_MODULE;
+ module_to_unload.dll = dll_name;
+ // The next two are dummy values that make the structures regular, instead
+ // of having special cases. They should not be used.
+ module_to_unload.function = kUnloadDLLDummyFunction;
+ module_to_unload.interceptor_address = reinterpret_cast<void*>(1);
+
+ interceptions_.push_back(module_to_unload);
+ return true;
+}
+
+ResultCode InterceptionManager::InitializeInterceptions() {
+ if (interceptions_.empty())
+ return SBOX_ALL_OK; // Nothing to do here
+
+ size_t buffer_bytes = GetBufferSize();
+ std::unique_ptr<char[]> local_buffer(new char[buffer_bytes]);
+
+ if (!SetupConfigBuffer(local_buffer.get(), buffer_bytes))
+ return SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_CONFIG_BUFFER;
+
+ void* remote_buffer;
+ if (!CopyToChildMemory(child_->Process(), local_buffer.get(), buffer_bytes,
+ &remote_buffer))
+ return SBOX_ERROR_CANNOT_COPY_DATA_TO_CHILD;
+
+ bool hot_patch_needed = (0 != buffer_bytes);
+ ResultCode rc = PatchNtdll(hot_patch_needed);
+
+ if (rc != SBOX_ALL_OK)
+ return rc;
+
+ g_interceptions = reinterpret_cast<SharedMemory*>(remote_buffer);
+ rc = child_->TransferVariable("g_interceptions", &g_interceptions,
+ sizeof(g_interceptions));
+ return rc;
+}
+
+size_t InterceptionManager::GetBufferSize() const {
+ std::set<std::wstring> dlls;
+ size_t buffer_bytes = 0;
+
+ for (const auto& interception : interceptions_) {
+ // skip interceptions that are performed from the parent
+ if (!IsInterceptionPerformedByChild(interception))
+ continue;
+
+ if (!dlls.count(interception.dll)) {
+ // NULL terminate the dll name on the structure
+ size_t dll_name_bytes = (interception.dll.size() + 1) * sizeof(wchar_t);
+
+ // include the dll related size
+ buffer_bytes += RoundUpToMultiple(
+ offsetof(DllPatchInfo, dll_name) + dll_name_bytes, sizeof(size_t));
+ dlls.insert(interception.dll);
+ }
+
+ // we have to NULL terminate the strings on the structure
+ size_t strings_chars =
+ interception.function.size() + interception.interceptor.size() + 2;
+
+ // a new FunctionInfo is required per function
+ size_t record_bytes = offsetof(FunctionInfo, function) + strings_chars;
+ record_bytes = RoundUpToMultiple(record_bytes, sizeof(size_t));
+ buffer_bytes += record_bytes;
+ }
+
+ if (0 != buffer_bytes)
+ // add the part of SharedMemory that we have not counted yet
+ buffer_bytes += offsetof(SharedMemory, dll_list);
+
+ return buffer_bytes;
+}
+
+// Basically, walk the list of interceptions moving them to the config buffer,
+// but keeping together all interceptions that belong to the same dll.
+// The config buffer is a local buffer, not the one allocated on the child.
+bool InterceptionManager::SetupConfigBuffer(void* buffer, size_t buffer_bytes) {
+ if (0 == buffer_bytes)
+ return true;
+
+ DCHECK(buffer_bytes > sizeof(SharedMemory));
+
+ SharedMemory* shared_memory = reinterpret_cast<SharedMemory*>(buffer);
+ DllPatchInfo* dll_info = shared_memory->dll_list;
+ int num_dlls = 0;
+
+ shared_memory->interceptor_base =
+ names_used_ ? child_->MainModule() : nullptr;
+
+ buffer_bytes -= offsetof(SharedMemory, dll_list);
+ buffer = dll_info;
+
+ std::list<InterceptionData>::iterator it = interceptions_.begin();
+ for (; it != interceptions_.end();) {
+ // skip interceptions that are performed from the parent
+ if (!IsInterceptionPerformedByChild(*it)) {
+ ++it;
+ continue;
+ }
+
+ const std::wstring dll = it->dll;
+ if (!SetupDllInfo(*it, &buffer, &buffer_bytes))
+ return false;
+
+ // walk the interceptions from this point, saving the ones that are
+ // performed on this dll, and removing the entry from the list.
+ // advance the iterator before removing the element from the list
+ std::list<InterceptionData>::iterator rest = it;
+ for (; rest != interceptions_.end();) {
+ if (rest->dll == dll) {
+ if (!SetupInterceptionInfo(*rest, &buffer, &buffer_bytes, dll_info))
+ return false;
+ if (it == rest)
+ ++it;
+ rest = interceptions_.erase(rest);
+ } else {
+ ++rest;
+ }
+ }
+ dll_info = reinterpret_cast<DllPatchInfo*>(buffer);
+ ++num_dlls;
+ }
+
+ shared_memory->num_intercepted_dlls = num_dlls;
+ return true;
+}
+
+// Fills up just the part that depends on the dll, not the info that depends on
+// the actual interception.
+bool InterceptionManager::SetupDllInfo(const InterceptionData& data,
+ void** buffer,
+ size_t* buffer_bytes) const {
+ DCHECK(buffer_bytes);
+ DCHECK(buffer);
+ DCHECK(*buffer);
+
+ DllPatchInfo* dll_info = reinterpret_cast<DllPatchInfo*>(*buffer);
+
+ // the strings have to be zero terminated
+ size_t required = offsetof(DllPatchInfo, dll_name) +
+ (data.dll.size() + 1) * sizeof(wchar_t);
+ required = RoundUpToMultiple(required, sizeof(size_t));
+ if (*buffer_bytes < required)
+ return false;
+
+ *buffer_bytes -= required;
+ *buffer = reinterpret_cast<char*>(*buffer) + required;
+
+ // set up the dll info to be what we know about it at this time
+ dll_info->unload_module = (data.type == INTERCEPTION_UNLOAD_MODULE);
+ dll_info->record_bytes = required;
+ dll_info->offset_to_functions = required;
+ dll_info->num_functions = 0;
+ data.dll.copy(dll_info->dll_name, data.dll.size());
+ dll_info->dll_name[data.dll.size()] = L'\0';
+
+ return true;
+}
+
+bool InterceptionManager::SetupInterceptionInfo(const InterceptionData& data,
+ void** buffer,
+ size_t* buffer_bytes,
+ DllPatchInfo* dll_info) const {
+ DCHECK(buffer_bytes);
+ DCHECK(buffer);
+ DCHECK(*buffer);
+
+ if ((dll_info->unload_module) && (data.function != kUnloadDLLDummyFunction)) {
+ // Can't specify a dll for both patch and unload.
+ NOTREACHED();
+ }
+
+ FunctionInfo* function = reinterpret_cast<FunctionInfo*>(*buffer);
+
+ size_t name_bytes = data.function.size();
+ size_t interceptor_bytes = data.interceptor.size();
+
+ // the strings at the end of the structure are zero terminated
+ size_t required =
+ offsetof(FunctionInfo, function) + name_bytes + interceptor_bytes + 2;
+ required = RoundUpToMultiple(required, sizeof(size_t));
+ if (*buffer_bytes < required)
+ return false;
+
+ // update the caller's values
+ *buffer_bytes -= required;
+ *buffer = reinterpret_cast<char*>(*buffer) + required;
+
+ function->record_bytes = required;
+ function->type = data.type;
+ function->id = data.id;
+ function->interceptor_address = data.interceptor_address;
+ char* names = function->function;
+
+ data.function.copy(names, name_bytes);
+ names += name_bytes;
+ *names++ = '\0';
+
+ // interceptor follows the function_name
+ data.interceptor.copy(names, interceptor_bytes);
+ names += interceptor_bytes;
+ *names++ = '\0';
+
+ // update the dll table
+ dll_info->num_functions++;
+ dll_info->record_bytes += required;
+
+ return true;
+}
+
+// Only return true if the child should be able to perform this interception.
+bool InterceptionManager::IsInterceptionPerformedByChild(
+ const InterceptionData& data) const {
+ if (INTERCEPTION_INVALID == data.type)
+ return false;
+
+ if (INTERCEPTION_SERVICE_CALL == data.type)
+ return false;
+
+ if (data.type >= INTERCEPTION_LAST)
+ return false;
+
+ std::wstring ntdll(kNtdllName);
+ if (ntdll == data.dll)
+ return false; // ntdll has to be intercepted from the parent
+
+ return true;
+}
+
+ResultCode InterceptionManager::PatchNtdll(bool hot_patch_needed) {
+ // Maybe there is nothing to do
+ if (!hot_patch_needed && interceptions_.empty())
+ return SBOX_ALL_OK;
+
+ if (hot_patch_needed) {
+#if defined(SANDBOX_EXPORTS)
+// Make sure the functions are not excluded by the linker.
+#if defined(_WIN64)
+#pragma comment(linker, "/include:TargetNtMapViewOfSection64")
+#pragma comment(linker, "/include:TargetNtUnmapViewOfSection64")
+#else
+#pragma comment(linker, "/include:_TargetNtMapViewOfSection@44")
+#pragma comment(linker, "/include:_TargetNtUnmapViewOfSection@12")
+#endif
+#endif // defined(SANDBOX_EXPORTS)
+ ADD_NT_INTERCEPTION(NtMapViewOfSection, MAP_VIEW_OF_SECTION_ID, 44);
+ ADD_NT_INTERCEPTION(NtUnmapViewOfSection, UNMAP_VIEW_OF_SECTION_ID, 12);
+ }
+
+ // Reserve a full 64k memory range in the child process.
+ HANDLE child = child_->Process();
+ BYTE* thunk_base = reinterpret_cast<BYTE*>(::VirtualAllocEx(
+ child, nullptr, kAllocGranularity, MEM_RESERVE, PAGE_NOACCESS));
+
+ // Find an aligned, random location within the reserved range.
+ size_t thunk_bytes =
+ interceptions_.size() * sizeof(ThunkData) + sizeof(DllInterceptionData);
+ size_t thunk_offset = internal::GetGranularAlignedRandomOffset(thunk_bytes);
+
+ // Split the base and offset along page boundaries.
+ thunk_base += thunk_offset & ~(kPageSize - 1);
+ thunk_offset &= kPageSize - 1;
+
+ // Make an aligned, padded allocation, and move the pointer to our chunk.
+ size_t thunk_bytes_padded = (thunk_bytes + kPageSize - 1) & ~(kPageSize - 1);
+ thunk_base = reinterpret_cast<BYTE*>(
+ ::VirtualAllocEx(child, thunk_base, thunk_bytes_padded, MEM_COMMIT,
+ PAGE_EXECUTE_READWRITE));
+ CHECK(thunk_base); // If this fails we'd crash anyway on an invalid access.
+ DllInterceptionData* thunks =
+ reinterpret_cast<DllInterceptionData*>(thunk_base + thunk_offset);
+
+ DllInterceptionData dll_data;
+ dll_data.data_bytes = thunk_bytes;
+ dll_data.num_thunks = 0;
+ dll_data.used_bytes = offsetof(DllInterceptionData, thunks);
+
+ // Reset all helpers for a new child.
+ memset(g_originals, 0, sizeof(g_originals));
+
+ // this should write all the individual thunks to the child's memory
+ ResultCode rc = PatchClientFunctions(thunks, thunk_bytes, &dll_data);
+
+ if (rc != SBOX_ALL_OK)
+ return rc;
+
+ // and now write the first part of the table to the child's memory
+ SIZE_T written;
+ bool ok =
+ !!::WriteProcessMemory(child, thunks, &dll_data,
+ offsetof(DllInterceptionData, thunks), &written);
+
+ if (!ok || (offsetof(DllInterceptionData, thunks) != written))
+ return SBOX_ERROR_CANNOT_WRITE_INTERCEPTION_THUNK;
+
+ // Attempt to protect all the thunks, but ignore failure
+ DWORD old_protection;
+ ::VirtualProtectEx(child, thunks, thunk_bytes, PAGE_EXECUTE_READ,
+ &old_protection);
+
+ ResultCode ret =
+ child_->TransferVariable("g_originals", g_originals, sizeof(g_originals));
+ return ret;
+}
+
+ResultCode InterceptionManager::PatchClientFunctions(
+ DllInterceptionData* thunks,
+ size_t thunk_bytes,
+ DllInterceptionData* dll_data) {
+ DCHECK(thunks);
+ DCHECK(dll_data);
+
+ HMODULE ntdll_base = ::GetModuleHandle(kNtdllName);
+ if (!ntdll_base)
+ return SBOX_ERROR_NO_HANDLE;
+
+ char* interceptor_base = nullptr;
+
+#if defined(SANDBOX_EXPORTS)
+ interceptor_base = reinterpret_cast<char*>(child_->MainModule());
+ base::ScopedNativeLibrary local_interceptor(::LoadLibrary(child_->Name()));
+#endif // defined(SANDBOX_EXPORTS)
+
+ std::unique_ptr<ServiceResolverThunk> thunk;
+#if defined(_WIN64)
+ thunk.reset(new ServiceResolverThunk(child_->Process(), relaxed_));
+#else
+ base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+ if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
+ if (os_info->version() >= base::win::Version::WIN10)
+ thunk.reset(new Wow64W10ResolverThunk(child_->Process(), relaxed_));
+ else if (os_info->version() >= base::win::Version::WIN8)
+ thunk.reset(new Wow64W8ResolverThunk(child_->Process(), relaxed_));
+ else
+ thunk.reset(new Wow64ResolverThunk(child_->Process(), relaxed_));
+ } else if (os_info->version() >= base::win::Version::WIN8) {
+ thunk.reset(new Win8ResolverThunk(child_->Process(), relaxed_));
+ } else {
+ thunk.reset(new ServiceResolverThunk(child_->Process(), relaxed_));
+ }
+#endif
+
+ for (auto interception : interceptions_) {
+ const std::wstring ntdll(kNtdllName);
+ if (interception.dll != ntdll)
+ return SBOX_ERROR_BAD_PARAMS;
+
+ if (INTERCEPTION_SERVICE_CALL != interception.type)
+ return SBOX_ERROR_BAD_PARAMS;
+
+#if defined(SANDBOX_EXPORTS)
+ // We may be trying to patch by function name.
+ if (!interception.interceptor_address) {
+ const char* address;
+ NTSTATUS ret = thunk->ResolveInterceptor(
+ local_interceptor.get(), interception.interceptor.c_str(),
+ reinterpret_cast<const void**>(&address));
+ if (!NT_SUCCESS(ret)) {
+ ::SetLastError(GetLastErrorFromNtStatus(ret));
+ return SBOX_ERROR_CANNOT_RESOLVE_INTERCEPTION_THUNK;
+ }
+
+ // Translate the local address to an address on the child.
+ interception.interceptor_address =
+ interceptor_base +
+ (address - reinterpret_cast<char*>(local_interceptor.get()));
+ }
+#endif // defined(SANDBOX_EXPORTS)
+ NTSTATUS ret = thunk->Setup(
+ ntdll_base, interceptor_base, interception.function.c_str(),
+ interception.interceptor.c_str(), interception.interceptor_address,
+ &thunks->thunks[dll_data->num_thunks],
+ thunk_bytes - dll_data->used_bytes, nullptr);
+ if (!NT_SUCCESS(ret)) {
+ ::SetLastError(GetLastErrorFromNtStatus(ret));
+ return SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_THUNK;
+ }
+
+ DCHECK(!g_originals[interception.id]);
+ g_originals[interception.id] = &thunks->thunks[dll_data->num_thunks];
+
+ dll_data->num_thunks++;
+ dll_data->used_bytes += sizeof(ThunkData);
+ }
+
+ return SBOX_ALL_OK;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/interception.h b/security/sandbox/chromium/sandbox/win/src/interception.h
new file mode 100644
index 0000000000..6b4612fb6c
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interception.h
@@ -0,0 +1,290 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines InterceptionManager, the class in charge of setting up interceptions
+// for the sandboxed process. For more details see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#ifndef SANDBOX_SRC_INTERCEPTION_H_
+#define SANDBOX_SRC_INTERCEPTION_H_
+
+#include <stddef.h>
+
+#include <list>
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+class TargetProcess;
+
+// Internal structures used for communication between the broker and the target.
+struct DllPatchInfo;
+struct DllInterceptionData;
+
+// The InterceptionManager executes on the parent application, and it is in
+// charge of setting up the desired interceptions, and placing the Interception
+// Agent into the child application.
+//
+// The exposed API consists of two methods: AddToPatchedFunctions to set up a
+// particular interception, and InitializeInterceptions to actually go ahead and
+// perform all interceptions and transfer data to the child application.
+//
+// The typical usage is something like this:
+//
+// InterceptionManager interception_manager(child);
+// if (!interception_manager.AddToPatchedFunctions(
+// L"ntdll.dll", "NtCreateFile",
+// sandbox::INTERCEPTION_SERVICE_CALL, &MyNtCreateFile, MY_ID_1))
+// return false;
+//
+// if (!interception_manager.AddToPatchedFunctions(
+// L"kernel32.dll", "CreateDirectoryW",
+// sandbox::INTERCEPTION_EAT, L"MyCreateDirectoryW@12", MY_ID_2))
+// return false;
+//
+// sandbox::ResultCode rc = interception_manager.InitializeInterceptions();
+// if (rc != sandbox::SBOX_ALL_OK) {
+// DWORD error = ::GetLastError();
+// return rc;
+// }
+//
+// Any required syncronization must be performed outside this class. Also, it is
+// not possible to perform further interceptions after InitializeInterceptions
+// is called.
+//
+class InterceptionManager {
+ // The unit test will access private members.
+ // Allow tests to be marked DISABLED_. Note that FLAKY_ and FAILS_ prefixes
+ // do not work with sandbox tests.
+ FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout1);
+ FRIEND_TEST_ALL_PREFIXES(InterceptionManagerTest, BufferLayout2);
+
+ public:
+ // An interception manager performs interceptions on a given child process.
+ // If we are allowed to intercept functions that have been patched by somebody
+ // else, relaxed should be set to true.
+ // Note: We increase the child's reference count internally.
+ InterceptionManager(TargetProcess* child_process, bool relaxed);
+ ~InterceptionManager();
+
+ // Patches function_name inside dll_name to point to replacement_code_address.
+ // function_name has to be an exported symbol of dll_name.
+ // Returns true on success.
+ //
+ // The new function should match the prototype and calling convention of the
+ // function to intercept except for one extra argument (the first one) that
+ // contains a pointer to the original function, to simplify the development
+ // of interceptors (for IA32). In x64, there is no extra argument to the
+ // interceptor, so the provided InterceptorId is used to keep a table of
+ // intercepted functions so that the interceptor can index that table to get
+ // the pointer that would have been the first argument (g_originals[id]).
+ //
+ // For example, to intercept NtClose, the following code could be used:
+ //
+ // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle);
+ // NTSTATUS WINAPI MyNtCose(IN NtCloseFunction OriginalClose,
+ // IN HANDLE Handle) {
+ // // do something
+ // // call the original function
+ // return OriginalClose(Handle);
+ // }
+ //
+ // And in x64:
+ //
+ // typedef NTSTATUS (WINAPI *NtCloseFunction) (IN HANDLE Handle);
+ // NTSTATUS WINAPI MyNtCose64(IN HANDLE Handle) {
+ // // do something
+ // // call the original function
+ // NtCloseFunction OriginalClose = g_originals[NT_CLOSE_ID];
+ // return OriginalClose(Handle);
+ // }
+ bool AddToPatchedFunctions(const wchar_t* dll_name,
+ const char* function_name,
+ InterceptionType interception_type,
+ const void* replacement_code_address,
+ InterceptorId id);
+
+ // Patches function_name inside dll_name to point to
+ // replacement_function_name.
+ bool AddToPatchedFunctions(const wchar_t* dll_name,
+ const char* function_name,
+ InterceptionType interception_type,
+ const char* replacement_function_name,
+ InterceptorId id);
+
+ // The interception agent will unload the dll with dll_name.
+ bool AddToUnloadModules(const wchar_t* dll_name);
+
+ // Initializes all interceptions on the client.
+ // Returns SBOX_ALL_OK on success, or an appropriate error code.
+ //
+ // The child process must be created suspended, and cannot be resumed until
+ // after this method returns. In addition, no action should be performed on
+ // the child that may cause it to resume momentarily, such as injecting
+ // threads or APCs.
+ //
+ // This function must be called only once, after all interceptions have been
+ // set up using AddToPatchedFunctions.
+ ResultCode InitializeInterceptions();
+
+ private:
+ // Used to store the interception information until the actual set-up.
+ struct InterceptionData {
+ InterceptionData();
+ InterceptionData(const InterceptionData& other);
+ ~InterceptionData();
+
+ InterceptionType type; // Interception type.
+ InterceptorId id; // Interceptor id.
+ std::wstring dll; // Name of dll to intercept.
+ std::string function; // Name of function to intercept.
+ std::string interceptor; // Name of interceptor function.
+ const void* interceptor_address; // Interceptor's entry point.
+ };
+
+ // Calculates the size of the required configuration buffer.
+ size_t GetBufferSize() const;
+
+ // Rounds up the size of a given buffer, considering alignment (padding).
+ // value is the current size of the buffer, and alignment is specified in
+ // bytes.
+ static inline size_t RoundUpToMultiple(size_t value, size_t alignment) {
+ return ((value + alignment - 1) / alignment) * alignment;
+ }
+
+ // Sets up a given buffer with all the information that has to be transfered
+ // to the child.
+ // Returns true on success.
+ //
+ // The buffer size should be at least the value returned by GetBufferSize
+ bool SetupConfigBuffer(void* buffer, size_t buffer_bytes);
+
+ // Fills up the part of the transfer buffer that corresponds to information
+ // about one dll to patch.
+ // data is the first recorded interception for this dll.
+ // Returns true on success.
+ //
+ // On successful return, buffer will be advanced from it's current position
+ // to the point where the next block of configuration data should be written
+ // (the actual interception info), and the current size of the buffer will
+ // decrease to account the space used by this method.
+ bool SetupDllInfo(const InterceptionData& data,
+ void** buffer,
+ size_t* buffer_bytes) const;
+
+ // Fills up the part of the transfer buffer that corresponds to a single
+ // function to patch.
+ // dll_info points to the dll being updated with the interception stored on
+ // data. The buffer pointer and remaining size are updated by this call.
+ // Returns true on success.
+ bool SetupInterceptionInfo(const InterceptionData& data,
+ void** buffer,
+ size_t* buffer_bytes,
+ DllPatchInfo* dll_info) const;
+
+ // Returns true if this interception is to be performed by the child
+ // as opposed to from the parent.
+ bool IsInterceptionPerformedByChild(const InterceptionData& data) const;
+
+ // Allocates a buffer on the child's address space (returned on
+ // remote_buffer), and fills it with the contents of a local buffer.
+ // Returns SBOX_ALL_OK on success.
+ ResultCode CopyDataToChild(const void* local_buffer,
+ size_t buffer_bytes,
+ void** remote_buffer) const;
+
+ // Performs the cold patch (from the parent) of ntdll.
+ // Returns SBOX_ALL_OK on success.
+ //
+ // This method will insert additional interceptions to launch the interceptor
+ // agent on the child process, if there are additional interceptions to do.
+ ResultCode PatchNtdll(bool hot_patch_needed);
+
+ // Peforms the actual interceptions on ntdll.
+ // thunks is the memory to store all the thunks for this dll (on the child),
+ // and dll_data is a local buffer to hold global dll interception info.
+ // Returns SBOX_ALL_OK on success.
+ ResultCode PatchClientFunctions(DllInterceptionData* thunks,
+ size_t thunk_bytes,
+ DllInterceptionData* dll_data);
+
+ // The process to intercept.
+ TargetProcess* child_;
+ // Holds all interception info until the call to initialize (perform the
+ // actual patch).
+ std::list<InterceptionData> interceptions_;
+
+ // Keep track of patches added by name.
+ bool names_used_;
+
+ // true if we are allowed to patch already-patched functions.
+ bool relaxed_;
+
+ DISALLOW_COPY_AND_ASSIGN(InterceptionManager);
+};
+
+// This macro simply calls interception_manager.AddToPatchedFunctions with
+// the given service to intercept (INTERCEPTION_SERVICE_CALL), and assumes that
+// the interceptor is called "TargetXXX", where XXX is the name of the service.
+// Note that num_params is the number of bytes to pop out of the stack for
+// the exported interceptor, following the calling convention of a service call
+// (WINAPI = with the "C" underscore).
+#if SANDBOX_EXPORTS
+#if defined(_WIN64)
+#define MAKE_SERVICE_NAME(service, params) "Target" #service "64"
+#else
+#define MAKE_SERVICE_NAME(service, params) "_Target" #service "@" #params
+#endif
+
+#define ADD_NT_INTERCEPTION(service, id, num_params) \
+ AddToPatchedFunctions(kNtdllName, #service, \
+ sandbox::INTERCEPTION_SERVICE_CALL, \
+ MAKE_SERVICE_NAME(service, num_params), id)
+
+#define INTERCEPT_NT(manager, service, id, num_params) \
+ ((&Target##service) ? manager->ADD_NT_INTERCEPTION(service, id, num_params) \
+ : false)
+
+// When intercepting the EAT it is important that the patched version of the
+// function not call any functions imported from system libraries unless
+// |TargetServices::InitCalled()| returns true, because it is only then that
+// we are guaranteed that our IAT has been initialized.
+#define INTERCEPT_EAT(manager, dll, function, id, num_params) \
+ ((&Target##function) ? manager->AddToPatchedFunctions( \
+ dll, #function, sandbox::INTERCEPTION_EAT, \
+ MAKE_SERVICE_NAME(function, num_params), id) \
+ : false)
+#else // SANDBOX_EXPORTS
+#if defined(_WIN64)
+#define MAKE_SERVICE_NAME(service) &Target##service##64
+#else
+#define MAKE_SERVICE_NAME(service) &Target##service
+#endif
+
+#define ADD_NT_INTERCEPTION(service, id, num_params) \
+ AddToPatchedFunctions( \
+ kNtdllName, #service, sandbox::INTERCEPTION_SERVICE_CALL, \
+ reinterpret_cast<void*>(MAKE_SERVICE_NAME(service)), id)
+
+#define INTERCEPT_NT(manager, service, id, num_params) \
+ manager->ADD_NT_INTERCEPTION(service, id, num_params)
+
+// When intercepting the EAT it is important that the patched version of the
+// function not call any functions imported from system libraries unless
+// |TargetServices::InitCalled()| returns true, because it is only then that
+// we are guaranteed that our IAT has been initialized.
+#define INTERCEPT_EAT(manager, dll, function, id, num_params) \
+ manager->AddToPatchedFunctions( \
+ dll, #function, sandbox::INTERCEPTION_EAT, \
+ reinterpret_cast<void*>(MAKE_SERVICE_NAME(function)), id)
+#endif // SANDBOX_EXPORTS
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/interception_agent.cc b/security/sandbox/chromium/sandbox/win/src/interception_agent.cc
new file mode 100644
index 0000000000..e095328a71
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interception_agent.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// For information about interceptions as a whole see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#include "sandbox/win/src/interception_agent.h"
+
+#include <windows.h>
+
+#include <stddef.h>
+
+#include "sandbox/win/src/eat_resolver.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sidestep_resolver.h"
+
+namespace {
+
+// Returns true if target lies between base and base + range.
+bool IsWithinRange(const void* base, size_t range, const void* target) {
+ const char* end = reinterpret_cast<const char*>(base) + range;
+ return reinterpret_cast<const char*>(target) < end;
+}
+
+} // namespace
+
+namespace sandbox {
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// The list of intercepted functions back-pointers.
+SANDBOX_INTERCEPT OriginalFunctions g_originals;
+
+// Memory buffer mapped from the parent, with the list of interceptions.
+SANDBOX_INTERCEPT SharedMemory* g_interceptions = nullptr;
+
+InterceptionAgent* InterceptionAgent::GetInterceptionAgent() {
+ static InterceptionAgent* s_singleton = nullptr;
+ if (!s_singleton) {
+ if (!g_interceptions)
+ return nullptr;
+
+ size_t array_bytes = g_interceptions->num_intercepted_dlls * sizeof(void*);
+ s_singleton = reinterpret_cast<InterceptionAgent*>(
+ new (NT_ALLOC) char[array_bytes + sizeof(InterceptionAgent)]);
+
+ bool success = s_singleton->Init(g_interceptions);
+ if (!success) {
+ operator delete(s_singleton, NT_ALLOC);
+ s_singleton = nullptr;
+ }
+ }
+ return s_singleton;
+}
+
+bool InterceptionAgent::Init(SharedMemory* shared_memory) {
+ interceptions_ = shared_memory;
+ for (int i = 0; i < shared_memory->num_intercepted_dlls; i++)
+ dlls_[i] = nullptr;
+ return true;
+}
+
+bool InterceptionAgent::DllMatch(const UNICODE_STRING* full_path,
+ const UNICODE_STRING* name,
+ const DllPatchInfo* dll_info) {
+ UNICODE_STRING current_name;
+ current_name.Length =
+ static_cast<USHORT>(g_nt.wcslen(dll_info->dll_name) * sizeof(wchar_t));
+ current_name.MaximumLength = current_name.Length;
+ current_name.Buffer = const_cast<wchar_t*>(dll_info->dll_name);
+
+ BOOLEAN case_insensitive = TRUE;
+ if (full_path &&
+ !g_nt.RtlCompareUnicodeString(&current_name, full_path, case_insensitive))
+ return true;
+
+ if (name &&
+ !g_nt.RtlCompareUnicodeString(&current_name, name, case_insensitive))
+ return true;
+
+ return false;
+}
+
+bool InterceptionAgent::OnDllLoad(const UNICODE_STRING* full_path,
+ const UNICODE_STRING* name,
+ void* base_address) {
+ DllPatchInfo* dll_info = interceptions_->dll_list;
+ int i = 0;
+ for (; i < interceptions_->num_intercepted_dlls; i++) {
+ if (DllMatch(full_path, name, dll_info))
+ break;
+
+ dll_info = reinterpret_cast<DllPatchInfo*>(
+ reinterpret_cast<char*>(dll_info) + dll_info->record_bytes);
+ }
+
+ // Return now if the dll is not in our list of interest.
+ if (i == interceptions_->num_intercepted_dlls)
+ return true;
+
+ // The dll must be unloaded.
+ if (dll_info->unload_module)
+ return false;
+
+ // Purify causes this condition to trigger.
+ if (dlls_[i])
+ return true;
+
+ size_t buffer_bytes = offsetof(DllInterceptionData, thunks) +
+ dll_info->num_functions * sizeof(ThunkData);
+ dlls_[i] = reinterpret_cast<DllInterceptionData*>(
+ new (NT_PAGE, base_address) char[buffer_bytes]);
+
+ DCHECK_NT(dlls_[i]);
+ if (!dlls_[i])
+ return true;
+
+ dlls_[i]->data_bytes = buffer_bytes;
+ dlls_[i]->num_thunks = 0;
+ dlls_[i]->base = base_address;
+ dlls_[i]->used_bytes = offsetof(DllInterceptionData, thunks);
+
+ VERIFY(PatchDll(dll_info, dlls_[i]));
+
+ ULONG old_protect;
+ SIZE_T real_size = buffer_bytes;
+ void* to_protect = dlls_[i];
+ VERIFY_SUCCESS(g_nt.ProtectVirtualMemory(NtCurrentProcess, &to_protect,
+ &real_size, PAGE_EXECUTE_READ,
+ &old_protect));
+ return true;
+}
+
+void InterceptionAgent::OnDllUnload(void* base_address) {
+ for (int i = 0; i < interceptions_->num_intercepted_dlls; i++) {
+ if (dlls_[i] && dlls_[i]->base == base_address) {
+ operator delete(dlls_[i], NT_PAGE);
+ dlls_[i] = nullptr;
+ break;
+ }
+ }
+}
+
+// TODO(rvargas): We have to deal with prebinded dlls. I see two options: change
+// the timestamp of the patched dll, or modify the info on the prebinded dll.
+// the first approach messes matching of debug symbols, the second one is more
+// complicated.
+bool InterceptionAgent::PatchDll(const DllPatchInfo* dll_info,
+ DllInterceptionData* thunks) {
+ DCHECK_NT(thunks);
+ DCHECK_NT(dll_info);
+
+ const FunctionInfo* function = reinterpret_cast<const FunctionInfo*>(
+ reinterpret_cast<const char*>(dll_info) + dll_info->offset_to_functions);
+
+ for (int i = 0; i < dll_info->num_functions; i++) {
+ if (!IsWithinRange(dll_info, dll_info->record_bytes, function->function)) {
+ NOTREACHED_NT();
+ return false;
+ }
+
+ ResolverThunk* resolver = GetResolver(function->type);
+ if (!resolver)
+ return false;
+
+ const char* interceptor =
+ function->function + g_nt.strlen(function->function) + 1;
+
+ if (!IsWithinRange(function, function->record_bytes, interceptor) ||
+ !IsWithinRange(dll_info, dll_info->record_bytes, interceptor)) {
+ NOTREACHED_NT();
+ return false;
+ }
+
+ NTSTATUS ret = resolver->Setup(
+ thunks->base, interceptions_->interceptor_base, function->function,
+ interceptor, function->interceptor_address, &thunks->thunks[i],
+ sizeof(ThunkData), nullptr);
+ if (!NT_SUCCESS(ret)) {
+ NOTREACHED_NT();
+ return false;
+ }
+
+ DCHECK_NT(!g_originals[function->id] ||
+ g_originals[function->id] == &thunks->thunks[i]);
+ g_originals[function->id] = &thunks->thunks[i];
+
+ thunks->num_thunks++;
+ thunks->used_bytes += sizeof(ThunkData);
+
+ function = reinterpret_cast<const FunctionInfo*>(
+ reinterpret_cast<const char*>(function) + function->record_bytes);
+ }
+
+ return true;
+}
+
+// This method is called from within the loader lock
+ResolverThunk* InterceptionAgent::GetResolver(InterceptionType type) {
+ static EatResolverThunk* eat_resolver = nullptr;
+ static SidestepResolverThunk* sidestep_resolver = nullptr;
+ static SmartSidestepResolverThunk* smart_sidestep_resolver = nullptr;
+
+ if (!eat_resolver)
+ eat_resolver = new (NT_ALLOC) EatResolverThunk;
+
+#if !defined(_WIN64)
+ // Sidestep is not supported for x64.
+ if (!sidestep_resolver)
+ sidestep_resolver = new (NT_ALLOC) SidestepResolverThunk;
+
+ if (!smart_sidestep_resolver)
+ smart_sidestep_resolver = new (NT_ALLOC) SmartSidestepResolverThunk;
+#endif
+
+ switch (type) {
+ case INTERCEPTION_EAT:
+ return eat_resolver;
+ case INTERCEPTION_SIDESTEP:
+ return sidestep_resolver;
+ case INTERCEPTION_SMART_SIDESTEP:
+ return smart_sidestep_resolver;
+ default:
+ NOTREACHED_NT();
+ }
+
+ return nullptr;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/interception_agent.h b/security/sandbox/chromium/sandbox/win/src/interception_agent.h
new file mode 100644
index 0000000000..b2bce08b09
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interception_agent.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines InterceptionAgent, the class in charge of setting up interceptions
+// from the inside of the sandboxed process. For more details see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#ifndef SANDBOX_SRC_INTERCEPTION_AGENT_H__
+#define SANDBOX_SRC_INTERCEPTION_AGENT_H__
+
+#include "base/macros.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+// Internal structures used for communication between the broker and the target.
+struct DllInterceptionData;
+struct SharedMemory;
+struct DllPatchInfo;
+
+class ResolverThunk;
+
+// The InterceptionAgent executes on the target application, and it is in charge
+// of setting up the desired interceptions or indicating what module needs to
+// be unloaded.
+//
+// The exposed API consists of three methods: GetInterceptionAgent to retrieve
+// the single class instance, OnDllLoad and OnDllUnload to process a dll being
+// loaded and unloaded respectively.
+//
+// This class assumes that it will get called for every dll being loaded,
+// starting with kernel32, so the singleton will be instantiated from within the
+// loader lock.
+class InterceptionAgent {
+ public:
+ // Returns the single InterceptionAgent object for this process.
+ static InterceptionAgent* GetInterceptionAgent();
+
+ // This method should be invoked whenever a new dll is loaded to perform the
+ // required patches. If the return value is false, this dll should not be
+ // allowed to load.
+ //
+ // full_path is the (optional) full name of the module being loaded and name
+ // is the internal module name. If full_path is provided, it will be used
+ // before the internal name to determine if we care about this dll.
+ bool OnDllLoad(const UNICODE_STRING* full_path, const UNICODE_STRING* name,
+ void* base_address);
+
+ // Performs cleanup when a dll is unloaded.
+ void OnDllUnload(void* base_address);
+
+ private:
+ ~InterceptionAgent() {}
+
+ // Performs initialization of the singleton.
+ bool Init(SharedMemory* shared_memory);
+
+ // Returns true if we are interested on this dll. dll_info is an entry of the
+ // list of intercepted dlls.
+ bool DllMatch(const UNICODE_STRING* full_path, const UNICODE_STRING* name,
+ const DllPatchInfo* dll_info);
+
+ // Performs the patching of the dll loaded at base_address.
+ // The patches to perform are described on dll_info, and thunks is the thunk
+ // storage for the whole dll.
+ // Returns true on success.
+ bool PatchDll(const DllPatchInfo* dll_info, DllInterceptionData* thunks);
+
+ // Returns a resolver for a given interception type.
+ ResolverThunk* GetResolver(InterceptionType type);
+
+ // Shared memory containing the list of functions to intercept.
+ SharedMemory* interceptions_;
+
+ // Array of thunk data buffers for the intercepted dlls. This object singleton
+ // is allocated with a placement new with enough space to hold the complete
+ // array of pointers, not just the first element.
+ DllInterceptionData* dlls_[1];
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(InterceptionAgent);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_INTERCEPTION_AGENT_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/interception_internal.h b/security/sandbox/chromium/sandbox/win/src/interception_internal.h
new file mode 100644
index 0000000000..bf452e049e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interception_internal.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines InterceptionManager, the class in charge of setting up interceptions
+// for the sandboxed process. For more details see:
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#ifndef SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
+#define SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
+
+#include <stddef.h>
+
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+const int kMaxThunkDataBytes = 64;
+
+// The following structures contain variable size fields at the end, and will be
+// used to transfer information between two processes. In order to guarantee
+// our ability to follow the chain of structures, the alignment should be fixed,
+// hence this pragma.
+#pragma pack(push, 4)
+
+// Structures for the shared memory that contains patching information
+// for the InterceptionAgent.
+// A single interception:
+struct FunctionInfo {
+ size_t record_bytes; // rounded to sizeof(size_t) bytes
+ InterceptionType type;
+ InterceptorId id;
+ const void* interceptor_address;
+ char function[1]; // placeholder for null terminated name
+ // char interceptor[] // followed by the interceptor function
+};
+
+// A single dll:
+struct DllPatchInfo {
+ size_t record_bytes; // rounded to sizeof(size_t) bytes
+ size_t offset_to_functions;
+ int num_functions;
+ bool unload_module;
+ wchar_t dll_name[1]; // placeholder for null terminated name
+ // FunctionInfo function_info[] // followed by the functions to intercept
+};
+
+// All interceptions:
+struct SharedMemory {
+ int num_intercepted_dlls;
+ void* interceptor_base;
+ DllPatchInfo dll_list[1]; // placeholder for the list of dlls
+};
+
+// Dummy single thunk:
+struct ThunkData {
+ char data[kMaxThunkDataBytes];
+};
+
+// In-memory representation of the interceptions for a given dll:
+struct DllInterceptionData {
+ size_t data_bytes;
+ size_t used_bytes;
+ void* base;
+ int num_thunks;
+#if defined(_WIN64)
+ int dummy; // Improve alignment.
+#endif
+ ThunkData thunks[1];
+};
+
+#pragma pack(pop)
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_INTERCEPTION_INTERNAL_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/interception_unittest.cc b/security/sandbox/chromium/sandbox/win/src/interception_unittest.cc
new file mode 100644
index 0000000000..0120682bcb
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interception_unittest.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for InterceptionManager.
+// The tests require private information so the whole interception.cc file is
+// included from this file.
+
+#include "sandbox/win/src/interception.h"
+
+#include <windows.h>
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <memory>
+#include <set>
+
+#include "base/bits.h"
+#include "sandbox/win/src/interception_internal.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/target_process.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace internal {
+size_t GetGranularAlignedRandomOffset(size_t size);
+}
+
+// Walks the settings buffer, verifying that the values make sense and counting
+// objects.
+// Arguments:
+// buffer (in): the buffer to walk.
+// size (in): buffer size
+// num_dlls (out): count of the dlls on the buffer.
+// num_function (out): count of intercepted functions.
+// num_names (out): count of named interceptor functions.
+void WalkBuffer(void* buffer,
+ size_t size,
+ int* num_dlls,
+ int* num_functions,
+ int* num_names) {
+ ASSERT_TRUE(buffer);
+ ASSERT_TRUE(num_functions);
+ ASSERT_TRUE(num_names);
+ *num_dlls = *num_functions = *num_names = 0;
+ SharedMemory* memory = reinterpret_cast<SharedMemory*>(buffer);
+
+ ASSERT_GT(size, sizeof(SharedMemory));
+ DllPatchInfo* dll = &memory->dll_list[0];
+
+ for (int i = 0; i < memory->num_intercepted_dlls; i++) {
+ ASSERT_NE(0u, wcslen(dll->dll_name));
+ ASSERT_EQ(0u, dll->record_bytes % sizeof(size_t));
+ ASSERT_EQ(0u, dll->offset_to_functions % sizeof(size_t));
+ ASSERT_NE(0, dll->num_functions);
+
+ FunctionInfo* function = reinterpret_cast<FunctionInfo*>(
+ reinterpret_cast<char*>(dll) + dll->offset_to_functions);
+
+ for (int j = 0; j < dll->num_functions; j++) {
+ ASSERT_EQ(0u, function->record_bytes % sizeof(size_t));
+
+ char* name = function->function;
+ size_t length = strlen(name);
+ ASSERT_NE(0u, length);
+ name += length + 1;
+
+ // look for overflows
+ ASSERT_GT(reinterpret_cast<char*>(buffer) + size, name + strlen(name));
+
+ // look for a named interceptor
+ if (strlen(name)) {
+ (*num_names)++;
+ EXPECT_TRUE(!function->interceptor_address);
+ } else {
+ EXPECT_TRUE(function->interceptor_address);
+ }
+
+ (*num_functions)++;
+ function = reinterpret_cast<FunctionInfo*>(
+ reinterpret_cast<char*>(function) + function->record_bytes);
+ }
+
+ (*num_dlls)++;
+ dll = reinterpret_cast<DllPatchInfo*>(reinterpret_cast<char*>(dll) +
+ dll->record_bytes);
+ }
+}
+
+TEST(InterceptionManagerTest, GetGranularAlignedRandomOffset) {
+ std::set<size_t> sizes;
+
+ // 544 is current value of interceptions_.size() * sizeof(ThunkData) +
+ // sizeof(DllInterceptionData).
+ const size_t kThunkBytes = 544;
+
+ // ciel(log2(544)) = 10.
+ // Alignment must be 2^10 = 1024.
+ const size_t kAlignmentBits = base::bits::Log2Ceiling(kThunkBytes);
+ const size_t kAlignment = static_cast<size_t>(1) << kAlignmentBits;
+
+ const size_t kAllocGranularity = 65536;
+
+ // Generate enough sample data to ensure there is at least one value in each
+ // potential bucket.
+ for (size_t i = 0; i < 1000000; i++)
+ sizes.insert(internal::GetGranularAlignedRandomOffset(kThunkBytes));
+
+ size_t prev_val = 0;
+ size_t min_val = kAllocGranularity;
+ size_t min_nonzero_val = kAllocGranularity;
+ size_t max_val = 0;
+
+ for (size_t val : sizes) {
+ ASSERT_LT(val, kAllocGranularity);
+ if (prev_val)
+ ASSERT_EQ(val - prev_val, kAlignment);
+ if (val)
+ min_nonzero_val = std::min(val, min_nonzero_val);
+ min_val = std::min(val, min_val);
+ prev_val = val;
+ max_val = std::max(val, max_val);
+ }
+ ASSERT_EQ(max_val, kAllocGranularity - kAlignment);
+ ASSERT_EQ(0u, min_val);
+ ASSERT_EQ(min_nonzero_val, kAlignment);
+}
+
+TEST(InterceptionManagerTest, BufferLayout1) {
+ wchar_t exe_name[MAX_PATH];
+ ASSERT_NE(0u, GetModuleFileName(nullptr, exe_name, MAX_PATH - 1));
+
+ TargetProcess* target =
+ MakeTestTargetProcess(::GetCurrentProcess(), ::GetModuleHandle(exe_name));
+
+ InterceptionManager interceptions(target, true);
+
+ // Any pointer will do for a function pointer.
+ void* function = &interceptions;
+
+ // We don't care about the interceptor id.
+ interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtCreateFile",
+ INTERCEPTION_SERVICE_CALL, function,
+ OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"kernel32.dll", "CreateFileEx",
+ INTERCEPTION_EAT, function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"kernel32.dll", "SomeFileEx",
+ INTERCEPTION_SMART_SIDESTEP, function,
+ OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"user32.dll", "FindWindow",
+ INTERCEPTION_EAT, function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"kernel32.dll", "CreateMutex",
+ INTERCEPTION_EAT, function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"user32.dll", "PostMsg",
+ INTERCEPTION_EAT, function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"user32.dll", "PostMsg",
+ INTERCEPTION_EAT, "replacement",
+ OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+ INTERCEPTION_EAT, function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtClose",
+ INTERCEPTION_SERVICE_CALL, function,
+ OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtOpenFile",
+ INTERCEPTION_SIDESTEP, function,
+ OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"some.dll", "Superfn", INTERCEPTION_EAT,
+ function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+ INTERCEPTION_EAT, "a", OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+ INTERCEPTION_SIDESTEP, "ab", OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"comctl.dll", "SaveAsDlg",
+ INTERCEPTION_EAT, "abc", OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"a.dll", "p", INTERCEPTION_EAT, function,
+ OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"b.dll",
+ "TheIncredibleCallToSaveTheWorld",
+ INTERCEPTION_EAT, function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"a.dll", "BIsLame", INTERCEPTION_EAT,
+ function, OPEN_KEY_ID);
+ interceptions.AddToPatchedFunctions(L"a.dll", "ARules", INTERCEPTION_EAT,
+ function, OPEN_KEY_ID);
+
+ // Verify that all interceptions were added
+ ASSERT_EQ(18u, interceptions.interceptions_.size());
+
+ size_t buffer_size = interceptions.GetBufferSize();
+ std::unique_ptr<BYTE[]> local_buffer(new BYTE[buffer_size]);
+
+ ASSERT_TRUE(interceptions.SetupConfigBuffer(local_buffer.get(), buffer_size));
+
+ // At this point, the interceptions should have been separated into two
+ // groups: one group with the local ("cold") interceptions, consisting of
+ // everything from ntdll and stuff set as INTRECEPTION_SERVICE_CALL, and
+ // another group with the interceptions belonging to dlls that will be "hot"
+ // patched on the client. The second group lives on local_buffer, and the
+ // first group remains on the list of interceptions (inside the object
+ // "interceptions"). There are 3 local interceptions (of ntdll); the
+ // other 15 have to be sent to the child to be performed "hot".
+ EXPECT_EQ(3u, interceptions.interceptions_.size());
+
+ int num_dlls, num_functions, num_names;
+ WalkBuffer(local_buffer.get(), buffer_size, &num_dlls, &num_functions,
+ &num_names);
+
+ // The 15 interceptions on the buffer (to the child) should be grouped on 6
+ // dlls. Only four interceptions are using an explicit name for the
+ // interceptor function.
+ EXPECT_EQ(6, num_dlls);
+ EXPECT_EQ(15, num_functions);
+ EXPECT_EQ(4, num_names);
+}
+
+TEST(InterceptionManagerTest, BufferLayout2) {
+ wchar_t exe_name[MAX_PATH];
+ ASSERT_NE(0u, GetModuleFileName(nullptr, exe_name, MAX_PATH - 1));
+
+ TargetProcess* target =
+ MakeTestTargetProcess(::GetCurrentProcess(), ::GetModuleHandle(exe_name));
+
+ InterceptionManager interceptions(target, true);
+
+ // Any pointer will do for a function pointer.
+ void* function = &interceptions;
+ interceptions.AddToUnloadModules(L"some01.dll");
+ // We don't care about the interceptor id.
+ interceptions.AddToPatchedFunctions(L"ntdll.dll", "NtCreateFile",
+ INTERCEPTION_SERVICE_CALL, function,
+ OPEN_FILE_ID);
+ interceptions.AddToPatchedFunctions(L"kernel32.dll", "CreateFileEx",
+ INTERCEPTION_EAT, function, OPEN_FILE_ID);
+ interceptions.AddToUnloadModules(L"some02.dll");
+ interceptions.AddToPatchedFunctions(L"kernel32.dll", "SomeFileEx",
+ INTERCEPTION_SMART_SIDESTEP, function,
+ OPEN_FILE_ID);
+ // Verify that all interceptions were added
+ ASSERT_EQ(5u, interceptions.interceptions_.size());
+
+ size_t buffer_size = interceptions.GetBufferSize();
+ std::unique_ptr<BYTE[]> local_buffer(new BYTE[buffer_size]);
+
+ ASSERT_TRUE(interceptions.SetupConfigBuffer(local_buffer.get(), buffer_size));
+
+ // At this point, the interceptions should have been separated into two
+ // groups: one group with the local ("cold") interceptions, and another
+ // group with the interceptions belonging to dlls that will be "hot"
+ // patched on the client. The second group lives on local_buffer, and the
+ // first group remains on the list of interceptions, in this case just one.
+ EXPECT_EQ(1u, interceptions.interceptions_.size());
+
+ int num_dlls, num_functions, num_names;
+ WalkBuffer(local_buffer.get(), buffer_size, &num_dlls, &num_functions,
+ &num_names);
+
+ EXPECT_EQ(3, num_dlls);
+ EXPECT_EQ(4, num_functions);
+ EXPECT_EQ(0, num_names);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/interceptors.h b/security/sandbox/chromium/sandbox/win/src/interceptors.h
new file mode 100644
index 0000000000..269597b0e1
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interceptors.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_INTERCEPTORS_H_
+#define SANDBOX_SRC_INTERCEPTORS_H_
+
+#if defined(_WIN64)
+#include "sandbox/win/src/interceptors_64.h"
+#endif
+
+namespace sandbox {
+
+enum InterceptorId {
+ // Internal use:
+ MAP_VIEW_OF_SECTION_ID = 0,
+ UNMAP_VIEW_OF_SECTION_ID,
+ // Policy broker:
+ IMPERSONATE_ANONYMOUS_TOKEN_ID,
+ SET_INFORMATION_THREAD_ID,
+ OPEN_THREAD_TOKEN_ID,
+ OPEN_THREAD_TOKEN_EX_ID,
+ OPEN_THREAD_ID,
+ OPEN_PROCESS_ID,
+ OPEN_PROCESS_TOKEN_ID,
+ OPEN_PROCESS_TOKEN_EX_ID,
+ // Filesystem dispatcher:
+ CREATE_FILE_ID,
+ OPEN_FILE_ID,
+ QUERY_ATTRIB_FILE_ID,
+ QUERY_FULL_ATTRIB_FILE_ID,
+ SET_INFO_FILE_ID,
+ // Named pipe dispatcher:
+ CREATE_NAMED_PIPE_ID,
+ // Process-thread dispatcher:
+ CREATE_PROCESSW_ID,
+ CREATE_PROCESSA_ID,
+ CREATE_THREAD_ID,
+ // Registry dispatcher:
+ CREATE_KEY_ID,
+ OPEN_KEY_ID,
+ OPEN_KEY_EX_ID,
+ // Sync dispatcher:
+ CREATE_EVENT_ID,
+ OPEN_EVENT_ID,
+ // Process mitigations Win32k dispatcher:
+ GDIINITIALIZE_ID,
+ GETSTOCKOBJECT_ID,
+ REGISTERCLASSW_ID,
+ ENUMDISPLAYMONITORS_ID,
+ ENUMDISPLAYDEVICESA_ID,
+ GETMONITORINFOA_ID,
+ GETMONITORINFOW_ID,
+ CREATEOPMPROTECTEDOUTPUTS_ID,
+ GETCERTIFICATE_ID,
+ GETCERTIFICATESIZE_ID,
+ GETCERTIFICATEBYHANDLE_ID,
+ GETCERTIFICATESIZEBYHANDLE_ID,
+ DESTROYOPMPROTECTEDOUTPUT_ID,
+ CONFIGUREOPMPROTECTEDOUTPUT_ID,
+ GETOPMINFORMATION_ID,
+ GETOPMRANDOMNUMBER_ID,
+ GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_ID,
+ SETOPMSIGNINGKEYANDSEQUENCENUMBERS_ID,
+ // Signed dispatcher:
+ CREATE_SECTION_ID,
+ INTERCEPTOR_MAX_ID
+};
+
+typedef void* OriginalFunctions[INTERCEPTOR_MAX_ID];
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_INTERCEPTORS_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/interceptors_64.cc b/security/sandbox/chromium/sandbox/win/src/interceptors_64.cc
new file mode 100644
index 0000000000..2d9c80b664
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interceptors_64.cc
@@ -0,0 +1,539 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/interceptors_64.h"
+
+#include "sandbox/win/src/filesystem_interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/named_pipe_interception.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/registry_interception.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/signed_interception.h"
+#include "sandbox/win/src/sync_interception.h"
+#include "sandbox/win/src/target_interceptions.h"
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+SANDBOX_INTERCEPT OriginalFunctions g_originals;
+
+NTSTATUS WINAPI TargetNtMapViewOfSection64(HANDLE section,
+ HANDLE process,
+ PVOID* base,
+ ULONG_PTR zero_bits,
+ SIZE_T commit_size,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size,
+ SECTION_INHERIT inherit,
+ ULONG allocation_type,
+ ULONG protect) {
+ NtMapViewOfSectionFunction orig_fn =
+ reinterpret_cast<NtMapViewOfSectionFunction>(
+ g_originals[MAP_VIEW_OF_SECTION_ID]);
+
+ return TargetNtMapViewOfSection(orig_fn, section, process, base, zero_bits,
+ commit_size, offset, view_size, inherit,
+ allocation_type, protect);
+}
+
+NTSTATUS WINAPI TargetNtUnmapViewOfSection64(HANDLE process, PVOID base) {
+ NtUnmapViewOfSectionFunction orig_fn =
+ reinterpret_cast<NtUnmapViewOfSectionFunction>(
+ g_originals[UNMAP_VIEW_OF_SECTION_ID]);
+ return TargetNtUnmapViewOfSection(orig_fn, process, base);
+}
+
+// -----------------------------------------------------------------------
+
+NTSTATUS WINAPI
+TargetNtImpersonateAnonymousToken64(HANDLE thread) {
+ NtImpersonateAnonymousTokenFunction orig_fn =
+ reinterpret_cast<NtImpersonateAnonymousTokenFunction>(
+ g_originals[IMPERSONATE_ANONYMOUS_TOKEN_ID]);
+ return TargetNtImpersonateAnonymousToken(orig_fn, thread);
+}
+
+NTSTATUS WINAPI
+TargetNtSetInformationThread64(HANDLE thread,
+ NT_THREAD_INFORMATION_CLASS thread_info_class,
+ PVOID thread_information,
+ ULONG thread_information_bytes) {
+ NtSetInformationThreadFunction orig_fn =
+ reinterpret_cast<NtSetInformationThreadFunction>(
+ g_originals[SET_INFORMATION_THREAD_ID]);
+ return TargetNtSetInformationThread(orig_fn, thread, thread_info_class,
+ thread_information,
+ thread_information_bytes);
+}
+
+NTSTATUS WINAPI TargetNtOpenThreadToken64(HANDLE thread,
+ ACCESS_MASK desired_access,
+ BOOLEAN open_as_self,
+ PHANDLE token) {
+ NtOpenThreadTokenFunction orig_fn =
+ reinterpret_cast<NtOpenThreadTokenFunction>(
+ g_originals[OPEN_THREAD_TOKEN_ID]);
+ return TargetNtOpenThreadToken(orig_fn, thread, desired_access, open_as_self,
+ token);
+}
+
+NTSTATUS WINAPI TargetNtOpenThreadTokenEx64(HANDLE thread,
+ ACCESS_MASK desired_access,
+ BOOLEAN open_as_self,
+ ULONG handle_attributes,
+ PHANDLE token) {
+ NtOpenThreadTokenExFunction orig_fn =
+ reinterpret_cast<NtOpenThreadTokenExFunction>(
+ g_originals[OPEN_THREAD_TOKEN_EX_ID]);
+ return TargetNtOpenThreadTokenEx(orig_fn, thread, desired_access,
+ open_as_self, handle_attributes, token);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateFile64(PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ PLARGE_INTEGER allocation_size,
+ ULONG file_attributes,
+ ULONG sharing,
+ ULONG disposition,
+ ULONG options,
+ PVOID ea_buffer,
+ ULONG ea_length) {
+ NtCreateFileFunction orig_fn =
+ reinterpret_cast<NtCreateFileFunction>(g_originals[CREATE_FILE_ID]);
+ return TargetNtCreateFile(orig_fn, file, desired_access, object_attributes,
+ io_status, allocation_size, file_attributes,
+ sharing, disposition, options, ea_buffer,
+ ea_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenFile64(PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ ULONG sharing,
+ ULONG options) {
+ NtOpenFileFunction orig_fn =
+ reinterpret_cast<NtOpenFileFunction>(g_originals[OPEN_FILE_ID]);
+ return TargetNtOpenFile(orig_fn, file, desired_access, object_attributes,
+ io_status, sharing, options);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtQueryAttributesFile64(POBJECT_ATTRIBUTES object_attributes,
+ PFILE_BASIC_INFORMATION file_attributes) {
+ NtQueryAttributesFileFunction orig_fn =
+ reinterpret_cast<NtQueryAttributesFileFunction>(
+ g_originals[QUERY_ATTRIB_FILE_ID]);
+ return TargetNtQueryAttributesFile(orig_fn, object_attributes,
+ file_attributes);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryFullAttributesFile64(
+ POBJECT_ATTRIBUTES object_attributes,
+ PFILE_NETWORK_OPEN_INFORMATION file_attributes) {
+ NtQueryFullAttributesFileFunction orig_fn =
+ reinterpret_cast<NtQueryFullAttributesFileFunction>(
+ g_originals[QUERY_FULL_ATTRIB_FILE_ID]);
+ return TargetNtQueryFullAttributesFile(orig_fn, object_attributes,
+ file_attributes);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtSetInformationFile64(HANDLE file,
+ PIO_STATUS_BLOCK io_status,
+ PVOID file_information,
+ ULONG length,
+ FILE_INFORMATION_CLASS file_information_class) {
+ NtSetInformationFileFunction orig_fn =
+ reinterpret_cast<NtSetInformationFileFunction>(
+ g_originals[SET_INFO_FILE_ID]);
+ return TargetNtSetInformationFile(orig_fn, file, io_status, file_information,
+ length, file_information_class);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateNamedPipeW64(LPCWSTR pipe_name,
+ DWORD open_mode,
+ DWORD pipe_mode,
+ DWORD max_instance,
+ DWORD out_buffer_size,
+ DWORD in_buffer_size,
+ DWORD default_timeout,
+ LPSECURITY_ATTRIBUTES security_attributes) {
+ CreateNamedPipeWFunction orig_fn = reinterpret_cast<CreateNamedPipeWFunction>(
+ g_originals[CREATE_NAMED_PIPE_ID]);
+ return TargetCreateNamedPipeW(orig_fn, pipe_name, open_mode, pipe_mode,
+ max_instance, out_buffer_size, in_buffer_size,
+ default_timeout, security_attributes);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenThread64(PHANDLE thread,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id) {
+ NtOpenThreadFunction orig_fn =
+ reinterpret_cast<NtOpenThreadFunction>(g_originals[OPEN_THREAD_ID]);
+ return TargetNtOpenThread(orig_fn, thread, desired_access, object_attributes,
+ client_id);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcess64(PHANDLE process,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id) {
+ NtOpenProcessFunction orig_fn =
+ reinterpret_cast<NtOpenProcessFunction>(g_originals[OPEN_PROCESS_ID]);
+ return TargetNtOpenProcess(orig_fn, process, desired_access,
+ object_attributes, client_id);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcessToken64(HANDLE process,
+ ACCESS_MASK desired_access,
+ PHANDLE token) {
+ NtOpenProcessTokenFunction orig_fn =
+ reinterpret_cast<NtOpenProcessTokenFunction>(
+ g_originals[OPEN_PROCESS_TOKEN_ID]);
+ return TargetNtOpenProcessToken(orig_fn, process, desired_access, token);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcessTokenEx64(HANDLE process,
+ ACCESS_MASK desired_access,
+ ULONG handle_attributes,
+ PHANDLE token) {
+ NtOpenProcessTokenExFunction orig_fn =
+ reinterpret_cast<NtOpenProcessTokenExFunction>(
+ g_originals[OPEN_PROCESS_TOKEN_EX_ID]);
+ return TargetNtOpenProcessTokenEx(orig_fn, process, desired_access,
+ handle_attributes, token);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetCreateProcessW64(LPCWSTR application_name,
+ LPWSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCWSTR current_directory,
+ LPSTARTUPINFOW startup_info,
+ LPPROCESS_INFORMATION process_information) {
+ CreateProcessWFunction orig_fn =
+ reinterpret_cast<CreateProcessWFunction>(g_originals[CREATE_PROCESSW_ID]);
+ return TargetCreateProcessW(
+ orig_fn, application_name, command_line, process_attributes,
+ thread_attributes, inherit_handles, flags, environment, current_directory,
+ startup_info, process_information);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetCreateProcessA64(LPCSTR application_name,
+ LPSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCSTR current_directory,
+ LPSTARTUPINFOA startup_info,
+ LPPROCESS_INFORMATION process_information) {
+ CreateProcessAFunction orig_fn =
+ reinterpret_cast<CreateProcessAFunction>(g_originals[CREATE_PROCESSA_ID]);
+ return TargetCreateProcessA(
+ orig_fn, application_name, command_line, process_attributes,
+ thread_attributes, inherit_handles, flags, environment, current_directory,
+ startup_info, process_information);
+}
+
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateThread64(LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ PVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id) {
+ CreateThreadFunction orig_fn =
+ reinterpret_cast<CreateThreadFunction>(g_originals[CREATE_THREAD_ID]);
+ return TargetCreateThread(orig_fn, thread_attributes, stack_size,
+ start_address, parameter, creation_flags,
+ thread_id);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateKey64(PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ ULONG title_index,
+ PUNICODE_STRING class_name,
+ ULONG create_options,
+ PULONG disposition) {
+ NtCreateKeyFunction orig_fn =
+ reinterpret_cast<NtCreateKeyFunction>(g_originals[CREATE_KEY_ID]);
+ return TargetNtCreateKey(orig_fn, key, desired_access, object_attributes,
+ title_index, class_name, create_options,
+ disposition);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenKey64(PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes) {
+ NtOpenKeyFunction orig_fn =
+ reinterpret_cast<NtOpenKeyFunction>(g_originals[OPEN_KEY_ID]);
+ return TargetNtOpenKey(orig_fn, key, desired_access, object_attributes);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenKeyEx64(PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ ULONG open_options) {
+ NtOpenKeyExFunction orig_fn =
+ reinterpret_cast<NtOpenKeyExFunction>(g_originals[OPEN_KEY_EX_ID]);
+ return TargetNtOpenKeyEx(orig_fn, key, desired_access, object_attributes,
+ open_options);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateEvent64(PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ EVENT_TYPE event_type,
+ BOOLEAN initial_state) {
+ NtCreateEventFunction orig_fn =
+ reinterpret_cast<NtCreateEventFunction>(g_originals[CREATE_EVENT_ID]);
+ return TargetNtCreateEvent(orig_fn, event_handle, desired_access,
+ object_attributes, event_type, initial_state);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenEvent64(PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes) {
+ NtOpenEventFunction orig_fn =
+ reinterpret_cast<NtOpenEventFunction>(g_originals[OPEN_EVENT_ID]);
+ return TargetNtOpenEvent(orig_fn, event_handle, desired_access,
+ object_attributes);
+}
+
+// -----------------------------------------------------------------------
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(HANDLE dll,
+ DWORD reason) {
+ GdiDllInitializeFunction orig_fn =
+ reinterpret_cast<GdiDllInitializeFunction>(g_originals[GDIINITIALIZE_ID]);
+ return TargetGdiDllInitialize(orig_fn, dll, reason);
+}
+
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object) {
+ GetStockObjectFunction orig_fn =
+ reinterpret_cast<GetStockObjectFunction>(g_originals[GETSTOCKOBJECT_ID]);
+ return TargetGetStockObject(orig_fn, object);
+}
+
+SANDBOX_INTERCEPT ATOM WINAPI
+TargetRegisterClassW64(const WNDCLASS* wnd_class) {
+ RegisterClassWFunction orig_fn =
+ reinterpret_cast<RegisterClassWFunction>(g_originals[REGISTERCLASSW_ID]);
+ return TargetRegisterClassW(orig_fn, wnd_class);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetEnumDisplayMonitors64(HDC hdc,
+ LPCRECT clip_rect,
+ MONITORENUMPROC enum_function,
+ LPARAM data_pointer) {
+ EnumDisplayMonitorsFunction orig_fn =
+ reinterpret_cast<EnumDisplayMonitorsFunction>(
+ g_originals[ENUMDISPLAYMONITORS_ID]);
+ return TargetEnumDisplayMonitors(orig_fn, hdc, clip_rect, enum_function,
+ data_pointer);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetEnumDisplayDevicesA64(LPCSTR device,
+ DWORD device_num,
+ PDISPLAY_DEVICEA display_device,
+ DWORD flags) {
+ EnumDisplayDevicesAFunction orig_fn =
+ reinterpret_cast<EnumDisplayDevicesAFunction>(
+ g_originals[ENUMDISPLAYDEVICESA_ID]);
+ return TargetEnumDisplayDevicesA(orig_fn, device, device_num, display_device,
+ flags);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetGetMonitorInfoA64(HMONITOR monitor, LPMONITORINFO monitor_info) {
+ GetMonitorInfoAFunction orig_fn = reinterpret_cast<GetMonitorInfoAFunction>(
+ g_originals[GETMONITORINFOA_ID]);
+ return TargetGetMonitorInfoA(orig_fn, monitor, monitor_info);
+}
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetGetMonitorInfoW64(HMONITOR monitor, LPMONITORINFO monitor_info) {
+ GetMonitorInfoWFunction orig_fn = reinterpret_cast<GetMonitorInfoWFunction>(
+ g_originals[GETMONITORINFOW_ID]);
+ return TargetGetMonitorInfoW(orig_fn, monitor, monitor_info);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetSuggestedOPMProtectedOutputArraySize64(
+ PUNICODE_STRING device_name,
+ DWORD* suggested_output_array_size) {
+ GetSuggestedOPMProtectedOutputArraySizeFunction orig_fn =
+ reinterpret_cast<GetSuggestedOPMProtectedOutputArraySizeFunction>(
+ g_originals[GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_ID]);
+ return TargetGetSuggestedOPMProtectedOutputArraySize(
+ orig_fn, device_name, suggested_output_array_size);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetCreateOPMProtectedOutputs64(
+ PUNICODE_STRING device_name,
+ DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
+ DWORD protected_output_array_size,
+ DWORD* num_output_handles,
+ OPM_PROTECTED_OUTPUT_HANDLE* protected_output_array) {
+ CreateOPMProtectedOutputsFunction orig_fn =
+ reinterpret_cast<CreateOPMProtectedOutputsFunction>(
+ g_originals[CREATEOPMPROTECTEDOUTPUTS_ID]);
+ return TargetCreateOPMProtectedOutputs(
+ orig_fn, device_name, vos, protected_output_array_size,
+ num_output_handles, protected_output_array);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificate64(PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length) {
+ GetCertificateFunction orig_fn =
+ reinterpret_cast<GetCertificateFunction>(g_originals[GETCERTIFICATE_ID]);
+ return TargetGetCertificate(orig_fn, device_name, certificate_type,
+ certificate, certificate_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificateSize64(PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length) {
+ GetCertificateSizeFunction orig_fn =
+ reinterpret_cast<GetCertificateSizeFunction>(
+ g_originals[GETCERTIFICATESIZE_ID]);
+ return TargetGetCertificateSize(orig_fn, device_name, certificate_type,
+ certificate_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificateByHandle64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length) {
+ GetCertificateByHandleFunction orig_fn =
+ reinterpret_cast<GetCertificateByHandleFunction>(
+ g_originals[GETCERTIFICATE_ID]);
+ return TargetGetCertificateByHandle(orig_fn, protected_output,
+ certificate_type, certificate,
+ certificate_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificateSizeByHandle64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length) {
+ GetCertificateSizeByHandleFunction orig_fn =
+ reinterpret_cast<GetCertificateSizeByHandleFunction>(
+ g_originals[GETCERTIFICATESIZE_ID]);
+ return TargetGetCertificateSizeByHandle(orig_fn, protected_output,
+ certificate_type, certificate_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetDestroyOPMProtectedOutput64(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output) {
+ DestroyOPMProtectedOutputFunction orig_fn =
+ reinterpret_cast<DestroyOPMProtectedOutputFunction>(
+ g_originals[DESTROYOPMPROTECTEDOUTPUT_ID]);
+ return TargetDestroyOPMProtectedOutput(orig_fn, protected_output);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetOPMInformation64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
+ DXGKMDT_OPM_REQUESTED_INFORMATION* requested_info) {
+ GetOPMInformationFunction orig_fn =
+ reinterpret_cast<GetOPMInformationFunction>(
+ g_originals[GETOPMINFORMATION_ID]);
+ return TargetGetOPMInformation(orig_fn, protected_output, parameters,
+ requested_info);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetOPMRandomNumber64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_OPM_RANDOM_NUMBER* random_number) {
+ GetOPMRandomNumberFunction orig_fn =
+ reinterpret_cast<GetOPMRandomNumberFunction>(
+ g_originals[GETOPMRANDOMNUMBER_ID]);
+ return TargetGetOPMRandomNumber(orig_fn, protected_output, random_number);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetSetOPMSigningKeyAndSequenceNumbers64(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters) {
+ SetOPMSigningKeyAndSequenceNumbersFunction orig_fn =
+ reinterpret_cast<SetOPMSigningKeyAndSequenceNumbersFunction>(
+ g_originals[SETOPMSIGNINGKEYANDSEQUENCENUMBERS_ID]);
+ return TargetSetOPMSigningKeyAndSequenceNumbers(orig_fn, protected_output,
+ parameters);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetConfigureOPMProtectedOutput64(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
+ ULONG additional_parameters_size,
+ const BYTE* additional_parameters) {
+ ConfigureOPMProtectedOutputFunction orig_fn =
+ reinterpret_cast<ConfigureOPMProtectedOutputFunction>(
+ g_originals[CONFIGUREOPMPROTECTEDOUTPUT_ID]);
+ return TargetConfigureOPMProtectedOutput(
+ orig_fn, protected_output, parameters, additional_parameters_size,
+ additional_parameters);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateSection64(PHANDLE section_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PLARGE_INTEGER maximum_size,
+ ULONG section_page_protection,
+ ULONG allocation_attributes,
+ HANDLE file_handle) {
+ NtCreateSectionFunction orig_fn =
+ reinterpret_cast<NtCreateSectionFunction>(g_originals[CREATE_SECTION_ID]);
+ return TargetNtCreateSection(
+ orig_fn, section_handle, desired_access, object_attributes, maximum_size,
+ section_page_protection, allocation_attributes, file_handle);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/interceptors_64.h b/security/sandbox/chromium/sandbox/win/src/interceptors_64.h
new file mode 100644
index 0000000000..c446d5d9c1
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/interceptors_64.h
@@ -0,0 +1,334 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_INTERCEPTORS_64_H_
+#define SANDBOX_WIN_SRC_INTERCEPTORS_64_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtMapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being loaded, so we can patch them if needed.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtMapViewOfSection64(HANDLE section,
+ HANDLE process,
+ PVOID* base,
+ ULONG_PTR zero_bits,
+ SIZE_T commit_size,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size,
+ SECTION_INHERIT inherit,
+ ULONG allocation_type,
+ ULONG protect);
+
+// Interception of NtUnmapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being unloaded, so we can clean up our interceptions.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtUnmapViewOfSection64(HANDLE process,
+ PVOID base);
+
+// -----------------------------------------------------------------------
+// Interceptors without IPC.
+
+// Interception of NtImpersonateAnonymousToken on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtImpersonateAnonymousToken64(HANDLE thread);
+
+// Interception of NtSetInformationThread on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtSetInformationThread64(HANDLE thread,
+ NT_THREAD_INFORMATION_CLASS thread_info_class,
+ PVOID thread_information,
+ ULONG thread_information_bytes);
+
+// Interception of NtOpenThreadToken on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenThreadToken64(HANDLE thread,
+ ACCESS_MASK desired_access,
+ BOOLEAN open_as_self,
+ PHANDLE token);
+
+// Interception of NtOpenThreadTokenEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenThreadTokenEx64(HANDLE thread,
+ ACCESS_MASK desired_access,
+ BOOLEAN open_as_self,
+ ULONG handle_attributes,
+ PHANDLE token);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the file system dispatcher.
+
+// Interception of NtCreateFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateFile64(PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ PLARGE_INTEGER allocation_size,
+ ULONG file_attributes,
+ ULONG sharing,
+ ULONG disposition,
+ ULONG options,
+ PVOID ea_buffer,
+ ULONG ea_length);
+
+// Interception of NtOpenFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenFile64(PHANDLE file,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PIO_STATUS_BLOCK io_status,
+ ULONG sharing,
+ ULONG options);
+
+// Interception of NtQueryAtttributesFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtQueryAttributesFile64(POBJECT_ATTRIBUTES object_attributes,
+ PFILE_BASIC_INFORMATION file_attributes);
+
+// Interception of NtQueryFullAtttributesFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtQueryFullAttributesFile64(
+ POBJECT_ATTRIBUTES object_attributes,
+ PFILE_NETWORK_OPEN_INFORMATION file_attributes);
+
+// Interception of NtSetInformationFile on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtSetInformationFile64(HANDLE file,
+ PIO_STATUS_BLOCK io_status,
+ PVOID file_information,
+ ULONG length,
+ FILE_INFORMATION_CLASS file_information_class);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the named pipe dispatcher.
+
+// Interception of CreateNamedPipeW in kernel32.dll
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateNamedPipeW64(LPCWSTR pipe_name,
+ DWORD open_mode,
+ DWORD pipe_mode,
+ DWORD max_instance,
+ DWORD out_buffer_size,
+ DWORD in_buffer_size,
+ DWORD default_timeout,
+ LPSECURITY_ATTRIBUTES security_attributes);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the process-thread dispatcher.
+
+// Interception of NtOpenThread on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenThread64(PHANDLE thread,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id);
+
+// Interception of NtOpenProcess on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcess64(PHANDLE process,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id);
+
+// Interception of NtOpenProcessToken on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcessToken64(HANDLE process,
+ ACCESS_MASK desired_access,
+ PHANDLE token);
+
+// Interception of NtOpenProcessTokenEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcessTokenEx64(HANDLE process,
+ ACCESS_MASK desired_access,
+ ULONG handle_attributes,
+ PHANDLE token);
+
+// Interception of CreateProcessW in kernel32.dll.
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetCreateProcessW64(LPCWSTR application_name,
+ LPWSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCWSTR current_directory,
+ LPSTARTUPINFOW startup_info,
+ LPPROCESS_INFORMATION process_information);
+
+// Interception of CreateProcessA in kernel32.dll.
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetCreateProcessA64(LPCSTR application_name,
+ LPSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCSTR current_directory,
+ LPSTARTUPINFOA startup_info,
+ LPPROCESS_INFORMATION process_information);
+
+// Interception of CreateThread in kernel32.dll.
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateThread64(LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ PVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the registry dispatcher.
+
+// Interception of NtCreateKey on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateKey64(PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ ULONG title_index,
+ PUNICODE_STRING class_name,
+ ULONG create_options,
+ PULONG disposition);
+
+// Interception of NtOpenKey on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenKey64(PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes);
+
+// Interception of NtOpenKeyEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenKeyEx64(PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ ULONG open_options);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the sync dispatcher.
+
+// Interception of NtCreateEvent/NtOpenEvent on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateEvent64(PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ EVENT_TYPE event_type,
+ BOOLEAN initial_state);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenEvent64(PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the process mitigations win32k lockdown code.
+
+// Interceptor for the GdiDllInitialize function.
+SANDBOX_INTERCEPT BOOL WINAPI TargetGdiDllInitialize64(HANDLE dll,
+ DWORD reason);
+
+// Interceptor for the GetStockObject function.
+SANDBOX_INTERCEPT HGDIOBJ WINAPI TargetGetStockObject64(int object);
+
+// Interceptor for the RegisterClassW function.
+SANDBOX_INTERCEPT ATOM WINAPI TargetRegisterClassW64(const WNDCLASS* wnd_class);
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetEnumDisplayMonitors64(HDC hdc,
+ LPCRECT lprcClip,
+ MONITORENUMPROC lpfnEnum,
+ LPARAM dwData);
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetEnumDisplayDevicesA64(LPCSTR lpDevice,
+ DWORD iDevNum,
+ PDISPLAY_DEVICEA lpDisplayDevice,
+ DWORD dwFlags);
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetGetMonitorInfoA64(HMONITOR hMonitor,
+ LPMONITORINFO lpmi);
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetGetMonitorInfoW64(HMONITOR hMonitor,
+ LPMONITORINFO lpmi);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetSuggestedOPMProtectedOutputArraySize64(
+ PUNICODE_STRING device_name,
+ DWORD* suggested_output_array_size);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetCreateOPMProtectedOutputs64(
+ PUNICODE_STRING device_name,
+ DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
+ DWORD protected_output_array_size,
+ DWORD* num_output_handles,
+ OPM_PROTECTED_OUTPUT_HANDLE* protected_output_array);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificate64(PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificateSize64(PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificateByHandle64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificateSizeByHandle64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetDestroyOPMProtectedOutput64(OPM_PROTECTED_OUTPUT_HANDLE protected_output);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetOPMInformation64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
+ DXGKMDT_OPM_REQUESTED_INFORMATION* requested_info);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetOPMRandomNumber64(OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_OPM_RANDOM_NUMBER* random_number);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetSetOPMSigningKeyAndSequenceNumbers64(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetConfigureOPMProtectedOutput64(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
+ ULONG additional_parameters_size,
+ const BYTE* additional_parameters);
+
+// -----------------------------------------------------------------------
+// Interceptors handled by the signed process code.
+
+// Interception of NtCreateSection on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateSection64(PHANDLE section_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PLARGE_INTEGER maximum_size,
+ ULONG section_page_protection,
+ ULONG allocation_attributes,
+ HANDLE file_handle);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_INTERCEPTORS_64_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/internal_types.h b/security/sandbox/chromium/sandbox/win/src/internal_types.h
new file mode 100644
index 0000000000..9971da81d0
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/internal_types.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
+#define SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
+
+#include <stdint.h>
+
+namespace sandbox {
+
+const wchar_t kNtdllName[] = L"ntdll.dll";
+const wchar_t kKerneldllName[] = L"kernel32.dll";
+const wchar_t kKernelBasedllName[] = L"kernelbase.dll";
+
+// Defines the supported C++ types encoding to numeric id. Like a simplified
+// RTTI. Note that true C++ RTTI will not work because the types are not
+// polymorphic anyway.
+enum ArgType {
+ INVALID_TYPE = 0,
+ WCHAR_TYPE,
+ UINT32_TYPE,
+ UNISTR_TYPE,
+ VOIDPTR_TYPE,
+ INPTR_TYPE,
+ INOUTPTR_TYPE,
+ LAST_TYPE
+};
+
+// Encapsulates a pointer to a buffer and the size of the buffer.
+class CountedBuffer {
+ public:
+ CountedBuffer(void* buffer, uint32_t size) : size_(size), buffer_(buffer) {}
+
+ uint32_t Size() const { return size_; }
+
+ void* Buffer() const { return buffer_; }
+
+ private:
+ uint32_t size_;
+ void* buffer_;
+};
+
+// Helper class to convert void-pointer packed ints for both
+// 32 and 64 bit builds. This construct is non-portable.
+class IPCInt {
+ public:
+ explicit IPCInt(void* buffer) { buffer_.vp = buffer; }
+
+ explicit IPCInt(uint32_t i32) {
+ buffer_.vp = nullptr;
+ buffer_.i32 = i32;
+ }
+
+ uint32_t As32Bit() const { return buffer_.i32; }
+
+ void* AsVoidPtr() const { return buffer_.vp; }
+
+ private:
+ union U {
+ void* vp;
+ uint32_t i32;
+ } buffer_;
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_INTERNAL_TYPES_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/ipc_args.cc b/security/sandbox/chromium/sandbox/win/src/ipc_args.cc
new file mode 100644
index 0000000000..c0c64f1864
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/ipc_args.cc
@@ -0,0 +1,96 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/ipc_args.h"
+
+#include <stddef.h>
+
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/crosscall_server.h"
+
+namespace sandbox {
+
+// Releases memory allocated for IPC arguments, if needed.
+void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]) {
+ for (size_t i = 0; i < kMaxIpcParams; i++) {
+ switch (ipc_params->args[i]) {
+ case WCHAR_TYPE: {
+ delete reinterpret_cast<std::wstring*>(args[i]);
+ args[i] = nullptr;
+ break;
+ }
+ case INPTR_TYPE:
+ case INOUTPTR_TYPE: {
+ delete reinterpret_cast<CountedBuffer*>(args[i]);
+ args[i] = nullptr;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+// Fills up the list of arguments (args and ipc_params) for an IPC call.
+bool GetArgs(CrossCallParamsEx* params,
+ IPCParams* ipc_params,
+ void* args[kMaxIpcParams]) {
+ if (kMaxIpcParams < params->GetParamsCount())
+ return false;
+
+ for (uint32_t i = 0; i < params->GetParamsCount(); i++) {
+ uint32_t size;
+ ArgType type;
+ args[i] = params->GetRawParameter(i, &size, &type);
+ if (args[i]) {
+ ipc_params->args[i] = type;
+ switch (type) {
+ case WCHAR_TYPE: {
+ std::unique_ptr<std::wstring> data(new std::wstring);
+ if (!params->GetParameterStr(i, data.get())) {
+ args[i] = 0;
+ ReleaseArgs(ipc_params, args);
+ return false;
+ }
+ args[i] = data.release();
+ break;
+ }
+ case UINT32_TYPE: {
+ uint32_t data;
+ if (!params->GetParameter32(i, &data)) {
+ ReleaseArgs(ipc_params, args);
+ return false;
+ }
+ IPCInt ipc_int(data);
+ args[i] = ipc_int.AsVoidPtr();
+ break;
+ }
+ case VOIDPTR_TYPE: {
+ void* data;
+ if (!params->GetParameterVoidPtr(i, &data)) {
+ ReleaseArgs(ipc_params, args);
+ return false;
+ }
+ args[i] = data;
+ break;
+ }
+ case INPTR_TYPE:
+ case INOUTPTR_TYPE: {
+ if (!args[i]) {
+ ReleaseArgs(ipc_params, args);
+ return false;
+ }
+ CountedBuffer* buffer = new CountedBuffer(args[i], size);
+ args[i] = buffer;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/ipc_args.h b/security/sandbox/chromium/sandbox/win/src/ipc_args.h
new file mode 100644
index 0000000000..58b7507dee
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/ipc_args.h
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_IPC_ARGS_H_
+#define SANDBOX_WIN_SRC_IPC_ARGS_H_
+
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/crosscall_server.h"
+
+namespace sandbox {
+
+// Releases memory allocated for IPC arguments.
+void ReleaseArgs(const IPCParams* ipc_params, void* args[kMaxIpcParams]);
+
+// Fills up the list of arguments (args and ipc_params) for an IPC call.
+// Call ReleaseArgs on |ipc_params| and |args| after calling this.
+bool GetArgs(CrossCallParamsEx* params,
+ IPCParams* ipc_params,
+ void* args[kMaxIpcParams]);
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_IPC_ARGS_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/ipc_ping_test.cc b/security/sandbox/chromium/sandbox/win/src/ipc_ping_test.cc
new file mode 100644
index 0000000000..44f6be433d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/ipc_ping_test.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Tests that the IPC is working by issuing a special IPC that is not exposed
+// in the public API.
+SBOX_TESTS_COMMAND int IPC_Ping(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED;
+
+ TargetServices* ts = SandboxFactory::GetTargetServices();
+ if (!ts)
+ return SBOX_TEST_FAILED;
+
+ // Downcast because we have internal knowledge of the object returned.
+ TargetServicesBase* ts_base = reinterpret_cast<TargetServicesBase*>(ts);
+
+ int version = 0;
+ if (L'1' == argv[0][0])
+ version = 1;
+ else
+ version = 2;
+
+ if (!ts_base->TestIPCPing(version))
+ return SBOX_TEST_FAILED;
+
+ ::Sleep(1);
+ if (!ts_base->TestIPCPing(version))
+ return SBOX_TEST_FAILED;
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// The IPC ping test should work before and after the token drop.
+TEST(IPCTest, IPCPingTestSimple) {
+ TestRunner runner;
+ runner.SetTimeout(2000);
+ runner.SetTestState(EVERY_STATE);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"IPC_Ping 1"));
+}
+
+TEST(IPCTest, IPCPingTestWithOutput) {
+ TestRunner runner;
+ runner.SetTimeout(2000);
+ runner.SetTestState(EVERY_STATE);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"IPC_Ping 2"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"IPC_Ping 2"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/ipc_tags.h b/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
new file mode 100644
index 0000000000..ec6de4a66a
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_IPC_TAGS_H__
+#define SANDBOX_SRC_IPC_TAGS_H__
+
+namespace sandbox {
+
+enum class IpcTag {
+ UNUSED = 0,
+ PING1, // Takes a cookie in parameters and returns the cookie
+ // multiplied by 2 and the tick_count. Used for testing only.
+ PING2, // Takes an in/out cookie in parameters and modify the cookie
+ // to be multiplied by 3. Used for testing only.
+ NTCREATEFILE,
+ NTOPENFILE,
+ NTQUERYATTRIBUTESFILE,
+ NTQUERYFULLATTRIBUTESFILE,
+ NTSETINFO_RENAME,
+ CREATENAMEDPIPEW,
+ NTOPENTHREAD,
+ NTOPENPROCESS,
+ NTOPENPROCESSTOKEN,
+ NTOPENPROCESSTOKENEX,
+ CREATEPROCESSW,
+ CREATEEVENT,
+ OPENEVENT,
+ NTCREATEKEY,
+ NTOPENKEY,
+ DUPLICATEHANDLEPROXY,
+ GDI_GDIDLLINITIALIZE,
+ GDI_GETSTOCKOBJECT,
+ USER_REGISTERCLASSW,
+ CREATETHREAD,
+ USER_ENUMDISPLAYMONITORS,
+ USER_ENUMDISPLAYDEVICES,
+ USER_GETMONITORINFO,
+ GDI_CREATEOPMPROTECTEDOUTPUTS,
+ GDI_GETCERTIFICATE,
+ GDI_GETCERTIFICATESIZE,
+ GDI_DESTROYOPMPROTECTEDOUTPUT,
+ GDI_CONFIGUREOPMPROTECTEDOUTPUT,
+ GDI_GETOPMINFORMATION,
+ GDI_GETOPMRANDOMNUMBER,
+ GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE,
+ GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS,
+ NTCREATESECTION,
+ GETCOMPLEXLINEBREAKS,
+ LAST
+};
+
+constexpr size_t kMaxServiceCount = 64;
+constexpr size_t kMaxIpcTag = static_cast<size_t>(IpcTag::LAST);
+static_assert(kMaxIpcTag <= kMaxServiceCount, "kMaxServiceCount is too low");
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_IPC_TAGS_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/ipc_unittest.cc b/security/sandbox/chromium/sandbox/win/src/ipc_unittest.cc
new file mode 100644
index 0000000000..71f7aff4cc
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/ipc_unittest.cc
@@ -0,0 +1,632 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Helper function to make the fake shared memory with some
+// basic elements initialized.
+IPCControl* MakeChannels(size_t channel_size,
+ size_t total_shared_size,
+ size_t* base_start) {
+ // Allocate memory
+ char* mem = new char[total_shared_size];
+ memset(mem, 0, total_shared_size);
+ // Calculate how many channels we can fit in the shared memory.
+ total_shared_size -= offsetof(IPCControl, channels);
+ size_t channel_count =
+ total_shared_size / (sizeof(ChannelControl) + channel_size);
+ // Calculate the start of the first channel.
+ *base_start =
+ (sizeof(ChannelControl) * channel_count) + offsetof(IPCControl, channels);
+ // Setup client structure.
+ IPCControl* client_control = reinterpret_cast<IPCControl*>(mem);
+ client_control->channels_count = channel_count;
+ return client_control;
+}
+
+enum TestFixMode { FIX_NO_EVENTS, FIX_PONG_READY, FIX_PONG_NOT_READY };
+
+void FixChannels(IPCControl* client_control,
+ size_t base_start,
+ size_t channel_size,
+ TestFixMode mode) {
+ for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
+ ChannelControl& channel = client_control->channels[ix];
+ channel.channel_base = base_start;
+ channel.state = kFreeChannel;
+ if (mode != FIX_NO_EVENTS) {
+ bool signaled = (FIX_PONG_READY == mode) ? true : false;
+ channel.ping_event = ::CreateEventW(nullptr, false, false, nullptr);
+ channel.pong_event = ::CreateEventW(nullptr, false, signaled, nullptr);
+ }
+ base_start += channel_size;
+ }
+}
+
+void CloseChannelEvents(IPCControl* client_control) {
+ for (size_t ix = 0; ix != client_control->channels_count; ++ix) {
+ ChannelControl& channel = client_control->channels[ix];
+ ::CloseHandle(channel.ping_event);
+ ::CloseHandle(channel.pong_event);
+ }
+}
+
+TEST(IPCTest, ChannelMaker) {
+ // Test that our testing rig is computing offsets properly. We should have
+ // 5 channnels and the offset to the first channel is 108 bytes in 32 bits
+ // and 216 in 64 bits.
+ size_t channel_start = 0;
+ IPCControl* client_control = MakeChannels(12 * 64, 4096, &channel_start);
+ ASSERT_TRUE(client_control);
+ EXPECT_EQ(5u, client_control->channels_count);
+#if defined(_WIN64)
+ EXPECT_EQ(216u, channel_start);
+#else
+ EXPECT_EQ(108u, channel_start);
+#endif
+ delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, ClientLockUnlock) {
+ // Make 7 channels of kIPCChannelSize (1kb) each. Test that we lock and
+ // unlock channels properly.
+ size_t base_start = 0;
+ IPCControl* client_control =
+ MakeChannels(kIPCChannelSize, 4096 * 2, &base_start);
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_NO_EVENTS);
+
+ char* mem = reinterpret_cast<char*>(client_control);
+ SharedMemIPCClient client(mem);
+
+ // Test that we lock the first 3 channels in sequence.
+ void* buff0 = client.GetBuffer();
+ EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+ void* buff1 = client.GetBuffer();
+ EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+ void* buff2 = client.GetBuffer();
+ EXPECT_TRUE(mem + client_control->channels[2].channel_base == buff2);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+ // Test that we unlock and re-lock the right channel.
+ client.FreeBuffer(buff1);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+ void* buff2b = client.GetBuffer();
+ EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff2b);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+ client.FreeBuffer(buff0);
+ EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[2].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[3].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[4].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[5].state);
+
+ delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, CrossCallStrPacking) {
+ // This test tries the CrossCall object with null and non-null string
+ // combination of parameters, integer types and verifies that the unpacker
+ // can read them properly.
+ size_t base_start = 0;
+ IPCControl* client_control =
+ MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
+ client_control->server_alive = HANDLE(1);
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
+
+ char* mem = reinterpret_cast<char*>(client_control);
+ SharedMemIPCClient client(mem);
+
+ CrossCallReturn answer;
+ IpcTag tag1 = IpcTag::PING1;
+ const wchar_t* text = L"98765 - 43210";
+ std::wstring copied_text;
+ CrossCallParamsEx* actual_params;
+
+ CrossCall(client, tag1, text, &answer);
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+ EXPECT_EQ(1u, actual_params->GetParamsCount());
+ EXPECT_EQ(tag1, actual_params->GetTag());
+ EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
+ EXPECT_STREQ(text, copied_text.c_str());
+ copied_text.clear();
+
+ // Check with an empty string.
+ IpcTag tag2 = IpcTag::PING2;
+ const wchar_t* null_text = nullptr;
+ CrossCall(client, tag2, null_text, &answer);
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+ EXPECT_EQ(1u, actual_params->GetParamsCount());
+ EXPECT_EQ(tag2, actual_params->GetTag());
+ uint32_t param_size = 1;
+ ArgType type = INVALID_TYPE;
+ void* param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+ EXPECT_TRUE(param_addr);
+ EXPECT_EQ(0u, param_size);
+ EXPECT_EQ(WCHAR_TYPE, type);
+ EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
+ EXPECT_TRUE(copied_text.empty());
+
+ IpcTag tag3 = IpcTag::PING1;
+ param_size = 1;
+ copied_text.clear();
+
+ // Check with an empty string and a non-empty string.
+ CrossCall(client, tag3, null_text, text, &answer);
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+ EXPECT_EQ(2u, actual_params->GetParamsCount());
+ EXPECT_EQ(tag3, actual_params->GetTag());
+ type = INVALID_TYPE;
+ param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+ EXPECT_TRUE(param_addr);
+ EXPECT_EQ(0u, param_size);
+ EXPECT_EQ(WCHAR_TYPE, type);
+ EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text));
+ EXPECT_TRUE(copied_text.empty());
+ EXPECT_TRUE(actual_params->GetParameterStr(1, &copied_text));
+ EXPECT_STREQ(text, copied_text.c_str());
+
+ param_size = 1;
+ std::wstring copied_text_p0, copied_text_p2;
+
+ const wchar_t* text2 = L"AeFG";
+ CrossCall(client, tag1, text2, null_text, text, &answer);
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+ EXPECT_EQ(3u, actual_params->GetParamsCount());
+ EXPECT_EQ(tag1, actual_params->GetTag());
+ EXPECT_TRUE(actual_params->GetParameterStr(0, &copied_text_p0));
+ EXPECT_STREQ(text2, copied_text_p0.c_str());
+ EXPECT_TRUE(actual_params->GetParameterStr(2, &copied_text_p2));
+ EXPECT_STREQ(text, copied_text_p2.c_str());
+ type = INVALID_TYPE;
+ param_addr = actual_params->GetRawParameter(1, &param_size, &type);
+ EXPECT_TRUE(param_addr);
+ EXPECT_EQ(0u, param_size);
+ EXPECT_EQ(WCHAR_TYPE, type);
+
+ CloseChannelEvents(client_control);
+ delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, CrossCallIntPacking) {
+ // Check handling for regular 32 bit integers used in Windows.
+ size_t base_start = 0;
+ IPCControl* client_control =
+ MakeChannels(kIPCChannelSize, 4096 * 4, &base_start);
+ client_control->server_alive = HANDLE(1);
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
+
+ IpcTag tag1 = IpcTag::PING1;
+ IpcTag tag2 = IpcTag::PING2;
+ const wchar_t* text = L"godzilla";
+ CrossCallParamsEx* actual_params;
+
+ char* mem = reinterpret_cast<char*>(client_control);
+ SharedMemIPCClient client(mem);
+
+ CrossCallReturn answer;
+ DWORD dw = 0xE6578;
+ CrossCall(client, tag2, dw, &answer);
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+ EXPECT_EQ(1u, actual_params->GetParamsCount());
+ EXPECT_EQ(tag2, actual_params->GetTag());
+ ArgType type = INVALID_TYPE;
+ uint32_t param_size = 1;
+ void* param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+ ASSERT_EQ(sizeof(dw), param_size);
+ EXPECT_EQ(UINT32_TYPE, type);
+ ASSERT_TRUE(param_addr);
+ EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
+
+ // Check handling for windows HANDLES.
+ HANDLE h = HANDLE(0x70000500);
+ CrossCall(client, tag1, text, h, &answer);
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+ EXPECT_EQ(2u, actual_params->GetParamsCount());
+ EXPECT_EQ(tag1, actual_params->GetTag());
+ type = INVALID_TYPE;
+ param_addr = actual_params->GetRawParameter(1, &param_size, &type);
+ ASSERT_EQ(sizeof(h), param_size);
+ EXPECT_EQ(VOIDPTR_TYPE, type);
+ ASSERT_TRUE(param_addr);
+ EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
+
+ // Check combination of 32 and 64 bits.
+ CrossCall(client, tag2, h, dw, h, &answer);
+ actual_params = reinterpret_cast<CrossCallParamsEx*>(client.GetBuffer());
+ EXPECT_EQ(3u, actual_params->GetParamsCount());
+ EXPECT_EQ(tag2, actual_params->GetTag());
+ type = INVALID_TYPE;
+ param_addr = actual_params->GetRawParameter(0, &param_size, &type);
+ ASSERT_EQ(sizeof(h), param_size);
+ EXPECT_EQ(VOIDPTR_TYPE, type);
+ ASSERT_TRUE(param_addr);
+ EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
+ type = INVALID_TYPE;
+ param_addr = actual_params->GetRawParameter(1, &param_size, &type);
+ ASSERT_EQ(sizeof(dw), param_size);
+ EXPECT_EQ(UINT32_TYPE, type);
+ ASSERT_TRUE(param_addr);
+ EXPECT_EQ(0, memcmp(&dw, param_addr, param_size));
+ type = INVALID_TYPE;
+ param_addr = actual_params->GetRawParameter(2, &param_size, &type);
+ ASSERT_EQ(sizeof(h), param_size);
+ EXPECT_EQ(VOIDPTR_TYPE, type);
+ ASSERT_TRUE(param_addr);
+ EXPECT_EQ(0, memcmp(&h, param_addr, param_size));
+
+ CloseChannelEvents(client_control);
+ delete[] reinterpret_cast<char*>(client_control);
+}
+
+TEST(IPCTest, CrossCallValidation) {
+ // First a sanity test with a well formed parameter object.
+ unsigned long value = 124816;
+ IpcTag kTag = IpcTag::PING1;
+ const uint32_t kBufferSize = 256;
+ ActualCallParams<1, kBufferSize> params_1(kTag);
+ params_1.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+ void* buffer = const_cast<void*>(params_1.GetBuffer());
+
+ uint32_t out_size = 0;
+ CrossCallParamsEx* ccp = 0;
+ ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
+ &out_size);
+ ASSERT_TRUE(ccp);
+ EXPECT_TRUE(ccp->GetBuffer() != buffer);
+ EXPECT_EQ(kTag, ccp->GetTag());
+ EXPECT_EQ(1u, ccp->GetParamsCount());
+ delete[](reinterpret_cast<char*>(ccp));
+
+ // Test that we handle integer overflow on the number of params
+ // correctly. We use a test-only ctor for ActualCallParams that
+ // allows to create malformed cross-call buffers.
+ const int32_t kPtrDiffSz = sizeof(ptrdiff_t);
+ for (int32_t ix = -1; ix != 3; ++ix) {
+ uint32_t fake_num_params = (UINT32_MAX / kPtrDiffSz) + ix;
+ ActualCallParams<1, kBufferSize> params_2(kTag, fake_num_params);
+ params_2.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+ buffer = const_cast<void*>(params_2.GetBuffer());
+
+ EXPECT_TRUE(buffer);
+ ccp = CrossCallParamsEx::CreateFromBuffer(buffer, params_1.GetSize(),
+ &out_size);
+ // If the buffer is malformed the return is nullptr.
+ EXPECT_TRUE(!ccp);
+ }
+
+ ActualCallParams<1, kBufferSize> params_3(kTag, 1);
+ params_3.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+ buffer = const_cast<void*>(params_3.GetBuffer());
+ EXPECT_TRUE(buffer);
+
+ uint32_t correct_size = params_3.OverrideSize(1);
+ ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+ EXPECT_TRUE(!ccp);
+
+ // The correct_size is 8 bytes aligned.
+ params_3.OverrideSize(correct_size - 7);
+ ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+ EXPECT_TRUE(!ccp);
+
+ params_3.OverrideSize(correct_size);
+ ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+ EXPECT_TRUE(ccp);
+
+ // Make sure that two parameters work as expected.
+ ActualCallParams<2, kBufferSize> params_4(kTag, 2);
+ params_4.CopyParamIn(0, &value, sizeof(value), false, UINT32_TYPE);
+ params_4.CopyParamIn(1, buffer, sizeof(buffer), false, VOIDPTR_TYPE);
+ buffer = const_cast<void*>(params_4.GetBuffer());
+ EXPECT_TRUE(buffer);
+
+ ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+ EXPECT_TRUE(ccp);
+
+#if defined(_WIN64)
+ correct_size = params_4.OverrideSize(1);
+ params_4.OverrideSize(correct_size - 1);
+ ccp = CrossCallParamsEx::CreateFromBuffer(buffer, kBufferSize, &out_size);
+ EXPECT_TRUE(!ccp);
+#endif
+}
+
+// This structure is passed to the mock server threads to simulate
+// the server side IPC so it has the required kernel objects.
+struct ServerEvents {
+ HANDLE ping;
+ HANDLE pong;
+ volatile LONG* state;
+ HANDLE mutex;
+};
+
+// This is the server thread that quicky answers an IPC and exits.
+DWORD WINAPI QuickResponseServer(PVOID param) {
+ ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
+ DWORD wait_result = 0;
+ wait_result = ::WaitForSingleObject(events->ping, INFINITE);
+ ::InterlockedExchange(events->state, kAckChannel);
+ ::SetEvent(events->pong);
+ return wait_result;
+}
+
+class CrossCallParamsMock : public CrossCallParams {
+ public:
+ CrossCallParamsMock(IpcTag tag, uint32_t params_count)
+ : CrossCallParams(tag, params_count) {}
+};
+
+void FakeOkAnswerInChannel(void* channel) {
+ CrossCallReturn* answer = reinterpret_cast<CrossCallReturn*>(channel);
+ answer->call_outcome = SBOX_ALL_OK;
+}
+
+// Create two threads that will quickly answer IPCs; the first one
+// using channel 1 (channel 0 is busy) and one using channel 0. No time-out
+// should occur.
+TEST(IPCTest, ClientFastServer) {
+ const size_t channel_size = kIPCChannelSize;
+ size_t base_start = 0;
+ IPCControl* client_control =
+ MakeChannels(channel_size, 4096 * 2, &base_start);
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
+ client_control->server_alive = ::CreateMutex(nullptr, false, nullptr);
+
+ char* mem = reinterpret_cast<char*>(client_control);
+ SharedMemIPCClient client(mem);
+
+ ServerEvents events = {0};
+ events.ping = client_control->channels[1].ping_event;
+ events.pong = client_control->channels[1].pong_event;
+ events.state = &client_control->channels[1].state;
+
+ HANDLE t1 =
+ ::CreateThread(nullptr, 0, QuickResponseServer, &events, 0, nullptr);
+ ASSERT_TRUE(t1);
+ ::CloseHandle(t1);
+
+ void* buff0 = client.GetBuffer();
+ EXPECT_TRUE(mem + client_control->channels[0].channel_base == buff0);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+ void* buff1 = client.GetBuffer();
+ EXPECT_TRUE(mem + client_control->channels[1].channel_base == buff1);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kBusyChannel, client_control->channels[1].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+ EXPECT_EQ(IpcTag::UNUSED, client_control->channels[1].ipc_tag);
+
+ IpcTag tag = IpcTag::PING1;
+ CrossCallReturn answer;
+ CrossCallParamsMock* params1 = new (buff1) CrossCallParamsMock(tag, 1);
+ FakeOkAnswerInChannel(buff1);
+
+ ResultCode result = client.DoCall(params1, &answer);
+ if (SBOX_ERROR_CHANNEL_ERROR != result)
+ client.FreeBuffer(buff1);
+
+ EXPECT_TRUE(SBOX_ALL_OK == result);
+ EXPECT_EQ(tag, client_control->channels[1].ipc_tag);
+ EXPECT_EQ(kBusyChannel, client_control->channels[0].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+ HANDLE t2 =
+ ::CreateThread(nullptr, 0, QuickResponseServer, &events, 0, nullptr);
+ ASSERT_TRUE(t2);
+ ::CloseHandle(t2);
+
+ client.FreeBuffer(buff0);
+ events.ping = client_control->channels[0].ping_event;
+ events.pong = client_control->channels[0].pong_event;
+ events.state = &client_control->channels[0].state;
+
+ tag = IpcTag::PING2;
+ CrossCallParamsMock* params2 = new (buff0) CrossCallParamsMock(tag, 1);
+ FakeOkAnswerInChannel(buff0);
+
+ result = client.DoCall(params2, &answer);
+ if (SBOX_ERROR_CHANNEL_ERROR != result)
+ client.FreeBuffer(buff0);
+
+ EXPECT_TRUE(SBOX_ALL_OK == result);
+ EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
+ EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[1].state);
+ EXPECT_EQ(kFreeChannel, client_control->channels[2].state);
+
+ CloseChannelEvents(client_control);
+ ::CloseHandle(client_control->server_alive);
+
+ delete[] reinterpret_cast<char*>(client_control);
+}
+
+// This is the server thread that very slowly answers an IPC and exits. Note
+// that the pong event needs to be signaled twice.
+DWORD WINAPI SlowResponseServer(PVOID param) {
+ ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
+ DWORD wait_result = 0;
+ wait_result = ::WaitForSingleObject(events->ping, INFINITE);
+ ::Sleep(kIPCWaitTimeOut1 + kIPCWaitTimeOut2 + 200);
+ ::InterlockedExchange(events->state, kAckChannel);
+ ::SetEvent(events->pong);
+ return wait_result;
+}
+
+// This thread's job is to keep the mutex locked.
+DWORD WINAPI MainServerThread(PVOID param) {
+ ServerEvents* events = reinterpret_cast<ServerEvents*>(param);
+ DWORD wait_result = 0;
+ wait_result = ::WaitForSingleObject(events->mutex, INFINITE);
+ Sleep(kIPCWaitTimeOut1 * 20);
+ return wait_result;
+}
+
+// Creates a server thread that answers the IPC so slow that is guaranteed to
+// trigger the time-out code path in the client. A second thread is created
+// to hold locked the server_alive mutex: this signals the client that the
+// server is not dead and it retries the wait.
+TEST(IPCTest, ClientSlowServer) {
+ size_t base_start = 0;
+ IPCControl* client_control =
+ MakeChannels(kIPCChannelSize, 4096 * 2, &base_start);
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_NOT_READY);
+ client_control->server_alive = ::CreateMutex(nullptr, false, nullptr);
+
+ char* mem = reinterpret_cast<char*>(client_control);
+ SharedMemIPCClient client(mem);
+
+ ServerEvents events = {0};
+ events.ping = client_control->channels[0].ping_event;
+ events.pong = client_control->channels[0].pong_event;
+ events.state = &client_control->channels[0].state;
+
+ HANDLE t1 =
+ ::CreateThread(nullptr, 0, SlowResponseServer, &events, 0, nullptr);
+ ASSERT_TRUE(t1);
+ ::CloseHandle(t1);
+
+ ServerEvents events2 = {0};
+ events2.pong = events.pong;
+ events2.mutex = client_control->server_alive;
+
+ HANDLE t2 =
+ ::CreateThread(nullptr, 0, MainServerThread, &events2, 0, nullptr);
+ ASSERT_TRUE(t2);
+ ::CloseHandle(t2);
+
+ ::Sleep(1);
+
+ void* buff0 = client.GetBuffer();
+ IpcTag tag = IpcTag::PING1;
+ CrossCallReturn answer;
+ CrossCallParamsMock* params1 = new (buff0) CrossCallParamsMock(tag, 1);
+ FakeOkAnswerInChannel(buff0);
+
+ ResultCode result = client.DoCall(params1, &answer);
+ if (SBOX_ERROR_CHANNEL_ERROR != result)
+ client.FreeBuffer(buff0);
+
+ EXPECT_TRUE(SBOX_ALL_OK == result);
+ EXPECT_EQ(tag, client_control->channels[0].ipc_tag);
+ EXPECT_EQ(kFreeChannel, client_control->channels[0].state);
+
+ CloseChannelEvents(client_control);
+ ::CloseHandle(client_control->server_alive);
+ delete[] reinterpret_cast<char*>(client_control);
+}
+
+// This test-only IPC dispatcher has two handlers with the same signature
+// but only CallOneHandler should be used.
+class UnitTestIPCDispatcher : public Dispatcher {
+ public:
+ UnitTestIPCDispatcher();
+ ~UnitTestIPCDispatcher() override {}
+
+ bool SetupService(InterceptionManager* manager, IpcTag service) override {
+ return true;
+ }
+
+ private:
+ bool CallOneHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) {
+ ipc->return_info.extended[0].handle = p1;
+ ipc->return_info.extended[1].unsigned_int = p2;
+ return true;
+ }
+
+ bool CallTwoHandler(IPCInfo* ipc, HANDLE p1, uint32_t p2) { return true; }
+};
+
+UnitTestIPCDispatcher::UnitTestIPCDispatcher() {
+ static const IPCCall call_one = {{IpcTag::PING1, {VOIDPTR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &UnitTestIPCDispatcher::CallOneHandler)};
+ static const IPCCall call_two = {{IpcTag::PING2, {VOIDPTR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &UnitTestIPCDispatcher::CallTwoHandler)};
+ ipc_calls_.push_back(call_one);
+ ipc_calls_.push_back(call_two);
+}
+
+// This test does most of the shared memory IPC client-server roundtrip
+// and tests the packing, unpacking and call dispatching.
+TEST(IPCTest, SharedMemServerTests) {
+ size_t base_start = 0;
+ IPCControl* client_control = MakeChannels(kIPCChannelSize, 4096, &base_start);
+ client_control->server_alive = HANDLE(1);
+ FixChannels(client_control, base_start, kIPCChannelSize, FIX_PONG_READY);
+
+ char* mem = reinterpret_cast<char*>(client_control);
+ SharedMemIPCClient client(mem);
+
+ CrossCallReturn answer;
+ HANDLE bar = HANDLE(191919);
+ DWORD foo = 6767676;
+ CrossCall(client, IpcTag::PING1, bar, foo, &answer);
+ void* buff = client.GetBuffer();
+ ASSERT_TRUE(buff);
+
+ UnitTestIPCDispatcher dispatcher;
+ // Since we are directly calling InvokeCallback, most of this structure
+ // can be set to nullptr.
+ sandbox::SharedMemIPCServer::ServerControl srv_control = {};
+ srv_control.channel_size = kIPCChannelSize;
+ srv_control.shared_base = reinterpret_cast<char*>(client_control);
+ srv_control.dispatcher = &dispatcher;
+
+ sandbox::CrossCallReturn call_return = {0};
+ EXPECT_TRUE(
+ SharedMemIPCServer::InvokeCallback(&srv_control, buff, &call_return));
+ EXPECT_EQ(SBOX_ALL_OK, call_return.call_outcome);
+ EXPECT_TRUE(bar == call_return.extended[0].handle);
+ EXPECT_EQ(foo, call_return.extended[1].unsigned_int);
+
+ CloseChannelEvents(client_control);
+ delete[] reinterpret_cast<char*>(client_control);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/job.cc b/security/sandbox/chromium/sandbox/win/src/job.cc
new file mode 100644
index 0000000000..39baffb193
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/job.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/job.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/restricted_token.h"
+
+namespace sandbox {
+
+Job::Job() : job_handle_(nullptr) {}
+
+Job::~Job() {}
+
+DWORD Job::Init(JobLevel security_level,
+ const wchar_t* job_name,
+ DWORD ui_exceptions,
+ size_t memory_limit) {
+ if (job_handle_.IsValid())
+ return ERROR_ALREADY_INITIALIZED;
+
+ job_handle_.Set(::CreateJobObject(nullptr, // No security attribute
+ job_name));
+ if (!job_handle_.IsValid())
+ return ::GetLastError();
+
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {};
+ JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {};
+
+ // Set the settings for the different security levels. Note: The higher levels
+ // inherit from the lower levels.
+ switch (security_level) {
+ case JOB_LOCKDOWN: {
+ jeli.BasicLimitInformation.LimitFlags |=
+ JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
+ FALLTHROUGH;
+ }
+ case JOB_RESTRICTED: {
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_READCLIPBOARD;
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_GLOBALATOMS;
+ FALLTHROUGH;
+ }
+ case JOB_LIMITED_USER: {
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;
+ jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
+ jeli.BasicLimitInformation.ActiveProcessLimit = 1;
+ FALLTHROUGH;
+ }
+ case JOB_INTERACTIVE: {
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DESKTOP;
+ jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
+ FALLTHROUGH;
+ }
+ case JOB_UNPROTECTED: {
+ if (memory_limit) {
+ jeli.BasicLimitInformation.LimitFlags |=
+ JOB_OBJECT_LIMIT_PROCESS_MEMORY;
+ jeli.ProcessMemoryLimit = memory_limit;
+ }
+
+ jeli.BasicLimitInformation.LimitFlags |=
+ JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+ break;
+ }
+ default: { return ERROR_BAD_ARGUMENTS; }
+ }
+
+ if (!::SetInformationJobObject(job_handle_.Get(),
+ JobObjectExtendedLimitInformation, &jeli,
+ sizeof(jeli))) {
+ return ::GetLastError();
+ }
+
+ jbur.UIRestrictionsClass = jbur.UIRestrictionsClass & (~ui_exceptions);
+ if (!::SetInformationJobObject(job_handle_.Get(),
+ JobObjectBasicUIRestrictions, &jbur,
+ sizeof(jbur))) {
+ return ::GetLastError();
+ }
+
+ return ERROR_SUCCESS;
+}
+
+DWORD Job::UserHandleGrantAccess(HANDLE handle) {
+ if (!job_handle_.IsValid())
+ return ERROR_NO_DATA;
+
+ if (!::UserHandleGrantAccess(handle, job_handle_.Get(),
+ true)) { // Access allowed.
+ return ::GetLastError();
+ }
+
+ return ERROR_SUCCESS;
+}
+
+base::win::ScopedHandle Job::Take() {
+ return std::move(job_handle_);
+}
+
+DWORD Job::AssignProcessToJob(HANDLE process_handle) {
+ if (!job_handle_.IsValid())
+ return ERROR_NO_DATA;
+
+ if (!::AssignProcessToJobObject(job_handle_.Get(), process_handle))
+ return ::GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/job.h b/security/sandbox/chromium/sandbox/win/src/job.h
new file mode 100644
index 0000000000..153080bf6b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/job.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_JOB_H_
+#define SANDBOX_SRC_JOB_H_
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+
+namespace sandbox {
+
+// Handles the creation of job objects based on a security profile.
+// Sample usage:
+// Job job;
+// job.Init(JOB_LOCKDOWN, nullptr); //no job name
+// job.AssignProcessToJob(process_handle);
+class Job {
+ public:
+ Job();
+
+ ~Job();
+
+ // Initializes and creates the job object. The security of the job is based
+ // on the security_level parameter.
+ // job_name can be nullptr if the job is unnamed.
+ // If the chosen profile has too many ui restrictions, you can disable some
+ // by specifying them in the ui_exceptions parameters.
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD Init(JobLevel security_level,
+ const wchar_t* job_name,
+ DWORD ui_exceptions,
+ size_t memory_limit);
+
+ // Assigns the process referenced by process_handle to the job.
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD AssignProcessToJob(HANDLE process_handle);
+
+ // Grants access to "handle" to the job. All processes in the job can
+ // subsequently recognize and use the handle.
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD UserHandleGrantAccess(HANDLE handle);
+
+ // Revokes ownership to the job handle and returns it.
+ // If the object is not yet initialized, it returns an invalid handle.
+ base::win::ScopedHandle Take();
+
+ private:
+ // Handle to the job referenced by the object.
+ base::win::ScopedHandle job_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(Job);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_JOB_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/job_unittest.cc b/security/sandbox/chromium/sandbox/win/src/job_unittest.cc
new file mode 100644
index 0000000000..536900dc40
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/job_unittest.cc
@@ -0,0 +1,197 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for the job object.
+
+#include "sandbox/win/src/job.h"
+
+#include "base/win/scoped_process_information.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Tests the creation and destruction of the job.
+TEST(JobTest, TestCreation) {
+ // Scope the creation of Job.
+ {
+ // Create the job.
+ Job job;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+
+ // check if the job exists.
+ HANDLE job_handle =
+ ::OpenJobObjectW(GENERIC_ALL, false, L"my_test_job_name");
+ ASSERT_TRUE(job_handle);
+
+ if (job_handle)
+ CloseHandle(job_handle);
+ }
+
+ // Check if the job is destroyed when the object goes out of scope.
+ HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, false, L"my_test_job_name");
+ ASSERT_TRUE(!job_handle);
+ ASSERT_EQ(static_cast<DWORD>(ERROR_FILE_NOT_FOUND), ::GetLastError());
+}
+
+// Tests the method "Take".
+TEST(JobTest, Take) {
+ base::win::ScopedHandle job_handle;
+ // Scope the creation of Job.
+ {
+ // Create the job.
+ Job job;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+
+ job_handle = job.Take();
+ ASSERT_TRUE(job_handle.IsValid());
+ }
+
+ // Check to be sure that the job is still alive even after the object is gone
+ // out of scope.
+ HANDLE job_handle_dup =
+ ::OpenJobObjectW(GENERIC_ALL, false, L"my_test_job_name");
+ ASSERT_TRUE(job_handle_dup);
+
+ // Remove all references.
+ if (job_handle_dup)
+ ::CloseHandle(job_handle_dup);
+
+ job_handle.Close();
+
+ // Check if the jbo is really dead.
+ job_handle_dup = ::OpenJobObjectW(GENERIC_ALL, false, L"my_test_job_name");
+ ASSERT_TRUE(!job_handle_dup);
+ ASSERT_EQ(static_cast<DWORD>(ERROR_FILE_NOT_FOUND), ::GetLastError());
+}
+
+// Tests the ui exceptions
+TEST(JobTest, TestExceptions) {
+ base::win::ScopedHandle job_handle;
+ // Scope the creation of Job.
+ {
+ // Create the job.
+ Job job;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job.Init(JOB_LOCKDOWN, L"my_test_job_name",
+ JOB_OBJECT_UILIMIT_READCLIPBOARD, 0));
+
+ job_handle = job.Take();
+ ASSERT_TRUE(job_handle.IsValid());
+
+ JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
+ DWORD size = sizeof(jbur);
+ ASSERT_TRUE(::QueryInformationJobObject(
+ job_handle.Get(), JobObjectBasicUIRestrictions, &jbur, size, &size));
+
+ ASSERT_EQ(0u, jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD);
+ job_handle.Close();
+ }
+
+ // Scope the creation of Job.
+ {
+ // Create the job.
+ Job job;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+
+ job_handle = job.Take();
+ ASSERT_TRUE(job_handle.IsValid());
+
+ JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
+ DWORD size = sizeof(jbur);
+ ASSERT_TRUE(::QueryInformationJobObject(
+ job_handle.Get(), JobObjectBasicUIRestrictions, &jbur, size, &size));
+
+ ASSERT_EQ(static_cast<DWORD>(JOB_OBJECT_UILIMIT_READCLIPBOARD),
+ jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD);
+ }
+}
+
+// Tests the error case when the job is initialized twice.
+TEST(JobTest, DoubleInit) {
+ // Create the job.
+ Job job;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_ALREADY_INITIALIZED),
+ job.Init(JOB_LOCKDOWN, L"test", 0, 0));
+}
+
+// Tests the error case when we use a method and the object is not yet
+// initialized.
+TEST(JobTest, NoInit) {
+ Job job;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_NO_DATA),
+ job.UserHandleGrantAccess(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_NO_DATA), job.AssignProcessToJob(nullptr));
+ ASSERT_FALSE(job.Take().IsValid());
+}
+
+// Tests the initialization of the job with different security level.
+TEST(JobTest, SecurityLevel) {
+ Job job1;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job1.Init(JOB_LOCKDOWN, L"job1", 0, 0));
+
+ Job job2;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job2.Init(JOB_RESTRICTED, L"job2", 0, 0));
+
+ Job job3;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job3.Init(JOB_LIMITED_USER, L"job3", 0, 0));
+
+ Job job4;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job4.Init(JOB_INTERACTIVE, L"job4", 0, 0));
+
+ Job job5;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job5.Init(JOB_UNPROTECTED, L"job5", 0, 0));
+
+ // JOB_NONE means we run without a job object so Init should fail.
+ Job job6;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_BAD_ARGUMENTS),
+ job6.Init(JOB_NONE, L"job6", 0, 0));
+
+ Job job7;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_BAD_ARGUMENTS),
+ job7.Init(static_cast<JobLevel>(JOB_NONE + 1), L"job7", 0, 0));
+}
+
+// Tests the method "AssignProcessToJob".
+TEST(JobTest, ProcessInJob) {
+ // Create the job.
+ Job job;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job.Init(JOB_UNPROTECTED, L"job_test_process", 0, 0));
+
+ wchar_t notepad[] = L"notepad";
+ STARTUPINFO si = {sizeof(si)};
+ PROCESS_INFORMATION temp_process_info = {};
+ ASSERT_TRUE(::CreateProcess(nullptr, notepad, nullptr, nullptr, false, 0,
+ nullptr, nullptr, &si, &temp_process_info));
+ base::win::ScopedProcessInformation pi(temp_process_info);
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ job.AssignProcessToJob(pi.process_handle()));
+
+ // Get the job handle.
+ base::win::ScopedHandle job_handle = job.Take();
+
+ // Check if the process is in the job.
+ JOBOBJECT_BASIC_PROCESS_ID_LIST jbpidl = {0};
+ DWORD size = sizeof(jbpidl);
+ EXPECT_TRUE(::QueryInformationJobObject(
+ job_handle.Get(), JobObjectBasicProcessIdList, &jbpidl, size, &size));
+
+ EXPECT_EQ(1u, jbpidl.NumberOfAssignedProcesses);
+ EXPECT_EQ(1u, jbpidl.NumberOfProcessIdsInList);
+ EXPECT_EQ(pi.process_id(), jbpidl.ProcessIdList[0]);
+
+ EXPECT_TRUE(::TerminateProcess(pi.process_handle(), 0));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.cc
new file mode 100644
index 0000000000..85ffebe6e6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/named_pipe_dispatcher.h"
+
+#include <stdint.h>
+
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/named_pipe_interception.h"
+#include "sandbox/win/src/named_pipe_policy.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+
+namespace sandbox {
+
+NamedPipeDispatcher::NamedPipeDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall create_params = {
+ {IpcTag::CREATENAMEDPIPEW,
+ {WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE,
+ UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&NamedPipeDispatcher::CreateNamedPipe)};
+
+ ipc_calls_.push_back(create_params);
+}
+
+bool NamedPipeDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ if (IpcTag::CREATENAMEDPIPEW == service)
+ return INTERCEPT_EAT(manager, kKerneldllName, CreateNamedPipeW,
+ CREATE_NAMED_PIPE_ID, 36);
+
+ return false;
+}
+
+bool NamedPipeDispatcher::CreateNamedPipe(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t open_mode,
+ uint32_t pipe_mode,
+ uint32_t max_instances,
+ uint32_t out_buffer_size,
+ uint32_t in_buffer_size,
+ uint32_t default_timeout) {
+ ipc->return_info.win32_result = ERROR_ACCESS_DENIED;
+ ipc->return_info.handle = INVALID_HANDLE_VALUE;
+
+ base::StringPiece16 dotdot(STRING16_LITERAL(".."));
+
+ for (const base::StringPiece16& path : base::SplitStringPiece(
+ base::AsStringPiece16(*name), STRING16_LITERAL("/"),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ for (const base::StringPiece16& inner :
+ base::SplitStringPiece(path, STRING16_LITERAL("\\"),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ if (inner == dotdot)
+ return true;
+ }
+ }
+
+ const wchar_t* pipe_name = name->c_str();
+ CountedParameterSet<NameBased> params;
+ params[NameBased::NAME] = ParamPickerMake(pipe_name);
+
+ EvalResult eval =
+ policy_base_->EvalPolicy(IpcTag::CREATENAMEDPIPEW, params.GetBase());
+
+ // "For file I/O, the "\\?\" prefix to a path string tells the Windows APIs to
+ // disable all string parsing and to send the string that follows it straight
+ // to the file system."
+ // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
+ // This ensures even if there is a path traversal in the pipe name, and it is
+ // able to get past the checks above, it will still not be allowed to escape
+ // our allowed namespace.
+ if (name->compare(0, 4, L"\\\\.\\") == 0)
+ name->replace(0, 4, L"\\\\\?\\");
+
+ HANDLE pipe;
+ DWORD ret = NamedPipePolicy::CreateNamedPipeAction(
+ eval, *ipc->client_info, *name, open_mode, pipe_mode, max_instances,
+ out_buffer_size, in_buffer_size, default_timeout, &pipe);
+
+ ipc->return_info.win32_result = ret;
+ ipc->return_info.handle = pipe;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.h
new file mode 100644
index 0000000000..a14f658506
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/named_pipe_dispatcher.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_NAMED_PIPE_DISPATCHER_H__
+#define SANDBOX_SRC_NAMED_PIPE_DISPATCHER_H__
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles named pipe related IPC calls.
+class NamedPipeDispatcher : public Dispatcher {
+ public:
+ explicit NamedPipeDispatcher(PolicyBase* policy_base);
+ ~NamedPipeDispatcher() override {}
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to CreateNamedPipeW() in the
+ // target.
+ bool CreateNamedPipe(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t open_mode,
+ uint32_t pipe_mode,
+ uint32_t max_instances,
+ uint32_t out_buffer_size,
+ uint32_t in_buffer_size,
+ uint32_t default_timeout);
+
+ PolicyBase* policy_base_;
+ DISALLOW_COPY_AND_ASSIGN(NamedPipeDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_NAMED_PIPE_DISPATCHER_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/named_pipe_interception.cc b/security/sandbox/chromium/sandbox/win/src/named_pipe_interception.cc
new file mode 100644
index 0000000000..aa3d5dc358
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/named_pipe_interception.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/named_pipe_interception.h"
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+
+namespace sandbox {
+
+HANDLE WINAPI
+TargetCreateNamedPipeW(CreateNamedPipeWFunction orig_CreateNamedPipeW,
+ LPCWSTR pipe_name,
+ DWORD open_mode,
+ DWORD pipe_mode,
+ DWORD max_instance,
+ DWORD out_buffer_size,
+ DWORD in_buffer_size,
+ DWORD default_timeout,
+ LPSECURITY_ATTRIBUTES security_attributes) {
+ HANDLE pipe = orig_CreateNamedPipeW(
+ pipe_name, open_mode, pipe_mode, max_instance, out_buffer_size,
+ in_buffer_size, default_timeout, security_attributes);
+ if (INVALID_HANDLE_VALUE != pipe)
+ return pipe;
+
+ mozilla::sandboxing::LogBlocked("CreateNamedPipeW", pipe_name);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return INVALID_HANDLE_VALUE;
+
+ DWORD original_error = ::GetLastError();
+
+ // We don't support specific Security Attributes.
+ if (security_attributes)
+ return INVALID_HANDLE_VALUE;
+
+ do {
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ CountedParameterSet<NameBased> params;
+ params[NameBased::NAME] = ParamPickerMake(pipe_name);
+
+ if (!QueryBroker(IpcTag::CREATENAMEDPIPEW, params.GetBase()))
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code =
+ CrossCall(ipc, IpcTag::CREATENAMEDPIPEW, pipe_name, open_mode,
+ pipe_mode, max_instance, out_buffer_size, in_buffer_size,
+ default_timeout, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ ::SetLastError(answer.win32_result);
+
+ if (ERROR_SUCCESS != answer.win32_result)
+ return INVALID_HANDLE_VALUE;
+
+ mozilla::sandboxing::LogAllowed("CreateNamedPipeW", pipe_name);
+ return answer.handle;
+ } while (false);
+
+ ::SetLastError(original_error);
+ return INVALID_HANDLE_VALUE;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/named_pipe_interception.h b/security/sandbox/chromium/sandbox/win/src/named_pipe_interception.h
new file mode 100644
index 0000000000..8eedd14b31
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/named_pipe_interception.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_NAMED_PIPE_INTERCEPTION_H_
+#define SANDBOX_WIN_SRC_NAMED_PIPE_INTERCEPTION_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+typedef HANDLE(WINAPI* CreateNamedPipeWFunction)(
+ LPCWSTR lpName,
+ DWORD dwOpenMode,
+ DWORD dwPipeMode,
+ DWORD nMaxInstances,
+ DWORD nOutBufferSize,
+ DWORD nInBufferSize,
+ DWORD nDefaultTimeOut,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+
+// Interception of CreateNamedPipeW in kernel32.dll
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateNamedPipeW(CreateNamedPipeWFunction orig_CreateNamedPipeW,
+ LPCWSTR pipe_name,
+ DWORD open_mode,
+ DWORD pipe_mode,
+ DWORD max_instance,
+ DWORD out_buffer_size,
+ DWORD in_buffer_size,
+ DWORD default_timeout,
+ LPSECURITY_ATTRIBUTES security_attributes);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_NAMED_PIPE_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/named_pipe_policy.cc b/security/sandbox/chromium/sandbox/win/src/named_pipe_policy.cc
new file mode 100644
index 0000000000..bfad75852d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/named_pipe_policy.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/named_pipe_policy.h"
+
+#include <string>
+
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace {
+
+// Creates a named pipe and duplicates the handle to 'target_process'. The
+// remaining parameters are the same as CreateNamedPipeW().
+HANDLE CreateNamedPipeHelper(HANDLE target_process,
+ LPCWSTR pipe_name,
+ DWORD open_mode,
+ DWORD pipe_mode,
+ DWORD max_instances,
+ DWORD out_buffer_size,
+ DWORD in_buffer_size,
+ DWORD default_timeout,
+ LPSECURITY_ATTRIBUTES security_attributes) {
+ HANDLE pipe = ::CreateNamedPipeW(
+ pipe_name, open_mode, pipe_mode, max_instances, out_buffer_size,
+ in_buffer_size, default_timeout, security_attributes);
+ if (INVALID_HANDLE_VALUE == pipe)
+ return pipe;
+
+ HANDLE new_pipe;
+ if (!::DuplicateHandle(::GetCurrentProcess(), pipe, target_process, &new_pipe,
+ 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return new_pipe;
+}
+
+} // namespace
+
+namespace sandbox {
+
+bool NamedPipePolicy::GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ if (TargetPolicy::NAMEDPIPES_ALLOW_ANY != semantics) {
+ return false;
+ }
+ PolicyRule pipe(ASK_BROKER);
+ if (!pipe.AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) {
+ return false;
+ }
+ if (!policy->AddRule(IpcTag::CREATENAMEDPIPEW, &pipe)) {
+ return false;
+ }
+ return true;
+}
+
+DWORD NamedPipePolicy::CreateNamedPipeAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& name,
+ DWORD open_mode,
+ DWORD pipe_mode,
+ DWORD max_instances,
+ DWORD out_buffer_size,
+ DWORD in_buffer_size,
+ DWORD default_timeout,
+ HANDLE* pipe) {
+ *pipe = INVALID_HANDLE_VALUE;
+ // The only action supported is ASK_BROKER which means create the pipe.
+ if (ASK_BROKER != eval_result) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ *pipe = CreateNamedPipeHelper(client_info.process, name.c_str(), open_mode,
+ pipe_mode, max_instances, out_buffer_size,
+ in_buffer_size, default_timeout, nullptr);
+
+ if (INVALID_HANDLE_VALUE == *pipe)
+ return ERROR_ACCESS_DENIED;
+
+ return ERROR_SUCCESS;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/named_pipe_policy.h b/security/sandbox/chromium/sandbox/win/src/named_pipe_policy.h
new file mode 100644
index 0000000000..4ad272f16f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/named_pipe_policy.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_NAMED_PIPE_POLICY_H__
+#define SANDBOX_SRC_NAMED_PIPE_POLICY_H__
+
+#include <string>
+
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+// This class centralizes most of the knowledge related to named pipe creation.
+class NamedPipePolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level.
+ // policy rule for named pipe creation
+ // 'name' is the named pipe to be created
+ // 'semantics' is the desired semantics.
+ // 'policy' is the policy generator to which the rules are going to be added.
+ static bool GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ // Processes a 'CreateNamedPipeW()' request from the target.
+ static DWORD CreateNamedPipeAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& name,
+ DWORD open_mode,
+ DWORD pipe_mode,
+ DWORD max_instances,
+ DWORD out_buffer_size,
+ DWORD in_buffer_size,
+ DWORD default_timeout,
+ HANDLE* pipe);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_NAMED_PIPE_POLICY_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/named_pipe_policy_test.cc b/security/sandbox/chromium/sandbox/win/src/named_pipe_policy_test.cc
new file mode 100644
index 0000000000..db532d618d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/named_pipe_policy_test.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/handle_closer.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int NamedPipe_Create(int argc, wchar_t** argv) {
+ if (argc < 1 || argc > 2 || !argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ HANDLE pipe = ::CreateNamedPipeW(
+ argv[0], PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 4096, 4096, 2000, nullptr);
+ if (INVALID_HANDLE_VALUE == pipe)
+ return SBOX_TEST_DENIED;
+
+ // The second parameter allows us to enforce an allowlist for where the
+ // pipe should be in the object namespace after creation.
+ if (argc == 2) {
+ std::wstring handle_name;
+ if (GetHandleName(pipe, &handle_name)) {
+ if (handle_name.compare(0, wcslen(argv[1]), argv[1]) != 0)
+ return SBOX_TEST_FAILED;
+ } else {
+ return SBOX_TEST_FAILED;
+ }
+ }
+
+ OVERLAPPED overlapped = {0};
+ overlapped.hEvent = ::CreateEvent(nullptr, true, true, nullptr);
+ bool result = ::ConnectNamedPipe(pipe, &overlapped);
+
+ if (!result) {
+ DWORD error = ::GetLastError();
+ if (ERROR_PIPE_CONNECTED != error && ERROR_IO_PENDING != error) {
+ return SBOX_TEST_FAILED;
+ }
+ }
+
+ if (!::CloseHandle(pipe))
+ return SBOX_TEST_FAILED;
+
+ ::CloseHandle(overlapped.hEvent);
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests if we can create a pipe in the sandbox.
+TEST(NamedPipePolicyTest, CreatePipe) {
+ TestRunner runner;
+ // TODO(nsylvain): This policy is wrong because "*" is a valid char in a
+ // namedpipe name. Here we apply it like a wildcard. http://b/893603
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_NAMED_PIPES,
+ TargetPolicy::NAMEDPIPES_ALLOW_ANY,
+ L"\\\\.\\pipe\\test*"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\testbleh"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\bleh"));
+}
+
+// Tests if we can create a pipe with a path traversal in the sandbox.
+TEST(NamedPipePolicyTest, CreatePipeTraversal) {
+ TestRunner runner;
+ // TODO(nsylvain): This policy is wrong because "*" is a valid char in a
+ // namedpipe name. Here we apply it like a wildcard. http://b/893603
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_NAMED_PIPES,
+ TargetPolicy::NAMEDPIPES_ALLOW_ANY,
+ L"\\\\.\\pipe\\test*"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test\\..\\bleh"));
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test/../bleh"));
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test\\../bleh"));
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\test/..\\bleh"));
+}
+
+// This tests that path canonicalization is actually disabled if we use \\?\
+// syntax.
+TEST(NamedPipePolicyTest, CreatePipeCanonicalization) {
+ // "For file I/O, the "\\?\" prefix to a path string tells the Windows APIs to
+ // disable all string parsing and to send the string that follows it straight
+ // to the file system."
+ // http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx
+ const wchar_t* argv[2] = {L"\\\\?\\pipe\\test\\..\\bleh",
+ L"\\Device\\NamedPipe\\test"};
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ NamedPipe_Create(2, const_cast<wchar_t**>(argv)));
+}
+
+// The same test as CreatePipe but this time using strict interceptions.
+TEST(NamedPipePolicyTest, CreatePipeStrictInterceptions) {
+ TestRunner runner;
+ runner.GetPolicy()->SetStrictInterceptions();
+
+ // TODO(nsylvain): This policy is wrong because "*" is a valid char in a
+ // namedpipe name. Here we apply it like a wildcard. http://b/893603
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_NAMED_PIPES,
+ TargetPolicy::NAMEDPIPES_ALLOW_ANY,
+ L"\\\\.\\pipe\\test*"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\testbleh"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"NamedPipe_Create \\\\.\\pipe\\bleh"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/nt_internals.h b/security/sandbox/chromium/sandbox/win/src/nt_internals.h
new file mode 100644
index 0000000000..01409c528b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/nt_internals.h
@@ -0,0 +1,986 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file holds definitions related to the ntdll API.
+
+#ifndef SANDBOX_WIN_SRC_NT_INTERNALS_H__
+#define SANDBOX_WIN_SRC_NT_INTERNALS_H__
+
+#include <windows.h>
+
+#include <stddef.h>
+
+typedef LONG NTSTATUS;
+#define NT_SUCCESS(st) (st >= 0)
+#define NT_ERROR(st) ((((ULONG)(st)) >> 30) == 3)
+
+// clang-format off
+#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
+#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
+#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
+#define STATUS_INVALID_INFO_CLASS ((NTSTATUS)0xC0000003L)
+#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
+#ifndef STATUS_INVALID_PARAMETER
+// It is now defined in Windows 2008 SDK.
+#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
+#endif
+#define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS)0xC0000018L)
+#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
+#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
+#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
+#define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS)0xC0000035L)
+#define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS)0xC000007AL)
+#define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS)0xC000007BL)
+#define STATUS_NO_TOKEN ((NTSTATUS)0xC000007CL)
+#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
+#define STATUS_INVALID_IMAGE_HASH ((NTSTATUS)0xC0000428L)
+// clang-format on
+
+#define CURRENT_PROCESS ((HANDLE)-1)
+#define CURRENT_THREAD ((HANDLE)-2)
+#define NtCurrentProcess CURRENT_PROCESS
+
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING;
+typedef UNICODE_STRING* PUNICODE_STRING;
+typedef const UNICODE_STRING* PCUNICODE_STRING;
+
+typedef struct _STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PCHAR Buffer;
+} STRING;
+typedef STRING* PSTRING;
+
+typedef STRING ANSI_STRING;
+typedef PSTRING PANSI_STRING;
+typedef CONST PSTRING PCANSI_STRING;
+
+typedef STRING OEM_STRING;
+typedef PSTRING POEM_STRING;
+typedef CONST STRING* PCOEM_STRING;
+
+#define OBJ_CASE_INSENSITIVE 0x00000040L
+#define OBJ_OPENIF 0x00000080L
+
+typedef struct _OBJECT_ATTRIBUTES {
+ ULONG Length;
+ HANDLE RootDirectory;
+ PUNICODE_STRING ObjectName;
+ ULONG Attributes;
+ PVOID SecurityDescriptor;
+ PVOID SecurityQualityOfService;
+} OBJECT_ATTRIBUTES;
+typedef OBJECT_ATTRIBUTES* POBJECT_ATTRIBUTES;
+
+#define InitializeObjectAttributes(p, n, a, r, s) \
+ { \
+ (p)->Length = sizeof(OBJECT_ATTRIBUTES); \
+ (p)->RootDirectory = r; \
+ (p)->Attributes = a; \
+ (p)->ObjectName = n; \
+ (p)->SecurityDescriptor = s; \
+ (p)->SecurityQualityOfService = nullptr; \
+ }
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+// -----------------------------------------------------------------------
+// File IO
+
+// Create disposition values.
+
+#define FILE_SUPERSEDE 0x00000000
+#define FILE_OPEN 0x00000001
+#define FILE_CREATE 0x00000002
+#define FILE_OPEN_IF 0x00000003
+#define FILE_OVERWRITE 0x00000004
+#define FILE_OVERWRITE_IF 0x00000005
+#define FILE_MAXIMUM_DISPOSITION 0x00000005
+
+// Create/open option flags.
+
+#define FILE_DIRECTORY_FILE 0x00000001
+#define FILE_WRITE_THROUGH 0x00000002
+#define FILE_SEQUENTIAL_ONLY 0x00000004
+#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008
+
+#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+#define FILE_NON_DIRECTORY_FILE 0x00000040
+#define FILE_CREATE_TREE_CONNECTION 0x00000080
+
+#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
+#define FILE_NO_EA_KNOWLEDGE 0x00000200
+#define FILE_OPEN_REMOTE_INSTANCE 0x00000400
+#define FILE_RANDOM_ACCESS 0x00000800
+
+#define FILE_DELETE_ON_CLOSE 0x00001000
+#define FILE_OPEN_BY_FILE_ID 0x00002000
+#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
+#define FILE_NO_COMPRESSION 0x00008000
+
+#define FILE_RESERVE_OPFILTER 0x00100000
+#define FILE_OPEN_REPARSE_POINT 0x00200000
+#define FILE_OPEN_NO_RECALL 0x00400000
+#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
+
+// Create/open result values. These are the disposition values returned on the
+// io status information.
+#define FILE_SUPERSEDED 0x00000000
+#define FILE_OPENED 0x00000001
+#define FILE_CREATED 0x00000002
+#define FILE_OVERWRITTEN 0x00000003
+#define FILE_EXISTS 0x00000004
+#define FILE_DOES_NOT_EXIST 0x00000005
+
+typedef NTSTATUS(WINAPI* NtCreateFileFunction)(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PLARGE_INTEGER AllocationSize OPTIONAL,
+ IN ULONG FileAttributes,
+ IN ULONG ShareAccess,
+ IN ULONG CreateDisposition,
+ IN ULONG CreateOptions,
+ IN PVOID EaBuffer OPTIONAL,
+ IN ULONG EaLength);
+
+typedef NTSTATUS(WINAPI* NtOpenFileFunction)(OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES
+ ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG ShareAccess,
+ IN ULONG OpenOptions);
+
+typedef NTSTATUS(WINAPI* NtCloseFunction)(IN HANDLE Handle);
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FileRenameInformation = 10
+} FILE_INFORMATION_CLASS,
+ *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_RENAME_INFORMATION {
+ BOOLEAN ReplaceIfExists;
+ HANDLE RootDirectory;
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtSetInformationFileFunction)(
+ IN HANDLE FileHandle,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN PVOID FileInformation,
+ IN ULONG Length,
+ IN FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef struct FILE_BASIC_INFORMATION {
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ ULONG FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtQueryAttributesFileFunction)(
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PFILE_BASIC_INFORMATION FileAttributes);
+
+typedef struct _FILE_NETWORK_OPEN_INFORMATION {
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER AllocationSize;
+ LARGE_INTEGER EndOfFile;
+ ULONG FileAttributes;
+} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtQueryFullAttributesFileFunction)(
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PFILE_NETWORK_OPEN_INFORMATION FileAttributes);
+
+// -----------------------------------------------------------------------
+// Sections
+
+typedef NTSTATUS(WINAPI* NtCreateSectionFunction)(
+ OUT PHANDLE SectionHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+ IN PLARGE_INTEGER MaximumSize OPTIONAL,
+ IN ULONG SectionPageProtection,
+ IN ULONG AllocationAttributes,
+ IN HANDLE FileHandle OPTIONAL);
+
+typedef ULONG SECTION_INHERIT;
+#define ViewShare 1
+#define ViewUnmap 2
+
+typedef NTSTATUS(WINAPI* NtMapViewOfSectionFunction)(
+ IN HANDLE SectionHandle,
+ IN HANDLE ProcessHandle,
+ IN OUT PVOID* BaseAddress,
+ IN ULONG_PTR ZeroBits,
+ IN SIZE_T CommitSize,
+ IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
+ IN OUT PSIZE_T ViewSize,
+ IN SECTION_INHERIT InheritDisposition,
+ IN ULONG AllocationType,
+ IN ULONG Win32Protect);
+
+typedef NTSTATUS(WINAPI* NtUnmapViewOfSectionFunction)(IN HANDLE ProcessHandle,
+ IN PVOID BaseAddress);
+
+typedef enum _SECTION_INFORMATION_CLASS {
+ SectionBasicInformation = 0,
+ SectionImageInformation
+} SECTION_INFORMATION_CLASS;
+
+typedef struct _SECTION_BASIC_INFORMATION {
+ PVOID BaseAddress;
+ ULONG Attributes;
+ LARGE_INTEGER Size;
+} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtQuerySectionFunction)(
+ IN HANDLE SectionHandle,
+ IN SECTION_INFORMATION_CLASS SectionInformationClass,
+ OUT PVOID SectionInformation,
+ IN SIZE_T SectionInformationLength,
+ OUT PSIZE_T ReturnLength OPTIONAL);
+
+// -----------------------------------------------------------------------
+// Process and Thread
+
+typedef struct _CLIENT_ID {
+ PVOID UniqueProcess;
+ PVOID UniqueThread;
+} CLIENT_ID, *PCLIENT_ID;
+
+typedef NTSTATUS(WINAPI* NtOpenThreadFunction)(OUT PHANDLE ThreadHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES
+ ObjectAttributes,
+ IN PCLIENT_ID ClientId);
+
+typedef NTSTATUS(WINAPI* NtOpenProcessFunction)(OUT PHANDLE ProcessHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES
+ ObjectAttributes,
+ IN PCLIENT_ID ClientId);
+
+typedef enum _NT_THREAD_INFORMATION_CLASS {
+ ThreadBasicInformation,
+ ThreadTimes,
+ ThreadPriority,
+ ThreadBasePriority,
+ ThreadAffinityMask,
+ ThreadImpersonationToken,
+ ThreadDescriptorTableEntry,
+ ThreadEnableAlignmentFaultFixup,
+ ThreadEventPair,
+ ThreadQuerySetWin32StartAddress,
+ ThreadZeroTlsCell,
+ ThreadPerformanceCount,
+ ThreadAmILastThread,
+ ThreadIdealProcessor,
+ ThreadPriorityBoost,
+ ThreadSetTlsArrayAddress,
+ ThreadIsIoPending,
+ ThreadHideFromDebugger
+} NT_THREAD_INFORMATION_CLASS,
+ *PNT_THREAD_INFORMATION_CLASS;
+
+typedef NTSTATUS(WINAPI* NtImpersonateAnonymousTokenFunction)(
+ IN HANDLE ThreadHandle);
+
+typedef NTSTATUS(WINAPI* NtSetInformationThreadFunction)(
+ IN HANDLE ThreadHandle,
+ IN NT_THREAD_INFORMATION_CLASS ThreadInformationClass,
+ IN PVOID ThreadInformation,
+ IN ULONG ThreadInformationLength);
+
+// Partial definition only:
+typedef enum _PROCESSINFOCLASS {
+ ProcessBasicInformation = 0,
+ ProcessExecuteFlags = 0x22
+} PROCESSINFOCLASS;
+
+// For the structure documentation, see
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa813741(v=vs.85).aspx
+typedef struct _RTL_USER_PROCESS_PARAMETERS {
+ BYTE Reserved1[16];
+ PVOID Reserved2[10];
+ UNICODE_STRING ImagePathName;
+ UNICODE_STRING CommandLine;
+} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
+
+// Partial definition only, from
+// https://msdn.microsoft.com/en-us/library/windows/desktop/aa813706(v=vs.85).aspx
+typedef struct _PEB {
+ BYTE InheritedAddressSpace;
+ BYTE ReadImageFileExecOptions;
+ BYTE BeingDebugged;
+ BYTE SpareBool;
+ PVOID Mutant;
+ PVOID ImageBaseAddress;
+ PVOID Ldr;
+ PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
+} PEB, *PPEB;
+
+typedef LONG KPRIORITY;
+
+typedef struct _PROCESS_BASIC_INFORMATION {
+ union {
+ NTSTATUS ExitStatus;
+ PVOID padding_for_x64_0;
+ };
+ PPEB PebBaseAddress;
+ KAFFINITY AffinityMask;
+ union {
+ KPRIORITY BasePriority;
+ PVOID padding_for_x64_1;
+ };
+ union {
+ DWORD UniqueProcessId;
+ PVOID padding_for_x64_2;
+ };
+ union {
+ DWORD InheritedFromUniqueProcessId;
+ PVOID padding_for_x64_3;
+ };
+} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtQueryInformationProcessFunction)(
+ IN HANDLE ProcessHandle,
+ IN PROCESSINFOCLASS ProcessInformationClass,
+ OUT PVOID ProcessInformation,
+ IN ULONG ProcessInformationLength,
+ OUT PULONG ReturnLength OPTIONAL);
+
+typedef NTSTATUS(WINAPI* NtSetInformationProcessFunction)(
+ HANDLE ProcessHandle,
+ IN PROCESSINFOCLASS ProcessInformationClass,
+ IN PVOID ProcessInformation,
+ IN ULONG ProcessInformationLength);
+
+typedef NTSTATUS(WINAPI* NtOpenThreadTokenFunction)(IN HANDLE ThreadHandle,
+ IN ACCESS_MASK
+ DesiredAccess,
+ IN BOOLEAN OpenAsSelf,
+ OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS(WINAPI* NtOpenThreadTokenExFunction)(IN HANDLE ThreadHandle,
+ IN ACCESS_MASK
+ DesiredAccess,
+ IN BOOLEAN OpenAsSelf,
+ IN ULONG HandleAttributes,
+ OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS(WINAPI* NtOpenProcessTokenFunction)(IN HANDLE ProcessHandle,
+ IN ACCESS_MASK
+ DesiredAccess,
+ OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS(WINAPI* NtOpenProcessTokenExFunction)(
+ IN HANDLE ProcessHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN ULONG HandleAttributes,
+ OUT PHANDLE TokenHandle);
+
+typedef NTSTATUS(WINAPI* NtQueryInformationTokenFunction)(
+ IN HANDLE TokenHandle,
+ IN TOKEN_INFORMATION_CLASS TokenInformationClass,
+ OUT PVOID TokenInformation,
+ IN ULONG TokenInformationLength,
+ OUT PULONG ReturnLength);
+
+typedef NTSTATUS(WINAPI* RtlCreateUserThreadFunction)(
+ IN HANDLE Process,
+ IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
+ IN BOOLEAN CreateSuspended,
+ IN ULONG ZeroBits,
+ IN SIZE_T MaximumStackSize,
+ IN SIZE_T CommittedStackSize,
+ IN LPTHREAD_START_ROUTINE StartAddress,
+ IN PVOID Parameter,
+ OUT PHANDLE Thread,
+ OUT PCLIENT_ID ClientId);
+
+typedef NTSTATUS(WINAPI* RtlConvertSidToUnicodeStringFunction)(
+ OUT PUNICODE_STRING UnicodeString,
+ IN PSID Sid,
+ IN BOOLEAN AllocateDestinationString);
+
+typedef VOID(WINAPI* RtlFreeUnicodeStringFunction)(
+ IN OUT PUNICODE_STRING UnicodeString);
+
+// -----------------------------------------------------------------------
+// Registry
+
+typedef enum _KEY_INFORMATION_CLASS {
+ KeyBasicInformation = 0,
+ KeyFullInformation = 2
+} KEY_INFORMATION_CLASS,
+ *PKEY_INFORMATION_CLASS;
+
+typedef struct _KEY_BASIC_INFORMATION {
+ LARGE_INTEGER LastWriteTime;
+ ULONG TitleIndex;
+ ULONG NameLength;
+ WCHAR Name[1];
+} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;
+
+typedef struct _KEY_FULL_INFORMATION {
+ LARGE_INTEGER LastWriteTime;
+ ULONG TitleIndex;
+ ULONG ClassOffset;
+ ULONG ClassLength;
+ ULONG SubKeys;
+ ULONG MaxNameLen;
+ ULONG MaxClassLen;
+ ULONG Values;
+ ULONG MaxValueNameLen;
+ ULONG MaxValueDataLen;
+ WCHAR Class[1];
+} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION;
+
+typedef enum _KEY_VALUE_INFORMATION_CLASS {
+ KeyValueFullInformation = 1
+} KEY_VALUE_INFORMATION_CLASS,
+ *PKEY_VALUE_INFORMATION_CLASS;
+
+typedef struct _KEY_VALUE_FULL_INFORMATION {
+ ULONG TitleIndex;
+ ULONG Type;
+ ULONG DataOffset;
+ ULONG DataLength;
+ ULONG NameLength;
+ WCHAR Name[1];
+} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtCreateKeyFunction)(OUT PHANDLE KeyHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES
+ ObjectAttributes,
+ IN ULONG TitleIndex,
+ IN PUNICODE_STRING Class OPTIONAL,
+ IN ULONG CreateOptions,
+ OUT PULONG Disposition OPTIONAL);
+
+typedef NTSTATUS(WINAPI* NtOpenKeyFunction)(OUT PHANDLE KeyHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES
+ ObjectAttributes);
+
+typedef NTSTATUS(WINAPI* NtOpenKeyExFunction)(OUT PHANDLE KeyHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES
+ ObjectAttributes,
+ IN DWORD open_options);
+
+typedef NTSTATUS(WINAPI* NtDeleteKeyFunction)(IN HANDLE KeyHandle);
+
+typedef NTSTATUS(WINAPI* RtlFormatCurrentUserKeyPathFunction)(
+ OUT PUNICODE_STRING RegistryPath);
+
+typedef NTSTATUS(WINAPI* NtQueryKeyFunction)(IN HANDLE KeyHandle,
+ IN KEY_INFORMATION_CLASS
+ KeyInformationClass,
+ OUT PVOID KeyInformation,
+ IN ULONG Length,
+ OUT PULONG ResultLength);
+
+typedef NTSTATUS(WINAPI* NtEnumerateKeyFunction)(IN HANDLE KeyHandle,
+ IN ULONG Index,
+ IN KEY_INFORMATION_CLASS
+ KeyInformationClass,
+ OUT PVOID KeyInformation,
+ IN ULONG Length,
+ OUT PULONG ResultLength);
+
+typedef NTSTATUS(WINAPI* NtQueryValueKeyFunction)(IN HANDLE KeyHandle,
+ IN PUNICODE_STRING ValueName,
+ IN KEY_VALUE_INFORMATION_CLASS
+ KeyValueInformationClass,
+ OUT PVOID KeyValueInformation,
+ IN ULONG Length,
+ OUT PULONG ResultLength);
+
+typedef NTSTATUS(WINAPI* NtSetValueKeyFunction)(IN HANDLE KeyHandle,
+ IN PUNICODE_STRING ValueName,
+ IN ULONG TitleIndex OPTIONAL,
+ IN ULONG Type,
+ IN PVOID Data,
+ IN ULONG DataSize);
+
+// -----------------------------------------------------------------------
+// Memory
+
+// Don't really need this structure right now.
+typedef PVOID PRTL_HEAP_PARAMETERS;
+
+typedef PVOID(WINAPI* RtlCreateHeapFunction)(IN ULONG Flags,
+ IN PVOID HeapBase OPTIONAL,
+ IN SIZE_T ReserveSize OPTIONAL,
+ IN SIZE_T CommitSize OPTIONAL,
+ IN PVOID Lock OPTIONAL,
+ IN PRTL_HEAP_PARAMETERS Parameters
+ OPTIONAL);
+
+typedef PVOID(WINAPI* RtlDestroyHeapFunction)(IN PVOID HeapHandle);
+
+typedef PVOID(WINAPI* RtlAllocateHeapFunction)(IN PVOID HeapHandle,
+ IN ULONG Flags,
+ IN SIZE_T Size);
+
+typedef BOOLEAN(WINAPI* RtlFreeHeapFunction)(IN PVOID HeapHandle,
+ IN ULONG Flags,
+ IN PVOID HeapBase);
+
+typedef NTSTATUS(WINAPI* NtAllocateVirtualMemoryFunction)(
+ IN HANDLE ProcessHandle,
+ IN OUT PVOID* BaseAddress,
+ IN ULONG_PTR ZeroBits,
+ IN OUT PSIZE_T RegionSize,
+ IN ULONG AllocationType,
+ IN ULONG Protect);
+
+typedef NTSTATUS(WINAPI* NtFreeVirtualMemoryFunction)(IN HANDLE ProcessHandle,
+ IN OUT PVOID* BaseAddress,
+ IN OUT PSIZE_T RegionSize,
+ IN ULONG FreeType);
+
+typedef enum _MEMORY_INFORMATION_CLASS {
+ MemoryBasicInformation = 0,
+ MemoryWorkingSetList,
+ MemorySectionName,
+ MemoryBasicVlmInformation
+} MEMORY_INFORMATION_CLASS;
+
+typedef struct _MEMORY_SECTION_NAME { // Information Class 2
+ UNICODE_STRING SectionFileName;
+} MEMORY_SECTION_NAME, *PMEMORY_SECTION_NAME;
+
+typedef NTSTATUS(WINAPI* NtQueryVirtualMemoryFunction)(
+ IN HANDLE ProcessHandle,
+ IN PVOID BaseAddress,
+ IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
+ OUT PVOID MemoryInformation,
+ IN SIZE_T MemoryInformationLength,
+ OUT PSIZE_T ReturnLength OPTIONAL);
+
+typedef NTSTATUS(WINAPI* NtProtectVirtualMemoryFunction)(
+ IN HANDLE ProcessHandle,
+ IN OUT PVOID* BaseAddress,
+ IN OUT PSIZE_T ProtectSize,
+ IN ULONG NewProtect,
+ OUT PULONG OldProtect);
+
+// -----------------------------------------------------------------------
+// Objects
+
+typedef enum _OBJECT_INFORMATION_CLASS {
+ ObjectBasicInformation,
+ ObjectNameInformation,
+ ObjectTypeInformation,
+ ObjectAllInformation,
+ ObjectDataInformation
+} OBJECT_INFORMATION_CLASS,
+ *POBJECT_INFORMATION_CLASS;
+
+typedef struct _OBJDIR_INFORMATION {
+ UNICODE_STRING ObjectName;
+ UNICODE_STRING ObjectTypeName;
+ BYTE Data[1];
+} OBJDIR_INFORMATION;
+
+typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
+ ULONG Attributes;
+ ACCESS_MASK GrantedAccess;
+ ULONG HandleCount;
+ ULONG PointerCount;
+ ULONG Reserved[10]; // reserved for internal use
+} PUBLIC_OBJECT_BASIC_INFORMATION, *PPUBLIC_OBJECT_BASIC_INFORMATION;
+
+typedef struct __PUBLIC_OBJECT_TYPE_INFORMATION {
+ UNICODE_STRING TypeName;
+ ULONG Reserved[22]; // reserved for internal use
+} PUBLIC_OBJECT_TYPE_INFORMATION, *PPUBLIC_OBJECT_TYPE_INFORMATION;
+
+typedef enum _POOL_TYPE {
+ NonPagedPool,
+ PagedPool,
+ NonPagedPoolMustSucceed,
+ ReservedType,
+ NonPagedPoolCacheAligned,
+ PagedPoolCacheAligned,
+ NonPagedPoolCacheAlignedMustS
+} POOL_TYPE;
+
+typedef struct _OBJECT_BASIC_INFORMATION {
+ ULONG Attributes;
+ ACCESS_MASK GrantedAccess;
+ ULONG HandleCount;
+ ULONG PointerCount;
+ ULONG PagedPoolUsage;
+ ULONG NonPagedPoolUsage;
+ ULONG Reserved[3];
+ ULONG NameInformationLength;
+ ULONG TypeInformationLength;
+ ULONG SecurityDescriptorLength;
+ LARGE_INTEGER CreateTime;
+} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
+
+typedef struct _OBJECT_TYPE_INFORMATION {
+ UNICODE_STRING Name;
+ ULONG TotalNumberOfObjects;
+ ULONG TotalNumberOfHandles;
+ ULONG TotalPagedPoolUsage;
+ ULONG TotalNonPagedPoolUsage;
+ ULONG TotalNamePoolUsage;
+ ULONG TotalHandleTableUsage;
+ ULONG HighWaterNumberOfObjects;
+ ULONG HighWaterNumberOfHandles;
+ ULONG HighWaterPagedPoolUsage;
+ ULONG HighWaterNonPagedPoolUsage;
+ ULONG HighWaterNamePoolUsage;
+ ULONG HighWaterHandleTableUsage;
+ ULONG InvalidAttributes;
+ GENERIC_MAPPING GenericMapping;
+ ULONG ValidAccess;
+ BOOLEAN SecurityRequired;
+ BOOLEAN MaintainHandleCount;
+ USHORT MaintainTypeList;
+ POOL_TYPE PoolType;
+ ULONG PagedPoolUsage;
+ ULONG NonPagedPoolUsage;
+} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
+
+typedef enum _SYSTEM_INFORMATION_CLASS {
+ SystemHandleInformation = 16
+} SYSTEM_INFORMATION_CLASS;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION {
+ USHORT ProcessId;
+ USHORT CreatorBackTraceIndex;
+ UCHAR ObjectTypeNumber;
+ UCHAR Flags;
+ USHORT Handle;
+ PVOID Object;
+ ACCESS_MASK GrantedAccess;
+} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
+ ULONG NumberOfHandles;
+ SYSTEM_HANDLE_INFORMATION Information[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
+typedef struct _OBJECT_NAME_INFORMATION {
+ UNICODE_STRING ObjectName;
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef NTSTATUS(WINAPI* NtQueryObjectFunction)(
+ IN HANDLE Handle,
+ IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ OUT PVOID ObjectInformation OPTIONAL,
+ IN ULONG ObjectInformationLength,
+ OUT PULONG ReturnLength OPTIONAL);
+
+typedef NTSTATUS(WINAPI* NtDuplicateObjectFunction)(IN HANDLE SourceProcess,
+ IN HANDLE SourceHandle,
+ IN HANDLE TargetProcess,
+ OUT PHANDLE TargetHandle,
+ IN ACCESS_MASK
+ DesiredAccess,
+ IN ULONG Attributes,
+ IN ULONG Options);
+
+typedef NTSTATUS(WINAPI* NtSignalAndWaitForSingleObjectFunction)(
+ IN HANDLE HandleToSignal,
+ IN HANDLE HandleToWait,
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER Timeout OPTIONAL);
+
+typedef NTSTATUS(WINAPI* NtWaitForSingleObjectFunction)(
+ IN HANDLE ObjectHandle,
+ IN BOOLEAN Alertable,
+ IN PLARGE_INTEGER TimeOut OPTIONAL);
+
+typedef NTSTATUS(WINAPI* NtQuerySystemInformation)(
+ IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
+ OUT PVOID SystemInformation,
+ IN ULONG SystemInformationLength,
+ OUT PULONG ReturnLength);
+
+typedef NTSTATUS(WINAPI* NtQueryObject)(IN HANDLE Handle,
+ IN OBJECT_INFORMATION_CLASS
+ ObjectInformationClass,
+ OUT PVOID ObjectInformation,
+ IN ULONG ObjectInformationLength,
+ OUT PULONG ReturnLength);
+
+// -----------------------------------------------------------------------
+// Strings
+
+typedef int(__cdecl* _strnicmpFunction)(IN const char* _Str1,
+ IN const char* _Str2,
+ IN size_t _MaxCount);
+
+typedef size_t(__cdecl* strlenFunction)(IN const char* _Str);
+
+typedef size_t(__cdecl* wcslenFunction)(IN const wchar_t* _Str);
+
+typedef void*(__cdecl* memcpyFunction)(IN void* dest,
+ IN const void* src,
+ IN size_t count);
+
+typedef NTSTATUS(WINAPI* RtlAnsiStringToUnicodeStringFunction)(
+ IN OUT PUNICODE_STRING DestinationString,
+ IN PANSI_STRING SourceString,
+ IN BOOLEAN AllocateDestinationString);
+
+typedef LONG(WINAPI* RtlCompareUnicodeStringFunction)(
+ IN PCUNICODE_STRING String1,
+ IN PCUNICODE_STRING String2,
+ IN BOOLEAN CaseInSensitive);
+
+typedef VOID(WINAPI* RtlInitUnicodeStringFunction)(IN OUT PUNICODE_STRING
+ DestinationString,
+ IN PCWSTR SourceString);
+
+typedef ULONG(WINAPI* RtlNtStatusToDosErrorFunction)(NTSTATUS status);
+
+typedef enum _EVENT_TYPE {
+ NotificationEvent,
+ SynchronizationEvent
+} EVENT_TYPE,
+ *PEVENT_TYPE;
+
+typedef NTSTATUS(WINAPI* NtCreateDirectoryObjectFunction)(
+ PHANDLE DirectoryHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS(WINAPI* NtOpenDirectoryObjectFunction)(
+ PHANDLE DirectoryHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes);
+
+typedef NTSTATUS(WINAPI* NtQuerySymbolicLinkObjectFunction)(
+ HANDLE LinkHandle,
+ PUNICODE_STRING LinkTarget,
+ PULONG ReturnedLength);
+
+typedef NTSTATUS(WINAPI* NtOpenSymbolicLinkObjectFunction)(
+ PHANDLE LinkHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes);
+
+#define DIRECTORY_QUERY 0x0001
+#define DIRECTORY_TRAVERSE 0x0002
+#define DIRECTORY_CREATE_OBJECT 0x0004
+#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
+#define DIRECTORY_ALL_ACCESS 0x000F
+
+typedef NTSTATUS(WINAPI* NtCreateLowBoxToken)(
+ OUT PHANDLE token,
+ IN HANDLE original_handle,
+ IN ACCESS_MASK access,
+ IN POBJECT_ATTRIBUTES object_attribute,
+ IN PSID appcontainer_sid,
+ IN DWORD capabilityCount,
+ IN PSID_AND_ATTRIBUTES capabilities,
+ IN DWORD handle_count,
+ IN PHANDLE handles);
+
+typedef NTSTATUS(WINAPI* NtSetInformationProcess)(IN HANDLE process_handle,
+ IN ULONG info_class,
+ IN PVOID process_information,
+ IN ULONG information_length);
+
+struct PROCESS_ACCESS_TOKEN {
+ HANDLE token;
+ HANDLE thread;
+};
+
+const unsigned int NtProcessInformationAccessToken = 9;
+
+typedef NTSTATUS(WINAPI* RtlDeriveCapabilitySidsFromNameFunction)(
+ PCUNICODE_STRING SourceString,
+ PSID CapabilityGroupSid,
+ PSID CapabilitySid);
+
+// -----------------------------------------------------------------------
+// GDI OPM API and Supported Calls
+
+#define DXGKMDT_OPM_OMAC_SIZE 16
+#define DXGKMDT_OPM_128_BIT_RANDOM_NUMBER_SIZE 16
+#define DXGKMDT_OPM_ENCRYPTED_PARAMETERS_SIZE 256
+#define DXGKMDT_OPM_CONFIGURE_SETTING_DATA_SIZE 4056
+#define DXGKMDT_OPM_GET_INFORMATION_PARAMETERS_SIZE 4056
+#define DXGKMDT_OPM_REQUESTED_INFORMATION_SIZE 4076
+#define DXGKMDT_OPM_HDCP_KEY_SELECTION_VECTOR_SIZE 5
+#define DXGKMDT_OPM_PROTECTION_TYPE_SIZE 4
+
+enum DXGKMDT_CERTIFICATE_TYPE {
+ DXGKMDT_OPM_CERTIFICATE = 0,
+ DXGKMDT_COPP_CERTIFICATE = 1,
+ DXGKMDT_UAB_CERTIFICATE = 2,
+ DXGKMDT_FORCE_ULONG = 0xFFFFFFFF
+};
+
+enum DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS {
+ DXGKMDT_OPM_VOS_COPP_SEMANTICS = 0,
+ DXGKMDT_OPM_VOS_OPM_SEMANTICS = 1
+};
+
+enum DXGKMDT_DPCP_PROTECTION_LEVEL {
+ DXGKMDT_OPM_DPCP_OFF = 0,
+ DXGKMDT_OPM_DPCP_ON = 1,
+ DXGKMDT_OPM_DPCP_FORCE_ULONG = 0x7fffffff
+};
+
+enum DXGKMDT_OPM_HDCP_PROTECTION_LEVEL {
+ DXGKMDT_OPM_HDCP_OFF = 0,
+ DXGKMDT_OPM_HDCP_ON = 1,
+ DXGKMDT_OPM_HDCP_FORCE_ULONG = 0x7fffffff
+};
+
+enum DXGKMDT_OPM_HDCP_FLAG {
+ DXGKMDT_OPM_HDCP_FLAG_NONE = 0x00,
+ DXGKMDT_OPM_HDCP_FLAG_REPEATER = 0x01
+};
+
+enum DXGKMDT_OPM_PROTECTION_TYPE {
+ DXGKMDT_OPM_PROTECTION_TYPE_OTHER = 0x80000000,
+ DXGKMDT_OPM_PROTECTION_TYPE_NONE = 0x00000000,
+ DXGKMDT_OPM_PROTECTION_TYPE_COPP_COMPATIBLE_HDCP = 0x00000001,
+ DXGKMDT_OPM_PROTECTION_TYPE_ACP = 0x00000002,
+ DXGKMDT_OPM_PROTECTION_TYPE_CGMSA = 0x00000004,
+ DXGKMDT_OPM_PROTECTION_TYPE_HDCP = 0x00000008,
+ DXGKMDT_OPM_PROTECTION_TYPE_DPCP = 0x00000010,
+ DXGKMDT_OPM_PROTECTION_TYPE_MASK = 0x8000001F
+};
+
+typedef void* OPM_PROTECTED_OUTPUT_HANDLE;
+
+struct DXGKMDT_OPM_ENCRYPTED_PARAMETERS {
+ BYTE abEncryptedParameters[DXGKMDT_OPM_ENCRYPTED_PARAMETERS_SIZE];
+};
+
+struct DXGKMDT_OPM_OMAC {
+ BYTE abOMAC[DXGKMDT_OPM_OMAC_SIZE];
+};
+
+struct DXGKMDT_OPM_CONFIGURE_PARAMETERS {
+ DXGKMDT_OPM_OMAC omac;
+ GUID guidSetting;
+ ULONG ulSequenceNumber;
+ ULONG cbParametersSize;
+ BYTE abParameters[DXGKMDT_OPM_CONFIGURE_SETTING_DATA_SIZE];
+};
+
+struct DXGKMDT_OPM_RANDOM_NUMBER {
+ BYTE abRandomNumber[DXGKMDT_OPM_128_BIT_RANDOM_NUMBER_SIZE];
+};
+
+struct DXGKMDT_OPM_GET_INFO_PARAMETERS {
+ DXGKMDT_OPM_OMAC omac;
+ DXGKMDT_OPM_RANDOM_NUMBER rnRandomNumber;
+ GUID guidInformation;
+ ULONG ulSequenceNumber;
+ ULONG cbParametersSize;
+ BYTE abParameters[DXGKMDT_OPM_GET_INFORMATION_PARAMETERS_SIZE];
+};
+
+struct DXGKMDT_OPM_REQUESTED_INFORMATION {
+ DXGKMDT_OPM_OMAC omac;
+ ULONG cbRequestedInformationSize;
+ BYTE abRequestedInformation[DXGKMDT_OPM_REQUESTED_INFORMATION_SIZE];
+};
+
+struct DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS {
+ ULONG ulProtectionType;
+ ULONG ulProtectionLevel;
+ ULONG Reserved;
+ ULONG Reserved2;
+};
+
+struct DXGKMDT_OPM_STANDARD_INFORMATION {
+ DXGKMDT_OPM_RANDOM_NUMBER rnRandomNumber;
+ ULONG ulStatusFlags;
+ ULONG ulInformation;
+ ULONG ulReserved;
+ ULONG ulReserved2;
+};
+
+typedef NTSTATUS(WINAPI* GetSuggestedOPMProtectedOutputArraySizeFunction)(
+ PUNICODE_STRING device_name,
+ DWORD* suggested_output_array_size);
+
+typedef NTSTATUS(WINAPI* CreateOPMProtectedOutputsFunction)(
+ PUNICODE_STRING device_name,
+ DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
+ DWORD output_array_size,
+ DWORD* num_in_output_array,
+ OPM_PROTECTED_OUTPUT_HANDLE* output_array);
+
+typedef NTSTATUS(WINAPI* GetCertificateFunction)(
+ PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length);
+
+typedef NTSTATUS(WINAPI* GetCertificateSizeFunction)(
+ PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length);
+
+typedef NTSTATUS(WINAPI* GetCertificateByHandleFunction)(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length);
+
+typedef NTSTATUS(WINAPI* GetCertificateSizeByHandleFunction)(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length);
+
+typedef NTSTATUS(WINAPI* DestroyOPMProtectedOutputFunction)(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output);
+
+typedef NTSTATUS(WINAPI* ConfigureOPMProtectedOutputFunction)(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
+ ULONG additional_parameters_size,
+ const BYTE* additional_parameters);
+
+typedef NTSTATUS(WINAPI* GetOPMInformationFunction)(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
+ DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information);
+
+typedef NTSTATUS(WINAPI* GetOPMRandomNumberFunction)(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_OPM_RANDOM_NUMBER* random_number);
+
+typedef NTSTATUS(WINAPI* SetOPMSigningKeyAndSequenceNumbersFunction)(
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters);
+
+#endif // SANDBOX_WIN_SRC_NT_INTERNALS_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_broker.cc b/security/sandbox/chromium/sandbox/win/src/policy_broker.cc
new file mode 100644
index 0000000000..200bfa3236
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_broker.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/policy_broker.h"
+
+#include <stddef.h>
+
+#include <map>
+
+#include "base/logging.h"
+#include "base/win/pe_image.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/target_process.h"
+
+// This code executes on the broker side, as a callback from the policy on the
+// target side (the child).
+
+namespace sandbox {
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+#define INIT_GLOBAL_NT(member) \
+ g_nt.member = reinterpret_cast<Nt##member##Function>( \
+ ntdll_image.GetProcAddress("Nt" #member)); \
+ if (!g_nt.member) \
+ return false
+
+#define INIT_GLOBAL_RTL(member) \
+ g_nt.member = \
+ reinterpret_cast<member##Function>(ntdll_image.GetProcAddress(#member)); \
+ if (!g_nt.member) \
+ return false
+
+bool InitGlobalNt() {
+ HMODULE ntdll = ::GetModuleHandle(kNtdllName);
+ base::win::PEImage ntdll_image(ntdll);
+
+ INIT_GLOBAL_NT(AllocateVirtualMemory);
+ INIT_GLOBAL_NT(Close);
+ INIT_GLOBAL_NT(DuplicateObject);
+ INIT_GLOBAL_NT(FreeVirtualMemory);
+ INIT_GLOBAL_NT(MapViewOfSection);
+ INIT_GLOBAL_NT(ProtectVirtualMemory);
+ INIT_GLOBAL_NT(QueryInformationProcess);
+ INIT_GLOBAL_NT(QueryObject);
+ INIT_GLOBAL_NT(QuerySection);
+ INIT_GLOBAL_NT(QueryVirtualMemory);
+ INIT_GLOBAL_NT(UnmapViewOfSection);
+ INIT_GLOBAL_NT(SignalAndWaitForSingleObject);
+ INIT_GLOBAL_NT(WaitForSingleObject);
+
+ INIT_GLOBAL_RTL(RtlAllocateHeap);
+ INIT_GLOBAL_RTL(RtlAnsiStringToUnicodeString);
+ INIT_GLOBAL_RTL(RtlCompareUnicodeString);
+ INIT_GLOBAL_RTL(RtlCreateHeap);
+ INIT_GLOBAL_RTL(RtlCreateUserThread);
+ INIT_GLOBAL_RTL(RtlDestroyHeap);
+ INIT_GLOBAL_RTL(RtlFreeHeap);
+ INIT_GLOBAL_RTL(_strnicmp);
+ INIT_GLOBAL_RTL(strlen);
+ INIT_GLOBAL_RTL(wcslen);
+ INIT_GLOBAL_RTL(memcpy);
+
+ return true;
+}
+
+bool SetupNtdllImports(TargetProcess* child) {
+ if (!InitGlobalNt()) {
+ return false;
+ }
+
+#ifndef NDEBUG
+ // Verify that the structure is fully initialized.
+ for (size_t i = 0; i < sizeof(g_nt) / sizeof(void*); i++)
+ DCHECK(reinterpret_cast<char**>(&g_nt)[i]);
+#endif
+ return (SBOX_ALL_OK == child->TransferVariable("g_nt", &g_nt, sizeof(g_nt)));
+}
+
+#undef INIT_GLOBAL_NT
+#undef INIT_GLOBAL_RTL
+
+bool SetupBasicInterceptions(InterceptionManager* manager,
+ bool is_csrss_connected) {
+ // Interceptions provided by process_thread_policy, without actual policy.
+ if (!INTERCEPT_NT(manager, NtOpenThread, OPEN_THREAD_ID, 20) ||
+ !INTERCEPT_NT(manager, NtOpenProcess, OPEN_PROCESS_ID, 20) ||
+ !INTERCEPT_NT(manager, NtOpenProcessToken, OPEN_PROCESS_TOKEN_ID, 16))
+ return false;
+
+ // Interceptions with neither policy nor IPC.
+ if (!INTERCEPT_NT(manager, NtSetInformationThread, SET_INFORMATION_THREAD_ID,
+ 20) ||
+ !INTERCEPT_NT(manager, NtImpersonateAnonymousToken,
+ IMPERSONATE_ANONYMOUS_TOKEN_ID, 8) ||
+ !INTERCEPT_NT(manager, NtOpenThreadToken, OPEN_THREAD_TOKEN_ID, 20))
+ return false;
+
+ // This one is also provided by process_thread_policy.
+ if (!INTERCEPT_NT(manager, NtOpenProcessTokenEx, OPEN_PROCESS_TOKEN_EX_ID,
+ 20))
+ return false;
+
+ if (!INTERCEPT_NT(manager, NtOpenThreadTokenEx, OPEN_THREAD_TOKEN_EX_ID, 24))
+ return false;
+
+ if (!is_csrss_connected) {
+ if (!INTERCEPT_EAT(manager, kKerneldllName, CreateThread, CREATE_THREAD_ID,
+ 28))
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_broker.h b/security/sandbox/chromium/sandbox/win/src/policy_broker.h
new file mode 100644
index 0000000000..95b123bd0d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_broker.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_BROKER_H_
+#define SANDBOX_SRC_POLICY_BROKER_H_
+
+#include "sandbox/win/src/interception.h"
+
+namespace sandbox {
+
+class TargetProcess;
+
+// Initializes global imported symbols from ntdll.
+bool InitGlobalNt();
+
+// Sets up interceptions not controlled by explicit policies.
+bool SetupBasicInterceptions(InterceptionManager* manager,
+ bool is_csrss_connected);
+
+// Sets up imports from NTDLL for the given target process so the interceptions
+// can work.
+bool SetupNtdllImports(TargetProcess* child);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_POLICY_BROKER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.cc b/security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.cc
new file mode 100644
index 0000000000..02c636f4aa
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.cc
@@ -0,0 +1,450 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/policy_engine_opcodes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace {
+const unsigned short kMaxUniStrSize = 0xfffc / sizeof(wchar_t);
+
+bool InitStringUnicode(const wchar_t* source,
+ size_t length,
+ UNICODE_STRING* ustring) {
+ if (length > kMaxUniStrSize) {
+ return false;
+ }
+ ustring->Buffer = const_cast<wchar_t*>(source);
+ ustring->Length = static_cast<USHORT>(length) * sizeof(wchar_t);
+ ustring->MaximumLength = source ? ustring->Length + sizeof(wchar_t) : 0;
+ return true;
+}
+
+} // namespace
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// Note: The opcodes are implemented as functions (as opposed to classes derived
+// from PolicyOpcode) because you should not add more member variables to the
+// PolicyOpcode class since it would cause object slicing on the target. So to
+// enforce that (instead of just trusting the developer) the opcodes became
+// just functions.
+//
+// In the code that follows I have keep the evaluation function and the factory
+// function together to stress the close relationship between both. For example,
+// only the factory method and the evaluation function know the stored argument
+// order and meaning.
+
+template <int>
+EvalResult OpcodeEval(PolicyOpcode* opcode,
+ const ParameterSet* pp,
+ MatchContext* match);
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpAlwaysFalse:
+// Does not require input parameter.
+
+PolicyOpcode* OpcodeFactory::MakeOpAlwaysFalse(uint32_t options) {
+ return MakeBase(OP_ALWAYS_FALSE, options, -1);
+}
+
+template <>
+EvalResult OpcodeEval<OP_ALWAYS_FALSE>(PolicyOpcode* opcode,
+ const ParameterSet* param,
+ MatchContext* context) {
+ return EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpAlwaysTrue:
+// Does not require input parameter.
+
+PolicyOpcode* OpcodeFactory::MakeOpAlwaysTrue(uint32_t options) {
+ return MakeBase(OP_ALWAYS_TRUE, options, -1);
+}
+
+template <>
+EvalResult OpcodeEval<OP_ALWAYS_TRUE>(PolicyOpcode* opcode,
+ const ParameterSet* param,
+ MatchContext* context) {
+ return EVAL_TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpAction:
+// Does not require input parameter.
+// Argument 0 contains the actual action to return.
+
+PolicyOpcode* OpcodeFactory::MakeOpAction(EvalResult action, uint32_t options) {
+ PolicyOpcode* opcode = MakeBase(OP_ACTION, options, -1);
+ if (!opcode)
+ return nullptr;
+ opcode->SetArgument(0, action);
+ return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_ACTION>(PolicyOpcode* opcode,
+ const ParameterSet* param,
+ MatchContext* context) {
+ int action = 0;
+ opcode->GetArgument(0, &action);
+ return static_cast<EvalResult>(action);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpNumberMatch:
+// Requires a uint32_t or void* in selected_param
+// Argument 0 is the stored number to match.
+// Argument 1 is the C++ type of the 0th argument.
+
+PolicyOpcode* OpcodeFactory::MakeOpNumberMatch(int16_t selected_param,
+ uint32_t match,
+ uint32_t options) {
+ PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
+ if (!opcode)
+ return nullptr;
+ opcode->SetArgument(0, match);
+ opcode->SetArgument(1, UINT32_TYPE);
+ return opcode;
+}
+
+PolicyOpcode* OpcodeFactory::MakeOpVoidPtrMatch(int16_t selected_param,
+ const void* match,
+ uint32_t options) {
+ PolicyOpcode* opcode = MakeBase(OP_NUMBER_MATCH, options, selected_param);
+ if (!opcode)
+ return nullptr;
+ opcode->SetArgument(0, match);
+ opcode->SetArgument(1, VOIDPTR_TYPE);
+ return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_NUMBER_MATCH>(PolicyOpcode* opcode,
+ const ParameterSet* param,
+ MatchContext* context) {
+ uint32_t value_uint32 = 0;
+ if (param->Get(&value_uint32)) {
+ uint32_t match_uint32 = 0;
+ opcode->GetArgument(0, &match_uint32);
+ return (match_uint32 != value_uint32) ? EVAL_FALSE : EVAL_TRUE;
+ } else {
+ const void* value_ptr = nullptr;
+ if (param->Get(&value_ptr)) {
+ const void* match_ptr = nullptr;
+ opcode->GetArgument(0, &match_ptr);
+ return (match_ptr != value_ptr) ? EVAL_FALSE : EVAL_TRUE;
+ }
+ }
+ return EVAL_ERROR;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpNumberMatchRange
+// Requires a uint32_t in selected_param.
+// Argument 0 is the stored lower bound to match.
+// Argument 1 is the stored upper bound to match.
+
+PolicyOpcode* OpcodeFactory::MakeOpNumberMatchRange(int16_t selected_param,
+ uint32_t lower_bound,
+ uint32_t upper_bound,
+ uint32_t options) {
+ if (lower_bound > upper_bound) {
+ return nullptr;
+ }
+ PolicyOpcode* opcode =
+ MakeBase(OP_NUMBER_MATCH_RANGE, options, selected_param);
+ if (!opcode)
+ return nullptr;
+ opcode->SetArgument(0, lower_bound);
+ opcode->SetArgument(1, upper_bound);
+ return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_NUMBER_MATCH_RANGE>(PolicyOpcode* opcode,
+ const ParameterSet* param,
+ MatchContext* context) {
+ uint32_t value = 0;
+ if (!param->Get(&value))
+ return EVAL_ERROR;
+
+ uint32_t lower_bound = 0;
+ uint32_t upper_bound = 0;
+ opcode->GetArgument(0, &lower_bound);
+ opcode->GetArgument(1, &upper_bound);
+ return ((lower_bound <= value) && (upper_bound >= value)) ? EVAL_TRUE
+ : EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpNumberAndMatch:
+// Requires a uint32_t in selected_param.
+// Argument 0 is the stored number to match.
+
+PolicyOpcode* OpcodeFactory::MakeOpNumberAndMatch(int16_t selected_param,
+ uint32_t match,
+ uint32_t options) {
+ PolicyOpcode* opcode = MakeBase(OP_NUMBER_AND_MATCH, options, selected_param);
+ if (!opcode)
+ return nullptr;
+ opcode->SetArgument(0, match);
+ return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_NUMBER_AND_MATCH>(PolicyOpcode* opcode,
+ const ParameterSet* param,
+ MatchContext* context) {
+ uint32_t value = 0;
+ if (!param->Get(&value))
+ return EVAL_ERROR;
+
+ uint32_t number = 0;
+ opcode->GetArgument(0, &number);
+ return (number & value) ? EVAL_TRUE : EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode OpWStringMatch:
+// Requires a wchar_t* in selected_param.
+// Argument 0 is the byte displacement of the stored string.
+// Argument 1 is the length in chars of the stored string.
+// Argument 2 is the offset to apply on the input string. It has special values.
+// as noted in the header file.
+// Argument 3 is the string matching options.
+
+PolicyOpcode* OpcodeFactory::MakeOpWStringMatch(int16_t selected_param,
+ const wchar_t* match_str,
+ int start_position,
+ StringMatchOptions match_opts,
+ uint32_t options) {
+ if (!match_str)
+ return nullptr;
+ if ('\0' == match_str[0])
+ return nullptr;
+
+ int length = lstrlenW(match_str);
+
+ PolicyOpcode* opcode = MakeBase(OP_WSTRING_MATCH, options, selected_param);
+ if (!opcode)
+ return nullptr;
+ ptrdiff_t delta_str = AllocRelative(opcode, match_str, wcslen(match_str) + 1);
+ if (0 == delta_str)
+ return nullptr;
+ opcode->SetArgument(0, delta_str);
+ opcode->SetArgument(1, length);
+ opcode->SetArgument(2, start_position);
+ opcode->SetArgument(3, match_opts);
+ return opcode;
+}
+
+template <>
+EvalResult OpcodeEval<OP_WSTRING_MATCH>(PolicyOpcode* opcode,
+ const ParameterSet* param,
+ MatchContext* context) {
+ if (!context) {
+ return EVAL_ERROR;
+ }
+ const wchar_t* source_str = nullptr;
+ if (!param->Get(&source_str))
+ return EVAL_ERROR;
+
+ int start_position = 0;
+ int match_len = 0;
+ unsigned int match_opts = 0;
+ opcode->GetArgument(1, &match_len);
+ opcode->GetArgument(2, &start_position);
+ opcode->GetArgument(3, &match_opts);
+
+ const wchar_t* match_str = opcode->GetRelativeString(0);
+ // Advance the source string to the last successfully evaluated position
+ // according to the match context.
+ source_str = &source_str[context->position];
+ int source_len = static_cast<int>(g_nt.wcslen(source_str));
+
+ if (0 == source_len) {
+ // If we reached the end of the source string there is nothing we can
+ // match against.
+ return EVAL_FALSE;
+ }
+ if (match_len > source_len) {
+ // There can't be a positive match when the target string is bigger than
+ // the source string
+ return EVAL_FALSE;
+ }
+
+ BOOLEAN case_sensitive = (match_opts & CASE_INSENSITIVE) ? TRUE : FALSE;
+
+ // We have three cases, depending on the value of start_pos:
+ // Case 1. We skip N characters and compare once.
+ // Case 2: We skip to the end and compare once.
+ // Case 3: We match the first substring (if we find any).
+ if (start_position >= 0) {
+ if (kSeekToEnd == start_position) {
+ start_position = source_len - match_len;
+ } else if (match_opts & EXACT_LENGTH) {
+ // A sub-case of case 3 is when the EXACT_LENGTH flag is on
+ // the match needs to be not just substring but full match.
+ if ((match_len + start_position) != source_len) {
+ return EVAL_FALSE;
+ }
+ }
+
+ // Advance start_pos characters. Warning! this does not consider
+ // utf16 encodings (surrogate pairs) or other Unicode 'features'.
+ source_str += start_position;
+
+ // Since we skipped, lets reevaluate just the lengths again.
+ if ((match_len + start_position) > source_len) {
+ return EVAL_FALSE;
+ }
+
+ UNICODE_STRING match_ustr;
+ UNICODE_STRING source_ustr;
+ if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
+ !InitStringUnicode(source_str, match_len, &source_ustr))
+ return EVAL_ERROR;
+
+ if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
+ case_sensitive)) {
+ // Match! update the match context.
+ context->position += start_position + match_len;
+ return EVAL_TRUE;
+ } else {
+ return EVAL_FALSE;
+ }
+ } else if (start_position < 0) {
+ UNICODE_STRING match_ustr;
+ UNICODE_STRING source_ustr;
+ if (!InitStringUnicode(match_str, match_len, &match_ustr) ||
+ !InitStringUnicode(source_str, match_len, &source_ustr))
+ return EVAL_ERROR;
+
+ do {
+ if (0 == g_nt.RtlCompareUnicodeString(&match_ustr, &source_ustr,
+ case_sensitive)) {
+ // Match! update the match context.
+ context->position += (source_ustr.Buffer - source_str) + match_len;
+ return EVAL_TRUE;
+ }
+ ++source_ustr.Buffer;
+ --source_len;
+ } while (source_len >= match_len);
+ }
+ return EVAL_FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// OpcodeMaker (other member functions).
+
+PolicyOpcode* OpcodeFactory::MakeBase(OpcodeID opcode_id,
+ uint32_t options,
+ int16_t selected_param) {
+ if (memory_size() < sizeof(PolicyOpcode))
+ return nullptr;
+
+ // Create opcode using placement-new on the buffer memory.
+ PolicyOpcode* opcode = new (memory_top_) PolicyOpcode();
+
+ // Fill in the standard fields, that every opcode has.
+ memory_top_ += sizeof(PolicyOpcode);
+ opcode->opcode_id_ = opcode_id;
+ opcode->SetOptions(options);
+ opcode->parameter_ = selected_param;
+ return opcode;
+}
+
+ptrdiff_t OpcodeFactory::AllocRelative(void* start,
+ const wchar_t* str,
+ size_t length) {
+ size_t bytes = length * sizeof(wchar_t);
+ if (memory_size() < bytes)
+ return 0;
+ memory_bottom_ -= bytes;
+ if (reinterpret_cast<UINT_PTR>(memory_bottom_) & 1) {
+ // TODO(cpu) replace this for something better.
+ ::DebugBreak();
+ }
+ memcpy(memory_bottom_, str, bytes);
+ ptrdiff_t delta = memory_bottom_ - reinterpret_cast<char*>(start);
+ return delta;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Opcode evaluation dispatchers.
+
+// This function is the one and only entry for evaluating any opcode. It is
+// in charge of applying any relevant opcode options and calling EvaluateInner
+// were the actual dispatch-by-id is made. It would seem at first glance that
+// the dispatch should be done by virtual function (vtable) calls but you have
+// to remember that the opcodes are made in the broker process and copied as
+// raw memory to the target process.
+
+EvalResult PolicyOpcode::Evaluate(const ParameterSet* call_params,
+ size_t param_count,
+ MatchContext* match) {
+ if (!call_params)
+ return EVAL_ERROR;
+ const ParameterSet* selected_param = nullptr;
+ if (parameter_ >= 0) {
+ if (static_cast<size_t>(parameter_) >= param_count) {
+ return EVAL_ERROR;
+ }
+ selected_param = &call_params[parameter_];
+ }
+ EvalResult result = EvaluateHelper(selected_param, match);
+
+ // Apply the general options regardless of the particular type of opcode.
+ if (kPolNone == options_) {
+ return result;
+ }
+
+ if (options_ & kPolNegateEval) {
+ if (EVAL_TRUE == result) {
+ result = EVAL_FALSE;
+ } else if (EVAL_FALSE == result) {
+ result = EVAL_TRUE;
+ } else if (EVAL_ERROR != result) {
+ result = EVAL_ERROR;
+ }
+ }
+ if (match) {
+ if (options_ & kPolClearContext)
+ match->Clear();
+ if (options_ & kPolUseOREval)
+ match->options = kPolUseOREval;
+ }
+ return result;
+}
+
+#define OPCODE_EVAL(op, x, y, z) \
+ case op: \
+ return OpcodeEval<op>(x, y, z)
+
+EvalResult PolicyOpcode::EvaluateHelper(const ParameterSet* parameters,
+ MatchContext* match) {
+ switch (opcode_id_) {
+ OPCODE_EVAL(OP_ALWAYS_FALSE, this, parameters, match);
+ OPCODE_EVAL(OP_ALWAYS_TRUE, this, parameters, match);
+ OPCODE_EVAL(OP_NUMBER_MATCH, this, parameters, match);
+ OPCODE_EVAL(OP_NUMBER_MATCH_RANGE, this, parameters, match);
+ OPCODE_EVAL(OP_NUMBER_AND_MATCH, this, parameters, match);
+ OPCODE_EVAL(OP_WSTRING_MATCH, this, parameters, match);
+ OPCODE_EVAL(OP_ACTION, this, parameters, match);
+ default:
+ return EVAL_ERROR;
+ }
+}
+
+#undef OPCODE_EVAL
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.h b/security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.h
new file mode 100644
index 0000000000..8e8816df1c
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_engine_opcodes.h
@@ -0,0 +1,379 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
+#define SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "sandbox/win/src/policy_engine_params.h"
+
+// The low-level policy is implemented using the concept of policy 'opcodes'.
+// An opcode is a structure that contains enough information to perform one
+// comparison against one single input parameter. For example, an opcode can
+// encode just one of the following comparison:
+//
+// - Is input parameter 3 not equal to nullptr?
+// - Does input parameter 2 start with L"c:\\"?
+// - Is input parameter 5, bit 3 is equal 1?
+//
+// Each opcode is in fact equivalent to a function invocation where all
+// the parameters are known by the opcode except one. So say you have a
+// function of this form:
+// bool fn(a, b, c, d) with 4 arguments
+//
+// Then an opcode is:
+// op(fn, b, c, d)
+// Which stores the function to call and its 3 last arguments
+//
+// Then and opcode evaluation is:
+// op.eval(a) ------------------------> fn(a,b,c,d)
+// internally calls
+//
+// The idea is that complex policy rules can be split into streams of
+// opcodes which are evaluated in sequence. The evaluation is done in
+// groups of opcodes that have N comparison opcodes plus 1 action opcode:
+//
+// [comparison 1][comparison 2]...[comparison N][action][comparison 1]...
+// ----- evaluation order----------->
+//
+// Each opcode group encodes one high-level policy rule. The rule applies
+// only if all the conditions on the group evaluate to true. The action
+// opcode contains the policy outcome for that particular rule.
+//
+// Note that this header contains the main building blocks of low-level policy
+// but not the low level policy class.
+namespace sandbox {
+
+// These are the possible policy outcomes. Note that some of them might
+// not apply and can be removed. Also note that The following values only
+// specify what to do, not how to do it and it is acceptable given specific
+// cases to ignore the policy outcome.
+enum EvalResult {
+ // Comparison opcode values:
+ EVAL_TRUE, // Opcode condition evaluated true.
+ EVAL_FALSE, // Opcode condition evaluated false.
+ EVAL_ERROR, // Opcode condition generated an error while evaluating.
+ // Action opcode values:
+ ASK_BROKER, // The target must generate an IPC to the broker. On the broker
+ // side, this means grant access to the resource.
+ DENY_ACCESS, // No access granted to the resource.
+ GIVE_READONLY, // Give readonly access to the resource.
+ GIVE_ALLACCESS, // Give full access to the resource.
+ GIVE_CACHED, // IPC is not required. Target can return a cached handle.
+ GIVE_FIRST, // TODO(cpu)
+ SIGNAL_ALARM, // Unusual activity. Generate an alarm.
+ FAKE_SUCCESS, // Do not call original function. Just return 'success'.
+ FAKE_ACCESS_DENIED, // Do not call original function. Just return 'denied'
+ // and do not do IPC.
+ TERMINATE_PROCESS, // Destroy target process. Do IPC as well.
+};
+
+// The following are the implemented opcodes.
+enum OpcodeID {
+ OP_ALWAYS_FALSE, // Evaluates to false (EVAL_FALSE).
+ OP_ALWAYS_TRUE, // Evaluates to true (EVAL_TRUE).
+ OP_NUMBER_MATCH, // Match a 32-bit integer as n == a.
+ OP_NUMBER_MATCH_RANGE, // Match a 32-bit integer as a <= n <= b.
+ OP_NUMBER_AND_MATCH, // Match using bitwise AND; as in: n & a != 0.
+ OP_WSTRING_MATCH, // Match a string for equality.
+ OP_ACTION // Evaluates to an action opcode.
+};
+
+// Options that apply to every opcode. They are specified when creating
+// each opcode using OpcodeFactory::MakeOpXXXXX() family of functions
+// Do nothing special.
+const uint32_t kPolNone = 0;
+
+// Convert EVAL_TRUE into EVAL_FALSE and vice-versa. This allows to express
+// negated conditions such as if ( a && !b).
+const uint32_t kPolNegateEval = 1;
+
+// Zero the MatchContext context structure. This happens after the opcode
+// is evaluated.
+const uint32_t kPolClearContext = 2;
+
+// Use OR when evaluating this set of opcodes. The policy evaluator by default
+// uses AND when evaluating. Very helpful when
+// used with kPolNegateEval. For example if you have a condition best expressed
+// as if(! (a && b && c)), the use of this flags allows it to be expressed as
+// if ((!a) || (!b) || (!c)).
+const uint32_t kPolUseOREval = 4;
+
+// Keeps the evaluation state between opcode evaluations. This is used
+// for string matching where the next opcode needs to continue matching
+// from the last character position from the current opcode. The match
+// context is preserved across opcode evaluation unless an opcode specifies
+// as an option kPolClearContext.
+struct MatchContext {
+ size_t position;
+ uint32_t options;
+
+ MatchContext() { Clear(); }
+
+ void Clear() {
+ position = 0;
+ options = 0;
+ }
+};
+
+// Models a policy opcode; that is a condition evaluation were all the
+// arguments but one are stored in objects of this class. Use OpcodeFactory
+// to create objects of this type.
+// This class is just an implementation artifact and not exposed to the
+// API clients or visible in the intercepted service. Internally, an
+// opcode is just:
+// - An integer that identifies the actual opcode.
+// - An index to indicate which one is the input argument
+// - An array of arguments.
+// While an OO hierarchy of objects would have been a natural choice, the fact
+// that 1) this code can execute before the CRT is loaded, presents serious
+// problems in terms of guarantees about the actual state of the vtables and
+// 2) because the opcode objects are generated in the broker process, we need to
+// use plain objects. To preserve some minimal type safety templates are used
+// when possible.
+class PolicyOpcode {
+ friend class OpcodeFactory;
+
+ public:
+ // Evaluates the opcode. For a typical comparison opcode the return value
+ // is EVAL_TRUE or EVAL_FALSE. If there was an error in the evaluation the
+ // the return is EVAL_ERROR. If the opcode is an action opcode then the
+ // return can take other values such as ASK_BROKER.
+ // parameters: An array of all input parameters. This argument is normally
+ // created by the macros POLPARAMS_BEGIN() POLPARAMS_END.
+ // count: The number of parameters passed as first argument.
+ // match: The match context that is persisted across the opcode evaluation
+ // sequence.
+ EvalResult Evaluate(const ParameterSet* parameters,
+ size_t count,
+ MatchContext* match);
+
+ // Retrieves a stored argument by index. Valid index values are
+ // from 0 to < kArgumentCount.
+ template <typename T>
+ void GetArgument(size_t index, T* argument) const {
+ static_assert(sizeof(T) <= sizeof(arguments_[0]), "invalid size");
+ *argument = *reinterpret_cast<const T*>(&arguments_[index].mem);
+ }
+
+ // Sets a stored argument by index. Valid index values are
+ // from 0 to < kArgumentCount.
+ template <typename T>
+ void SetArgument(size_t index, const T& argument) {
+ static_assert(sizeof(T) <= sizeof(arguments_[0]), "invalid size");
+ *reinterpret_cast<T*>(&arguments_[index].mem) = argument;
+ }
+
+ // Retrieves the actual address of a string argument. When using
+ // GetArgument() to retrieve an index that contains a string, the returned
+ // value is just an offset to the actual string.
+ // index: the stored string index. Valid values are from 0
+ // to < kArgumentCount.
+ const wchar_t* GetRelativeString(size_t index) const {
+ ptrdiff_t str_delta = 0;
+ GetArgument(index, &str_delta);
+ const char* delta = reinterpret_cast<const char*>(this) + str_delta;
+ return reinterpret_cast<const wchar_t*>(delta);
+ }
+
+ // Returns true if this opcode is an action opcode without actually
+ // evaluating it. Used to do a quick scan forward to the next opcode group.
+ bool IsAction() const { return (OP_ACTION == opcode_id_); }
+
+ // Returns the opcode type.
+ OpcodeID GetID() const { return opcode_id_; }
+
+ // Returns the stored options such as kPolNegateEval and others.
+ uint32_t GetOptions() const { return options_; }
+
+ // Sets the stored options such as kPolNegateEval.
+ void SetOptions(uint32_t options) { options_ = options; }
+
+ // Returns the parameter of the function the opcode concerns.
+ uint16_t GetParameter() const { return parameter_; }
+
+ private:
+ static const size_t kArgumentCount = 4; // The number of supported argument.
+
+ struct OpcodeArgument {
+ UINT_PTR mem;
+ };
+
+ // Better define placement new in the class instead of relying on the
+ // global definition which seems to be fubared.
+ void* operator new(size_t, void* location) { return location; }
+
+ // Helper function to evaluate the opcode. The parameters have the same
+ // meaning that in Evaluate().
+ EvalResult EvaluateHelper(const ParameterSet* parameters,
+ MatchContext* match);
+ OpcodeID opcode_id_;
+ int16_t parameter_;
+ uint32_t options_;
+ OpcodeArgument arguments_[PolicyOpcode::kArgumentCount];
+};
+
+enum StringMatchOptions {
+ CASE_SENSITIVE = 0, // Pay or Not attention to the case as defined by
+ CASE_INSENSITIVE = 1, // RtlCompareUnicodeString windows API.
+ EXACT_LENGTH = 2 // Don't do substring match. Do full string match.
+};
+
+// Opcodes that do string comparisons take a parameter that is the starting
+// position to perform the comparison so we can do substring matching. There
+// are two special values:
+//
+// Start from the current position and compare strings advancing forward until
+// a match is found if any. Similar to CRT strstr().
+const int kSeekForward = -1;
+// Perform a match with the end of the string. It only does a single comparison.
+const int kSeekToEnd = 0xfffff;
+
+// A PolicyBuffer is a variable size structure that contains all the opcodes
+// that are to be created or evaluated in sequence.
+struct PolicyBuffer {
+ size_t opcode_count;
+ PolicyOpcode opcodes[1];
+};
+
+// Helper class to create any opcode sequence. This class is normally invoked
+// only by the high level policy module or when you need to handcraft a special
+// policy.
+// The factory works by creating the opcodes using a chunk of memory given
+// in the constructor. The opcodes themselves are allocated from the beginning
+// (top) of the memory, while any string that an opcode needs is allocated from
+// the end (bottom) of the memory.
+//
+// In essence:
+//
+// low address ---> [opcode 1]
+// [opcode 2]
+// [opcode 3]
+// | | <--- memory_top_
+// | free |
+// | |
+// | | <--- memory_bottom_
+// [string 1]
+// high address --> [string 2]
+//
+// Note that this class does not keep track of the number of opcodes made and
+// it is designed to be a building block for low-level policy.
+//
+// Note that any of the MakeOpXXXXX member functions below can return nullptr on
+// failure. When that happens opcode sequence creation must be aborted.
+class OpcodeFactory {
+ public:
+ // memory: base pointer to a chunk of memory where the opcodes are created.
+ // memory_size: the size in bytes of the memory chunk.
+ OpcodeFactory(char* memory, size_t memory_size) : memory_top_(memory) {
+ memory_bottom_ = &memory_top_[memory_size];
+ }
+
+ // policy: contains the raw memory where the opcodes are created.
+ // memory_size: contains the actual size of the policy argument.
+ OpcodeFactory(PolicyBuffer* policy, size_t memory_size) {
+ memory_top_ = reinterpret_cast<char*>(&policy->opcodes[0]);
+ memory_bottom_ = &memory_top_[memory_size];
+ }
+
+ // Returns the available memory to make opcodes.
+ size_t memory_size() const {
+ DCHECK_GE(memory_bottom_, memory_top_);
+ return memory_bottom_ - memory_top_;
+ }
+
+ // Creates an OpAlwaysFalse opcode.
+ PolicyOpcode* MakeOpAlwaysFalse(uint32_t options);
+
+ // Creates an OpAlwaysFalse opcode.
+ PolicyOpcode* MakeOpAlwaysTrue(uint32_t options);
+
+ // Creates an OpAction opcode.
+ // action: The action to return when Evaluate() is called.
+ PolicyOpcode* MakeOpAction(EvalResult action, uint32_t options);
+
+ // Creates an OpNumberMatch opcode.
+ // selected_param: index of the input argument. It must be a uint32_t or the
+ // evaluation result will generate a EVAL_ERROR.
+ // match: the number to compare against the selected_param.
+ PolicyOpcode* MakeOpNumberMatch(int16_t selected_param,
+ uint32_t match,
+ uint32_t options);
+
+ // Creates an OpNumberMatch opcode (void pointers are cast to numbers).
+ // selected_param: index of the input argument. It must be an void* or the
+ // evaluation result will generate a EVAL_ERROR.
+ // match: the pointer numeric value to compare against selected_param.
+ PolicyOpcode* MakeOpVoidPtrMatch(int16_t selected_param,
+ const void* match,
+ uint32_t options);
+
+ // Creates an OpNumberMatchRange opcode using the memory passed in the ctor.
+ // selected_param: index of the input argument. It must be a uint32_t or the
+ // evaluation result will generate a EVAL_ERROR.
+ // lower_bound, upper_bound: the range to compare against selected_param.
+ PolicyOpcode* MakeOpNumberMatchRange(int16_t selected_param,
+ uint32_t lower_bound,
+ uint32_t upper_bound,
+ uint32_t options);
+
+ // Creates an OpWStringMatch opcode using the raw memory passed in the ctor.
+ // selected_param: index of the input argument. It must be a wide string
+ // pointer or the evaluation result will generate a EVAL_ERROR.
+ // match_str: string to compare against selected_param.
+ // start_position: when its value is from 0 to < 0x7fff it indicates an
+ // offset from the selected_param string where to perform the comparison. If
+ // the value is SeekForward then a substring search is performed. If the
+ // value is SeekToEnd the comparison is performed against the last part of
+ // the selected_param string.
+ // Note that the range in the position (0 to 0x7fff) is dictated by the
+ // current implementation.
+ // match_opts: Indicates additional matching flags. Currently CaseInsensitive
+ // is supported.
+ PolicyOpcode* MakeOpWStringMatch(int16_t selected_param,
+ const wchar_t* match_str,
+ int start_position,
+ StringMatchOptions match_opts,
+ uint32_t options);
+
+ // Creates an OpNumberAndMatch opcode using the raw memory passed in the ctor.
+ // selected_param: index of the input argument. It must be uint32_t or the
+ // evaluation result will generate a EVAL_ERROR.
+ // match: the value to bitwise AND against selected_param.
+ PolicyOpcode* MakeOpNumberAndMatch(int16_t selected_param,
+ uint32_t match,
+ uint32_t options);
+
+ private:
+ // Constructs the common part of every opcode. selected_param is the index
+ // of the input param to use when evaluating the opcode. Pass -1 in
+ // selected_param to indicate that no input parameter is required.
+ PolicyOpcode* MakeBase(OpcodeID opcode_id,
+ uint32_t options,
+ int16_t selected_param);
+
+ // Allocates (and copies) a string (of size length) inside the buffer and
+ // returns the displacement with respect to start.
+ ptrdiff_t AllocRelative(void* start, const wchar_t* str, size_t length);
+
+ // Points to the lowest currently available address of the memory
+ // used to make the opcodes. This pointer increments as opcodes are made.
+ char* memory_top_;
+
+ // Points to the highest currently available address of the memory
+ // used to make the opcodes. This pointer decrements as opcode strings are
+ // allocated.
+ char* memory_bottom_;
+
+ DISALLOW_COPY_AND_ASSIGN(OpcodeFactory);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_POLICY_ENGINE_OPCODES_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_engine_params.h b/security/sandbox/chromium/sandbox/win/src/policy_engine_params.h
new file mode 100644
index 0000000000..07fd7eac82
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_engine_params.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
+#define SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
+
+#include <stdint.h>
+
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+// This header defines the classes that allow the low level policy to select
+// the input parameters. In order to better make sense of this header is
+// recommended that you check policy_engine_opcodes.h first.
+
+namespace sandbox {
+
+// Models the set of interesting parameters of an intercepted system call
+// normally you don't create objects of this class directly, instead you
+// use the POLPARAMS_XXX macros.
+// For example, if an intercepted function has the following signature:
+//
+// NTSTATUS NtOpenFileFunction (PHANDLE FileHandle,
+// ACCESS_MASK DesiredAccess,
+// POBJECT_ATTRIBUTES ObjectAttributes,
+// PIO_STATUS_BLOCK IoStatusBlock,
+// ULONG ShareAccess,
+// ULONG OpenOptions);
+//
+// You could say that the following parameters are of interest to policy:
+//
+// POLPARAMS_BEGIN(open_params)
+// POLPARAM(DESIRED_ACCESS)
+// POLPARAM(OBJECT_NAME)
+// POLPARAM(SECURITY_DESCRIPTOR)
+// POLPARAM(IO_STATUS)
+// POLPARAM(OPEN_OPTIONS)
+// POLPARAMS_END;
+//
+// and the actual code will use this for defining the parameters:
+//
+// CountedParameterSet<open_params> p;
+// p[open_params::DESIRED_ACCESS] = ParamPickerMake(DesiredAccess);
+// p[open_params::OBJECT_NAME] =
+// ParamPickerMake(ObjectAttributes->ObjectName);
+// p[open_params::SECURITY_DESCRIPTOR] =
+// ParamPickerMake(ObjectAttributes->SecurityDescriptor);
+// p[open_params::IO_STATUS] = ParamPickerMake(IoStatusBlock);
+// p[open_params::OPEN_OPTIONS] = ParamPickerMake(OpenOptions);
+//
+// These will create an stack-allocated array of ParameterSet objects which
+// have each 1) the address of the parameter 2) a numeric id that encodes the
+// original C++ type. This allows the policy to treat any set of supported
+// argument types uniformily and with some type safety.
+//
+// TODO(cpu): support not fully implemented yet for unicode string and will
+// probably add other types as well.
+class ParameterSet {
+ public:
+ ParameterSet() : real_type_(INVALID_TYPE), address_(nullptr) {}
+
+ // Retrieve the stored parameter. If the type does not match ulong fail.
+ bool Get(uint32_t* destination) const {
+ if (real_type_ != UINT32_TYPE) {
+ return false;
+ }
+ *destination = Void2TypePointerCopy<uint32_t>();
+ return true;
+ }
+
+ // Retrieve the stored parameter. If the type does not match void* fail.
+ bool Get(const void** destination) const {
+ if (real_type_ != VOIDPTR_TYPE) {
+ return false;
+ }
+ *destination = Void2TypePointerCopy<void*>();
+ return true;
+ }
+
+ // Retrieve the stored parameter. If the type does not match wchar_t* fail.
+ bool Get(const wchar_t** destination) const {
+ if (real_type_ != WCHAR_TYPE) {
+ return false;
+ }
+ *destination = Void2TypePointerCopy<const wchar_t*>();
+ return true;
+ }
+
+ // False if the parameter is not properly initialized.
+ bool IsValid() const { return real_type_ != INVALID_TYPE; }
+
+ protected:
+ // The constructor can only be called by derived types, which should
+ // safely provide the real_type and the address of the argument.
+ ParameterSet(ArgType real_type, const void* address)
+ : real_type_(real_type), address_(address) {}
+
+ private:
+ // This template provides the same functionality as bits_cast but
+ // it works with pointer while the former works only with references.
+ template <typename T>
+ T Void2TypePointerCopy() const {
+ return *(reinterpret_cast<const T*>(address_));
+ }
+
+ ArgType real_type_;
+ const void* address_;
+};
+
+// To safely infer the type, we use a set of template specializations
+// in ParameterSetEx with a template function ParamPickerMake to do the
+// parameter type deduction.
+
+// Base template class. Not implemented so using unsupported types should
+// fail to compile.
+template <typename T>
+class ParameterSetEx : public ParameterSet {
+ public:
+ ParameterSetEx(const void* address);
+};
+
+template <>
+class ParameterSetEx<void const*> : public ParameterSet {
+ public:
+ ParameterSetEx(const void* address) : ParameterSet(VOIDPTR_TYPE, address) {}
+};
+
+template <>
+class ParameterSetEx<void*> : public ParameterSet {
+ public:
+ ParameterSetEx(const void* address) : ParameterSet(VOIDPTR_TYPE, address) {}
+};
+
+template <>
+class ParameterSetEx<wchar_t*> : public ParameterSet {
+ public:
+ ParameterSetEx(const void* address) : ParameterSet(WCHAR_TYPE, address) {}
+};
+
+template <>
+class ParameterSetEx<wchar_t const*> : public ParameterSet {
+ public:
+ ParameterSetEx(const void* address) : ParameterSet(WCHAR_TYPE, address) {}
+};
+
+template <>
+class ParameterSetEx<uint32_t> : public ParameterSet {
+ public:
+ ParameterSetEx(const void* address) : ParameterSet(UINT32_TYPE, address) {}
+};
+
+template <>
+class ParameterSetEx<UNICODE_STRING> : public ParameterSet {
+ public:
+ ParameterSetEx(const void* address) : ParameterSet(UNISTR_TYPE, address) {}
+};
+
+template <typename T>
+ParameterSet ParamPickerMake(T& parameter) {
+ return ParameterSetEx<T>(&parameter);
+}
+
+struct CountedParameterSetBase {
+ size_t count;
+ ParameterSet parameters[1];
+};
+
+// This template defines the actual list of policy parameters for a given
+// interception.
+// Warning: This template stores the address to the actual variables, in
+// other words, the values are not copied.
+template <typename T>
+struct CountedParameterSet {
+ CountedParameterSet() : count(T::PolParamLast) {}
+
+ ParameterSet& operator[](typename T::Args n) { return parameters[n]; }
+
+ CountedParameterSetBase* GetBase() {
+ return reinterpret_cast<CountedParameterSetBase*>(this);
+ }
+
+ size_t count;
+ ParameterSet parameters[T::PolParamLast];
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_POLICY_ENGINE_PARAMS_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_engine_processor.cc b/security/sandbox/chromium/sandbox/win/src/policy_engine_processor.cc
new file mode 100644
index 0000000000..07969f31a8
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_engine_processor.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/policy_engine_processor.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace sandbox {
+
+void PolicyProcessor::SetInternalState(size_t index, EvalResult result) {
+ state_.current_index_ = index;
+ state_.current_result_ = result;
+}
+
+EvalResult PolicyProcessor::GetAction() const {
+ return state_.current_result_;
+}
+
+// Decides if an opcode can be skipped (not evaluated) or not. The function
+// takes as inputs the opcode and the current evaluation context and returns
+// true if the opcode should be skipped or not and also can set keep_skipping
+// to false to signal that the current instruction should be skipped but not
+// the next after the current one.
+bool SkipOpcode(const PolicyOpcode& opcode,
+ MatchContext* context,
+ bool* keep_skipping) {
+ if (opcode.IsAction()) {
+ uint32_t options = context->options;
+ context->Clear();
+ *keep_skipping = false;
+ return (kPolUseOREval != options);
+ }
+ *keep_skipping = true;
+ return true;
+}
+
+PolicyResult PolicyProcessor::Evaluate(uint32_t options,
+ ParameterSet* parameters,
+ size_t param_count) {
+ if (!policy_)
+ return NO_POLICY_MATCH;
+ if (0 == policy_->opcode_count)
+ return NO_POLICY_MATCH;
+ if (!(kShortEval & options))
+ return POLICY_ERROR;
+
+ MatchContext context;
+ bool evaluation = false;
+ bool skip_group = false;
+ SetInternalState(0, EVAL_FALSE);
+ size_t count = policy_->opcode_count;
+
+ // Loop over all the opcodes Evaluating in sequence. Since we only support
+ // short circuit evaluation, we stop as soon as we find an 'action' opcode
+ // and the current evaluation is true.
+ //
+ // Skipping opcodes can happen when we are in AND mode (!kPolUseOREval) and
+ // have got EVAL_FALSE or when we are in OR mode (kPolUseOREval) and got
+ // EVAL_TRUE. Skipping will stop at the next action opcode or at the opcode
+ // after the action depending on kPolUseOREval.
+
+ for (size_t ix = 0; ix != count; ++ix) {
+ PolicyOpcode& opcode = policy_->opcodes[ix];
+ // Skipping block.
+ if (skip_group) {
+ if (SkipOpcode(opcode, &context, &skip_group))
+ continue;
+ }
+ // Evaluation block.
+ EvalResult result = opcode.Evaluate(parameters, param_count, &context);
+ switch (result) {
+ case EVAL_FALSE:
+ evaluation = false;
+ if (kPolUseOREval != context.options)
+ skip_group = true;
+ break;
+ case EVAL_ERROR:
+ if (kStopOnErrors & options)
+ return POLICY_ERROR;
+ break;
+ case EVAL_TRUE:
+ evaluation = true;
+ if (kPolUseOREval == context.options)
+ skip_group = true;
+ break;
+ default:
+ // We have evaluated an action.
+ SetInternalState(ix, result);
+ return POLICY_MATCH;
+ }
+ }
+
+ if (evaluation) {
+ // Reaching the end of the policy with a positive evaluation is probably
+ // an error: we did not find a final action opcode?
+ return POLICY_ERROR;
+ }
+ return NO_POLICY_MATCH;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_engine_processor.h b/security/sandbox/chromium/sandbox/win/src/policy_engine_processor.h
new file mode 100644
index 0000000000..b62973b14a
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_engine_processor.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
+#define SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_engine_params.h"
+
+namespace sandbox {
+
+// This header contains the core policy evaluator. In its simplest form
+// it evaluates a stream of opcodes assuming that they are laid out in
+// memory as opcode groups.
+//
+// An opcode group has N comparison opcodes plus 1 action opcode. For
+// example here we have 3 opcode groups (A, B,C):
+//
+// [comparison 1] <-- group A start
+// [comparison 2]
+// [comparison 3]
+// [action A ]
+// [comparison 1] <-- group B start
+// [action B ]
+// [comparison 1] <-- group C start
+// [comparison 2]
+// [action C ]
+//
+// The opcode evaluator proceeds from the top, evaluating each opcode in
+// sequence. An opcode group is evaluated until the first comparison that
+// returns false. At that point the rest of the group is skipped and evaluation
+// resumes with the first comparison of the next group. When all the comparisons
+// in a group have evaluated to true and the action is reached. The group is
+// considered a matching group.
+//
+// In the 'ShortEval' mode evaluation stops when it reaches the end or the first
+// matching group. The action opcode from this group is the resulting policy
+// action.
+//
+// In the 'RankedEval' mode evaluation stops only when it reaches the end of the
+// the opcode stream. In the process all matching groups are saved and at the
+// end the 'best' group is selected (what makes the best is TBD) and the action
+// from this group is the resulting policy action.
+//
+// As explained above, the policy evaluation of a group is a logical AND of
+// the evaluation of each opcode. However an opcode can request kPolUseOREval
+// which makes the evaluation to use logical OR. Given that each opcode can
+// request its evaluation result to be negated with kPolNegateEval you can
+// achieve the negation of the total group evaluation. This means that if you
+// need to express:
+// if (!(c1 && c2 && c3))
+// You can do it by:
+// if ((!c1) || (!c2) || (!c3))
+//
+
+// Possible outcomes of policy evaluation.
+enum PolicyResult { NO_POLICY_MATCH, POLICY_MATCH, POLICY_ERROR };
+
+// Policy evaluation flags
+// TODO(cpu): implement the options kStopOnErrors & kRankedEval.
+//
+// Stop evaluating as soon as an error is encountered.
+const uint32_t kStopOnErrors = 1;
+// Ignore all non fatal opcode evaluation errors.
+const uint32_t kIgnoreErrors = 2;
+// Short-circuit evaluation: Only evaluate until opcode group that
+// evaluated to true has been found.
+const uint32_t kShortEval = 4;
+// Discussed briefly at the policy design meeting. It will evaluate
+// all rules and then return the 'best' rule that evaluated true.
+const uint32_t kRankedEval = 8;
+
+// This class evaluates a policy-opcode stream given the memory where the
+// opcodes are and an input 'parameter set'.
+//
+// This class is designed to be callable from interception points
+// as low as the NtXXXX service level (it is not currently safe, but
+// it is designed to be made safe).
+//
+// Its usage in an interception is:
+//
+// POLPARAMS_BEGIN(eval_params)
+// POLPARAM(param1)
+// POLPARAM(param2)
+// POLPARAM(param3)
+// POLPARAM(param4)
+// POLPARAM(param5)
+// POLPARAMS_END;
+//
+// PolicyProcessor pol_evaluator(policy_memory);
+// PolicyResult pr = pol_evaluator.Evaluate(ShortEval, eval_params,
+// _countof(eval_params));
+// if (NO_POLICY_MATCH == pr) {
+// EvalResult policy_action = pol_evaluator.GetAction();
+// // apply policy here...
+// }
+//
+// Where the POLPARAM() arguments are derived from the intercepted function
+// arguments, and represent all the 'interesting' policy inputs, and
+// policy_memory is a memory buffer containing the opcode stream that is the
+// relevant policy for this intercept.
+class PolicyProcessor {
+ public:
+ // policy_buffer contains opcodes made with OpcodeFactory. They are usually
+ // created in the broker process and evaluated in the target process.
+
+ // This constructor is just a variant of the previous constructor.
+ explicit PolicyProcessor(PolicyBuffer* policy) : policy_(policy) {
+ SetInternalState(0, EVAL_FALSE);
+ }
+
+ // Evaluates a policy-opcode stream. See the comments at the top of this
+ // class for more info. Returns POLICY_MATCH if a rule set was found that
+ // matches an active policy.
+ PolicyResult Evaluate(uint32_t options,
+ ParameterSet* parameters,
+ size_t parameter_count);
+
+ // If the result of Evaluate() was POLICY_MATCH, calling this function returns
+ // the recommended policy action.
+ EvalResult GetAction() const;
+
+ private:
+ struct {
+ size_t current_index_;
+ EvalResult current_result_;
+ } state_;
+
+ // Sets the currently matching action result.
+ void SetInternalState(size_t index, EvalResult result);
+
+ PolicyBuffer* policy_;
+ DISALLOW_COPY_AND_ASSIGN(PolicyProcessor);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_POLICY_ENGINE_PROCESSOR_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_engine_unittest.cc b/security/sandbox/chromium/sandbox/win/src/policy_engine_unittest.cc
new file mode 100644
index 0000000000..b8b2002108
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_engine_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define POLPARAMS_BEGIN(x) sandbox::ParameterSet x[] = {
+#define POLPARAM(p) sandbox::ParamPickerMake(p),
+#define POLPARAMS_END }
+
+namespace sandbox {
+
+bool SetupNtdllImports();
+
+TEST(PolicyEngineTest, Rules1) {
+ SetupNtdllImports();
+
+ // Construct two policy rules that say:
+ //
+ // #1
+ // If the path is c:\\documents and settings\\* AND
+ // If the creation mode is 'open existing' AND
+ // If the security descriptor is null THEN
+ // Ask the broker.
+ //
+ // #2
+ // If the security descriptor is null AND
+ // If the path ends with *.txt AND
+ // If the creation mode is not 'create new' THEN
+ // return Access Denied.
+
+ enum FileCreateArgs {
+ FileNameArg,
+ CreationDispositionArg,
+ FlagsAndAttributesArg,
+ SecurityAttributes
+ };
+
+ const size_t policy_sz = 1024;
+ PolicyBuffer* policy = reinterpret_cast<PolicyBuffer*>(new char[policy_sz]);
+ OpcodeFactory opcode_maker(policy, policy_sz - 0x40);
+
+ // Add rule set #1
+ opcode_maker.MakeOpWStringMatch(FileNameArg, L"c:\\documents and settings\\",
+ 0, CASE_INSENSITIVE, kPolNone);
+ opcode_maker.MakeOpNumberMatch(CreationDispositionArg, OPEN_EXISTING,
+ kPolNone);
+ opcode_maker.MakeOpVoidPtrMatch(SecurityAttributes, nullptr, kPolNone);
+ opcode_maker.MakeOpAction(ASK_BROKER, kPolNone);
+
+ // Add rule set #2
+ opcode_maker.MakeOpWStringMatch(FileNameArg, L".TXT", kSeekToEnd,
+ CASE_INSENSITIVE, kPolNone);
+ opcode_maker.MakeOpNumberMatch(CreationDispositionArg, CREATE_NEW,
+ kPolNegateEval);
+ opcode_maker.MakeOpAction(FAKE_ACCESS_DENIED, kPolNone);
+ policy->opcode_count = 7;
+
+ const wchar_t* filename = L"c:\\Documents and Settings\\Microsoft\\BLAH.txt";
+ uint32_t creation_mode = OPEN_EXISTING;
+ uint32_t flags = FILE_ATTRIBUTE_NORMAL;
+ void* security_descriptor = nullptr;
+
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename)
+ POLPARAM(creation_mode)
+ POLPARAM(flags)
+ POLPARAM(security_descriptor)
+ POLPARAMS_END;
+
+ PolicyResult pr;
+ PolicyProcessor pol_ev(policy);
+
+ // Test should match the first rule set.
+ pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, pr);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ // Test should still match the first rule set.
+ pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, pr);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ // Changing creation_mode such that evaluation should not match any rule.
+ creation_mode = CREATE_NEW;
+ pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, pr);
+
+ // Changing creation_mode such that evaluation should match rule #2.
+ creation_mode = OPEN_ALWAYS;
+ pr = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, pr);
+ EXPECT_EQ(FAKE_ACCESS_DENIED, pol_ev.GetAction());
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_low_level.cc b/security/sandbox/chromium/sandbox/win/src/policy_low_level.cc
new file mode 100644
index 0000000000..d987211c8b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_low_level.cc
@@ -0,0 +1,355 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/policy_low_level.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <string>
+
+namespace {
+
+// A single rule can use at most this amount of memory.
+const size_t kRuleBufferSize = 1024 * 4;
+
+// The possible states of the string matching opcode generator.
+enum {
+ PENDING_NONE,
+ PENDING_ASTERISK, // Have seen an '*' but have not generated an opcode.
+ PENDING_QMARK, // Have seen an '?' but have not generated an opcode.
+};
+
+// The category of the last character seen by the string matching opcode
+// generator.
+const uint32_t kLastCharIsNone = 0;
+const uint32_t kLastCharIsAlpha = 1;
+const uint32_t kLastCharIsWild = 2;
+const uint32_t kLastCharIsAsterisk = kLastCharIsWild + 4;
+const uint32_t kLastCharIsQuestionM = kLastCharIsWild + 8;
+
+} // namespace
+
+namespace sandbox {
+
+LowLevelPolicy::LowLevelPolicy(PolicyGlobal* policy_store)
+ : policy_store_(policy_store) {}
+
+// Adding a rule is nothing more than pushing it into an stl container. Done()
+// is called for the rule in case the code that made the rule in the first
+// place has not done it.
+bool LowLevelPolicy::AddRule(IpcTag service, PolicyRule* rule) {
+ if (!rule->Done()) {
+ return false;
+ }
+
+ PolicyRule* local_rule = new PolicyRule(*rule);
+ RuleNode node = {local_rule, service};
+ rules_.push_back(node);
+ return true;
+}
+
+LowLevelPolicy::~LowLevelPolicy() {
+ // Delete all the rules.
+ typedef std::list<RuleNode> RuleNodes;
+ for (RuleNodes::iterator it = rules_.begin(); it != rules_.end(); ++it) {
+ delete it->rule;
+ }
+}
+
+// Here is where the heavy byte shuffling is done. We take all the rules and
+// 'compile' them into a single memory region. Now, the rules are in random
+// order so the first step is to reorganize them into a stl map that is keyed
+// by the service id and as a value contains a list with all the rules that
+// belong to that service. Then we enter the big for-loop where we carve a
+// memory zone for the opcodes and the data and call RebindCopy on each rule
+// so they all end up nicely packed in the policy_store_.
+bool LowLevelPolicy::Done() {
+ typedef std::list<RuleNode> RuleNodes;
+ typedef std::list<const PolicyRule*> RuleList;
+ typedef std::map<IpcTag, RuleList> Mmap;
+ Mmap mmap;
+
+ for (RuleNodes::iterator it = rules_.begin(); it != rules_.end(); ++it) {
+ mmap[it->service].push_back(it->rule);
+ }
+
+ PolicyBuffer* current_buffer = &policy_store_->data[0];
+ char* buffer_end =
+ reinterpret_cast<char*>(current_buffer) + policy_store_->data_size;
+ size_t avail_size = policy_store_->data_size;
+
+ for (Mmap::iterator it = mmap.begin(); it != mmap.end(); ++it) {
+ IpcTag service = (*it).first;
+ if (static_cast<size_t>(service) >= kMaxServiceCount) {
+ return false;
+ }
+ policy_store_->entry[static_cast<size_t>(service)] = current_buffer;
+
+ RuleList::iterator rules_it = (*it).second.begin();
+ RuleList::iterator rules_it_end = (*it).second.end();
+
+ size_t svc_opcode_count = 0;
+
+ for (; rules_it != rules_it_end; ++rules_it) {
+ const PolicyRule* rule = (*rules_it);
+ size_t op_count = rule->GetOpcodeCount();
+
+ size_t opcodes_size = op_count * sizeof(PolicyOpcode);
+ if (avail_size < opcodes_size) {
+ return false;
+ }
+ size_t data_size = avail_size - opcodes_size;
+ PolicyOpcode* opcodes_start = &current_buffer->opcodes[svc_opcode_count];
+ if (!rule->RebindCopy(opcodes_start, opcodes_size, buffer_end,
+ &data_size)) {
+ return false;
+ }
+ size_t used = avail_size - data_size;
+ buffer_end -= used;
+ avail_size -= used;
+ svc_opcode_count += op_count;
+ }
+
+ current_buffer->opcode_count = svc_opcode_count;
+ size_t policy_buffers_occupied =
+ (svc_opcode_count * sizeof(PolicyOpcode)) / sizeof(current_buffer[0]);
+ current_buffer = &current_buffer[policy_buffers_occupied + 1];
+ }
+
+ return true;
+}
+
+PolicyRule::PolicyRule(EvalResult action) : action_(action), done_(false) {
+ char* memory = new char[sizeof(PolicyBuffer) + kRuleBufferSize];
+ buffer_ = reinterpret_cast<PolicyBuffer*>(memory);
+ buffer_->opcode_count = 0;
+ opcode_factory_ =
+ new OpcodeFactory(buffer_, kRuleBufferSize + sizeof(PolicyOpcode));
+}
+
+PolicyRule::PolicyRule(const PolicyRule& other) {
+ if (this == &other)
+ return;
+ action_ = other.action_;
+ done_ = other.done_;
+ size_t buffer_size = sizeof(PolicyBuffer) + kRuleBufferSize;
+ char* memory = new char[buffer_size];
+ buffer_ = reinterpret_cast<PolicyBuffer*>(memory);
+ memcpy(buffer_, other.buffer_, buffer_size);
+
+ char* opcode_buffer = reinterpret_cast<char*>(&buffer_->opcodes[0]);
+ char* next_opcode = &opcode_buffer[GetOpcodeCount() * sizeof(PolicyOpcode)];
+ opcode_factory_ =
+ new OpcodeFactory(next_opcode, other.opcode_factory_->memory_size());
+}
+
+// This function get called from a simple state machine implemented in
+// AddStringMatch() which passes the current state (in state) and it passes
+// true in last_call if AddStringMatch() has finished processing the input
+// pattern string and this would be the last call to generate any pending
+// opcode. The skip_count is the currently accumulated number of '?' seen so
+// far and once the associated opcode is generated this function sets it back
+// to zero.
+bool PolicyRule::GenStringOpcode(RuleType rule_type,
+ StringMatchOptions match_opts,
+ uint16_t parameter,
+ int state,
+ bool last_call,
+ int* skip_count,
+ std::wstring* fragment) {
+ // The last opcode must:
+ // 1) Always clear the context.
+ // 2) Preserve the negation.
+ // 3) Remove the 'OR' mode flag.
+ uint32_t options = kPolNone;
+ if (last_call) {
+ if (IF_NOT == rule_type) {
+ options = kPolClearContext | kPolNegateEval;
+ } else {
+ options = kPolClearContext;
+ }
+ } else if (IF_NOT == rule_type) {
+ options = kPolUseOREval | kPolNegateEval;
+ }
+
+ PolicyOpcode* op = nullptr;
+
+ // The fragment string contains the accumulated characters to match with, it
+ // never contains wildcards (unless they have been escaped) and while there
+ // is no fragment there is no new string match opcode to generate.
+ if (fragment->empty()) {
+ // There is no new opcode to generate but in the last call we have to fix
+ // the previous opcode because it was really the last but we did not know
+ // it at that time.
+ if (last_call && (buffer_->opcode_count > 0)) {
+ op = &buffer_->opcodes[buffer_->opcode_count - 1];
+ op->SetOptions(options);
+ }
+ return true;
+ }
+
+ if (PENDING_ASTERISK == state) {
+ if (last_call) {
+ op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(),
+ kSeekToEnd, match_opts, options);
+ } else {
+ op = opcode_factory_->MakeOpWStringMatch(
+ parameter, fragment->c_str(), kSeekForward, match_opts, options);
+ }
+
+ } else if (PENDING_QMARK == state) {
+ op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(),
+ *skip_count, match_opts, options);
+ *skip_count = 0;
+ } else {
+ if (last_call) {
+ match_opts = static_cast<StringMatchOptions>(EXACT_LENGTH | match_opts);
+ }
+ op = opcode_factory_->MakeOpWStringMatch(parameter, fragment->c_str(), 0,
+ match_opts, options);
+ }
+ if (!op)
+ return false;
+ ++buffer_->opcode_count;
+ fragment->clear();
+ return true;
+}
+
+bool PolicyRule::AddStringMatch(RuleType rule_type,
+ int16_t parameter,
+ const wchar_t* string,
+ StringMatchOptions match_opts) {
+ if (done_) {
+ // Do not allow to add more rules after generating the action opcode.
+ return false;
+ }
+
+ const wchar_t* current_char = string;
+ uint32_t last_char = kLastCharIsNone;
+ int state = PENDING_NONE;
+ int skip_count = 0; // counts how many '?' we have seen in a row.
+ std::wstring fragment; // accumulates the non-wildcard part.
+
+ while (L'\0' != *current_char) {
+ switch (*current_char) {
+ case L'*':
+ if (kLastCharIsWild & last_char) {
+ // '**' and '&*' is an error.
+ return false;
+ }
+ if (!GenStringOpcode(rule_type, match_opts, parameter, state, false,
+ &skip_count, &fragment)) {
+ return false;
+ }
+ last_char = kLastCharIsAsterisk;
+ state = PENDING_ASTERISK;
+ break;
+ case L'?':
+ if (kLastCharIsAsterisk == last_char) {
+ // '*?' is an error.
+ return false;
+ }
+ if (!GenStringOpcode(rule_type, match_opts, parameter, state, false,
+ &skip_count, &fragment)) {
+ return false;
+ }
+ ++skip_count;
+ last_char = kLastCharIsQuestionM;
+ state = PENDING_QMARK;
+ break;
+ case L'/':
+ // Note: "/?" is an escaped '?'. Eat the slash and fall through.
+ if (L'?' == current_char[1]) {
+ ++current_char;
+ }
+ FALLTHROUGH;
+ default:
+ fragment += *current_char;
+ last_char = kLastCharIsAlpha;
+ }
+ ++current_char;
+ }
+
+ if (!GenStringOpcode(rule_type, match_opts, parameter, state, true,
+ &skip_count, &fragment)) {
+ return false;
+ }
+ return true;
+}
+
+bool PolicyRule::AddNumberMatch(RuleType rule_type,
+ int16_t parameter,
+ uint32_t number,
+ RuleOp comparison_op) {
+ if (done_) {
+ // Do not allow to add more rules after generating the action opcode.
+ return false;
+ }
+ uint32_t opts = (rule_type == IF_NOT) ? kPolNegateEval : kPolNone;
+
+ if (EQUAL == comparison_op) {
+ if (!opcode_factory_->MakeOpNumberMatch(parameter, number, opts))
+ return false;
+ } else if (AND == comparison_op) {
+ if (!opcode_factory_->MakeOpNumberAndMatch(parameter, number, opts))
+ return false;
+ }
+ ++buffer_->opcode_count;
+ return true;
+}
+
+bool PolicyRule::Done() {
+ if (done_) {
+ return true;
+ }
+ if (!opcode_factory_->MakeOpAction(action_, kPolNone))
+ return false;
+ ++buffer_->opcode_count;
+ done_ = true;
+ return true;
+}
+
+bool PolicyRule::RebindCopy(PolicyOpcode* opcode_start,
+ size_t opcode_size,
+ char* data_start,
+ size_t* data_size) const {
+ size_t count = buffer_->opcode_count;
+ for (size_t ix = 0; ix != count; ++ix) {
+ if (opcode_size < sizeof(PolicyOpcode)) {
+ return false;
+ }
+ PolicyOpcode& opcode = buffer_->opcodes[ix];
+ *opcode_start = opcode;
+ if (OP_WSTRING_MATCH == opcode.GetID()) {
+ // For this opcode argument 0 is a delta to the string and argument 1
+ // is the length (in chars) of the string.
+ const wchar_t* str = opcode.GetRelativeString(0);
+ size_t str_len;
+ opcode.GetArgument(1, &str_len);
+ str_len = str_len * sizeof(wchar_t);
+ if ((*data_size) < str_len) {
+ return false;
+ }
+ *data_size -= str_len;
+ data_start -= str_len;
+ memcpy(data_start, str, str_len);
+ // Recompute the string displacement
+ ptrdiff_t delta = data_start - reinterpret_cast<char*>(opcode_start);
+ opcode_start->SetArgument(0, delta);
+ }
+ ++opcode_start;
+ opcode_size -= sizeof(PolicyOpcode);
+ }
+
+ return true;
+}
+
+PolicyRule::~PolicyRule() {
+ delete[] reinterpret_cast<char*>(buffer_);
+ delete opcode_factory_;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_low_level.h b/security/sandbox/chromium/sandbox/win/src/policy_low_level.h
new file mode 100644
index 0000000000..1586f96af9
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_low_level.h
@@ -0,0 +1,189 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_LOW_LEVEL_H__
+#define SANDBOX_SRC_POLICY_LOW_LEVEL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <list>
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_engine_params.h"
+
+// Low level policy classes.
+// Built on top of the PolicyOpcode and OpcodeFactory, the low level policy
+// provides a way to define rules on strings and numbers but it is unaware
+// of Windows specific details or how the Interceptions must be set up.
+// To use these classes you construct one or more rules and add them to the
+// LowLevelPolicy object like this:
+//
+// PolicyRule rule1(ASK_BROKER);
+// rule1.AddStringMatch(IF, 0, L"\\\\/?/?\\c:\\*Microsoft*\\*.exe", true);
+// rule1.AddNumberMatch(IF_NOT, 1, CREATE_ALWAYS, EQUAL);
+// rule1.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL);
+//
+// PolicyRule rule2(FAKE_SUCCESS);
+// rule2.AddStringMatch(IF, 0, L"\\\\/?/?\\Pipe\\Chrome.*", false));
+// rule2.AddNumberMatch(IF, 1, OPEN_EXISTING, EQUAL));
+//
+// LowLevelPolicy policyGen(*policy_memory);
+// policyGen.AddRule(kNtCreateFileSvc, &rule1);
+// policyGen.AddRule(kNtCreateFileSvc, &rule2);
+// policyGen.Done();
+//
+// At this point (error checking omitted) the policy_memory can be copied
+// to the target process where it can be evaluated.
+
+namespace sandbox {
+
+// Defines the memory layout of the policy. This memory is filled by
+// LowLevelPolicy object.
+// For example:
+//
+// [Service 0] --points to---\
+// [Service 1] --------------|-----\
+// ...... | |
+// [Service N] | |
+// [data_size] | |
+// [Policy Buffer 0] <-------/ |
+// [opcodes of] |
+// ....... |
+// [Policy Buffer 1] <-------------/
+// [opcodes]
+// .......
+// .......
+// [Policy Buffer N]
+// [opcodes]
+// .......
+// <possibly unused space here>
+// .......
+// [opcode string ]
+// [opcode string ]
+// .......
+// [opcode string ]
+struct PolicyGlobal {
+ PolicyBuffer* entry[kMaxServiceCount];
+ size_t data_size;
+ PolicyBuffer data[1];
+};
+
+class PolicyRule;
+
+// Provides the means to collect rules into a policy store (memory)
+class LowLevelPolicy {
+ public:
+ // policy_store: must contain allocated memory and the internal
+ // size fields set to correct values.
+ explicit LowLevelPolicy(PolicyGlobal* policy_store);
+
+ // Destroys all the policy rules.
+ ~LowLevelPolicy();
+
+ // Adds a rule to be generated when Done() is called.
+ // service: The id of the service that this rule is associated with,
+ // for example the 'Open Thread' service or the "Create File" service.
+ // returns false on error.
+ bool AddRule(IpcTag service, PolicyRule* rule);
+
+ // Generates all the rules added with AddRule() into the memory area
+ // passed on the constructor. Returns false on error.
+ bool Done();
+
+ private:
+ struct RuleNode {
+ const PolicyRule* rule;
+ IpcTag service;
+ };
+ std::list<RuleNode> rules_;
+ PolicyGlobal* policy_store_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(LowLevelPolicy);
+};
+
+// There are 'if' rules and 'if not' comparisons
+enum RuleType {
+ IF = 0,
+ IF_NOT = 1,
+};
+
+// Possible comparisons for numbers
+enum RuleOp {
+ EQUAL,
+ AND,
+ RANGE // TODO(cpu): Implement this option.
+};
+
+// Provides the means to collect a set of comparisons into a single
+// rule and its associated action.
+class PolicyRule {
+ friend class LowLevelPolicy;
+
+ public:
+ explicit PolicyRule(EvalResult action);
+ PolicyRule(const PolicyRule& other);
+ ~PolicyRule();
+
+ // Adds a string comparison to the rule.
+ // rule_type: possible values are IF and IF_NOT.
+ // parameter: the expected index of the argument for this rule. For example
+ // in a 'create file' service the file name argument can be at index 0.
+ // string: is the desired matching pattern.
+ // match_opts: if the pattern matching is case sensitive or not.
+ bool AddStringMatch(RuleType rule_type,
+ int16_t parameter,
+ const wchar_t* string,
+ StringMatchOptions match_opts);
+
+ // Adds a number match comparison to the rule.
+ // rule_type: possible values are IF and IF_NOT.
+ // parameter: the expected index of the argument for this rule.
+ // number: the value to compare the input to.
+ // comparison_op: the comparison kind (equal, logical and, etc).
+ bool AddNumberMatch(RuleType rule_type,
+ int16_t parameter,
+ uint32_t number,
+ RuleOp comparison_op);
+
+ // Returns the number of opcodes generated so far.
+ size_t GetOpcodeCount() const { return buffer_->opcode_count; }
+
+ // Called when there is no more comparisons to add. Internally it generates
+ // the last opcode (the action opcode). Returns false if this operation fails.
+ bool Done();
+
+ private:
+ void operator=(const PolicyRule&);
+ // Called in a loop from AddStringMatch to generate the required string
+ // match opcodes. rule_type, match_opts and parameter are the same as
+ // in AddStringMatch.
+ bool GenStringOpcode(RuleType rule_type,
+ StringMatchOptions match_opts,
+ uint16_t parameter,
+ int state,
+ bool last_call,
+ int* skip_count,
+ std::wstring* fragment);
+
+ // Loop over all generated opcodes and copy them to increasing memory
+ // addresses from opcode_start and copy the extra data (strings usually) into
+ // decreasing addresses from data_start. Extra data is only present in the
+ // string evaluation opcodes.
+ bool RebindCopy(PolicyOpcode* opcode_start,
+ size_t opcode_size,
+ char* data_start,
+ size_t* data_size) const;
+ PolicyBuffer* buffer_;
+ OpcodeFactory* opcode_factory_;
+ EvalResult action_;
+ bool done_;
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_POLICY_LOW_LEVEL_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_low_level_unittest.cc b/security/sandbox/chromium/sandbox/win/src/policy_low_level_unittest.cc
new file mode 100644
index 0000000000..8484660096
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_low_level_unittest.cc
@@ -0,0 +1,684 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/policy_low_level.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define POLPARAMS_BEGIN(x) sandbox::ParameterSet x[] = {
+#define POLPARAM(p) sandbox::ParamPickerMake(p),
+#define POLPARAMS_END }
+
+namespace sandbox {
+
+bool SetupNtdllImports();
+
+// Testing that we allow opcode generation on valid string patterns.
+TEST(PolicyEngineTest, StringPatternsOK) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"c:\\adobe\\ver??\\", CASE_SENSITIVE));
+ EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"*.tmp", CASE_SENSITIVE));
+ EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"c:\\*.doc", CASE_SENSITIVE));
+ EXPECT_TRUE(pr.AddStringMatch(IF, 0, L"c:\\windows\\*", CASE_SENSITIVE));
+ EXPECT_TRUE(
+ pr.AddStringMatch(IF, 0, L"d:\\adobe\\acrobat.exe", CASE_SENSITIVE));
+}
+
+// Testing that we signal invalid string patterns.
+TEST(PolicyEngineTest, StringPatternsBAD) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"one**two", CASE_SENSITIVE));
+ EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"**three", CASE_SENSITIVE));
+ EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"five?six*?seven", CASE_SENSITIVE));
+ EXPECT_FALSE(pr.AddStringMatch(IF, 0, L"eight?*nine", CASE_SENSITIVE));
+}
+
+// Helper function to allocate space (on the heap) for policy.
+PolicyGlobal* MakePolicyMemory() {
+ const size_t kTotalPolicySz = 4096 * 8;
+ char* mem = new char[kTotalPolicySz];
+ memset(mem, 0, kTotalPolicySz);
+ PolicyGlobal* policy = reinterpret_cast<PolicyGlobal*>(mem);
+ policy->data_size = kTotalPolicySz - sizeof(PolicyGlobal);
+ return policy;
+}
+
+// The simplest test using LowLevelPolicy it should test a single opcode which
+// does a exact string comparison.
+TEST(PolicyEngineTest, SimpleStrMatch) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(
+ pr.AddStringMatch(IF, 0, L"z:\\Directory\\domo.txt", CASE_INSENSITIVE));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ const IpcTag kFakeService = IpcTag::PING2;
+
+ LowLevelPolicy policyGen(policy);
+ EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* filename = L"Z:\\Directory\\domo.txt";
+
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename) // Argument 0
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev(policy->entry[static_cast<size_t>(kFakeService)]);
+
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"Z:\\Directory\\domo.txt.tmp";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, SimpleIfNotStrMatch) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\", CASE_SENSITIVE));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ const IpcTag kFakeService = IpcTag::PING2;
+ LowLevelPolicy policyGen(policy);
+
+ EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* filename = nullptr;
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename) // Argument 0
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev(policy->entry[static_cast<size_t>(kFakeService)]);
+
+ filename = L"c:\\Microsoft\\";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\MicroNerd\\";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\Microsoft\\domo.txt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, SimpleIfNotStrMatchWild1) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(
+ pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\*", CASE_SENSITIVE));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ const IpcTag kFakeService = IpcTag::NTCREATEFILE;
+ LowLevelPolicy policyGen(policy);
+
+ EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* filename = nullptr;
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename) // Argument 0
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev(policy->entry[static_cast<size_t>(kFakeService)]);
+
+ filename = L"c:\\Microsoft\\domo.txt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\MicroNerd\\domo.txt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, SimpleIfNotStrMatchWild2) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(
+ pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\*.txt", CASE_SENSITIVE));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ const IpcTag kFakeService = IpcTag::NTCREATEFILE;
+ LowLevelPolicy policyGen(policy);
+
+ EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* filename = nullptr;
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename) // Argument 0
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev(policy->entry[static_cast<size_t>(kFakeService)]);
+
+ filename = L"c:\\Microsoft\\domo.txt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\MicroNerd\\domo.txt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\Microsoft\\domo.bmp";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, IfNotStrMatchTwoRulesWild1) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(
+ pr.AddStringMatch(IF_NOT, 0, L"c:\\Microsoft\\*", CASE_SENSITIVE));
+ EXPECT_TRUE(pr.AddNumberMatch(IF, 1, 24, EQUAL));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ const IpcTag kFakeService = IpcTag::NTCREATEFILE;
+ LowLevelPolicy policyGen(policy);
+
+ EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* filename = nullptr;
+ uint32_t access = 0;
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename) // Argument 0
+ POLPARAM(access) // Argument 1
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev(policy->entry[static_cast<size_t>(kFakeService)]);
+
+ filename = L"c:\\Microsoft\\domo.txt";
+ access = 24;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\Microsoft\\domo.txt";
+ access = 42;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\MicroNerd\\domo.txt";
+ access = 24;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\Micronesia\\domo.txt";
+ access = 42;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, IfNotStrMatchTwoRulesWild2) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(pr.AddNumberMatch(IF, 1, 24, EQUAL));
+ EXPECT_TRUE(
+ pr.AddStringMatch(IF_NOT, 0, L"c:\\GoogleV?\\*.txt", CASE_SENSITIVE));
+ EXPECT_TRUE(pr.AddNumberMatch(IF, 2, 66, EQUAL));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ const IpcTag kFakeService = IpcTag::NTCREATEFILE;
+ LowLevelPolicy policyGen(policy);
+
+ EXPECT_TRUE(policyGen.AddRule(kFakeService, &pr));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* filename = nullptr;
+ uint32_t access = 0;
+ uint32_t sharing = 66;
+
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename) // Argument 0
+ POLPARAM(access) // Argument 1
+ POLPARAM(sharing) // Argument 2
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev(policy->entry[static_cast<size_t>(kFakeService)]);
+
+ filename = L"c:\\GoogleV2\\domo.txt";
+ access = 24;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\GoogleV2\\domo.bmp";
+ access = 24;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\GoogleV23\\domo.txt";
+ access = 24;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\GoogleV2\\domo.txt";
+ access = 42;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\Google\\domo.txt";
+ access = 24;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\Micronesia\\domo.txt";
+ access = 42;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\GoogleV2\\domo.bmp";
+ access = 24;
+ sharing = 0;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+// Testing one single rule in one single service. The service is made to
+// resemble NtCreateFile.
+TEST(PolicyEngineTest, OneRuleTest) {
+ SetupNtdllImports();
+ PolicyRule pr(ASK_BROKER);
+ EXPECT_TRUE(
+ pr.AddStringMatch(IF, 0, L"c:\\*Microsoft*\\*.txt", CASE_SENSITIVE));
+ EXPECT_TRUE(pr.AddNumberMatch(IF_NOT, 1, CREATE_ALWAYS, EQUAL));
+ EXPECT_TRUE(pr.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+
+ const IpcTag kNtFakeCreateFile = IpcTag::NTCREATEFILE;
+
+ LowLevelPolicy policyGen(policy);
+ EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* filename = L"c:\\Documents and Settings\\Microsoft\\BLAH.txt";
+ uint32_t creation_mode = OPEN_EXISTING;
+ uint32_t flags = FILE_ATTRIBUTE_NORMAL;
+ void* security_descriptor = nullptr;
+
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(filename) // Argument 0
+ POLPARAM(creation_mode) // Argument 1
+ POLPARAM(flags) // Argument 2
+ POLPARAM(security_descriptor)
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev(policy->entry[static_cast<size_t>(kNtFakeCreateFile)]);
+
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ creation_mode = CREATE_ALWAYS;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ creation_mode = OPEN_EXISTING;
+ filename = L"c:\\Other\\Path\\Microsoft\\Another file.txt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\Other\\Path\\Microsoft\\Another file.txt.tmp";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ flags = FILE_ATTRIBUTE_DEVICE;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\Other\\Macrosoft\\Another file.txt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\Microsoft\\1.txt";
+ flags = FILE_ATTRIBUTE_NORMAL;
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev.GetAction());
+
+ filename = L"c:\\Microsoft\\1.ttt";
+ result = pol_ev.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+// Testing 3 rules in 3 services. Two of the services resemble File services.
+TEST(PolicyEngineTest, ThreeRulesTest) {
+ SetupNtdllImports();
+ PolicyRule pr_pipe(FAKE_SUCCESS);
+ EXPECT_TRUE(pr_pipe.AddStringMatch(IF, 0, L"\\\\/?/?\\Pipe\\Chrome.*",
+ CASE_INSENSITIVE));
+ EXPECT_TRUE(pr_pipe.AddNumberMatch(IF, 1, OPEN_EXISTING, EQUAL));
+ EXPECT_TRUE(pr_pipe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+ size_t opc1 = pr_pipe.GetOpcodeCount();
+ EXPECT_EQ(3u, opc1);
+
+ PolicyRule pr_dump(ASK_BROKER);
+ EXPECT_TRUE(pr_dump.AddStringMatch(IF, 0, L"\\\\/?/?\\*\\Crash Reports\\*",
+ CASE_INSENSITIVE));
+ EXPECT_TRUE(pr_dump.AddNumberMatch(IF, 1, CREATE_ALWAYS, EQUAL));
+ EXPECT_TRUE(pr_dump.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+ size_t opc2 = pr_dump.GetOpcodeCount();
+ EXPECT_EQ(4u, opc2);
+
+ PolicyRule pr_winexe(SIGNAL_ALARM);
+ EXPECT_TRUE(pr_winexe.AddStringMatch(IF, 0, L"\\\\/?/?\\C:\\Windows\\*.exe",
+ CASE_INSENSITIVE));
+ EXPECT_TRUE(pr_winexe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+ size_t opc3 = pr_winexe.GetOpcodeCount();
+ EXPECT_EQ(3u, opc3);
+
+ PolicyRule pr_adobe(GIVE_CACHED);
+ EXPECT_TRUE(
+ pr_adobe.AddStringMatch(IF, 0, L"c:\\adobe\\ver?.?\\", CASE_SENSITIVE));
+ EXPECT_TRUE(pr_adobe.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_NORMAL, EQUAL));
+
+ size_t opc4 = pr_adobe.GetOpcodeCount();
+ EXPECT_EQ(4u, opc4);
+
+ PolicyRule pr_none(GIVE_FIRST);
+ EXPECT_TRUE(pr_none.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_READONLY, AND));
+ EXPECT_TRUE(pr_none.AddNumberMatch(IF, 2, FILE_ATTRIBUTE_SYSTEM, AND));
+
+ size_t opc5 = pr_none.GetOpcodeCount();
+ EXPECT_EQ(2u, opc5);
+
+ PolicyGlobal* policy = MakePolicyMemory();
+
+ // These do not match the real tag values.
+ const IpcTag kNtFakeNone = static_cast<IpcTag>(4);
+ const IpcTag kNtFakeCreateFile = static_cast<IpcTag>(5);
+ const IpcTag kNtFakeOpenFile = static_cast<IpcTag>(6);
+
+ LowLevelPolicy policyGen(policy);
+ EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr_pipe));
+ EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr_dump));
+ EXPECT_TRUE(policyGen.AddRule(kNtFakeCreateFile, &pr_winexe));
+
+ EXPECT_TRUE(policyGen.AddRule(kNtFakeOpenFile, &pr_adobe));
+ EXPECT_TRUE(policyGen.AddRule(kNtFakeOpenFile, &pr_pipe));
+
+ EXPECT_TRUE(policyGen.AddRule(kNtFakeNone, &pr_none));
+
+ EXPECT_TRUE(policyGen.Done());
+
+ // Inspect the policy structure manually.
+ EXPECT_FALSE(policy->entry[0]);
+ EXPECT_FALSE(policy->entry[1]);
+ EXPECT_FALSE(policy->entry[2]);
+ EXPECT_FALSE(policy->entry[3]);
+ EXPECT_TRUE(policy->entry[4]); // kNtFakeNone.
+ EXPECT_TRUE(policy->entry[5]); // kNtFakeCreateFile.
+ EXPECT_TRUE(policy->entry[6]); // kNtFakeOpenFile.
+ EXPECT_FALSE(policy->entry[7]);
+
+ // The total per service opcode counts now must take in account one
+ // extra opcode (action opcode) per rule.
+ ++opc1;
+ ++opc2;
+ ++opc3;
+ ++opc4;
+ ++opc5;
+
+ size_t tc1 = policy->entry[static_cast<size_t>(kNtFakeNone)]->opcode_count;
+ size_t tc2 =
+ policy->entry[static_cast<size_t>(kNtFakeCreateFile)]->opcode_count;
+ size_t tc3 =
+ policy->entry[static_cast<size_t>(kNtFakeOpenFile)]->opcode_count;
+
+ EXPECT_EQ(opc5, tc1);
+ EXPECT_EQ((opc1 + opc2 + opc3), tc2);
+ EXPECT_EQ((opc1 + opc4), tc3);
+
+ // Check the type of the first and last opcode of each service.
+
+ EXPECT_EQ(
+ OP_NUMBER_AND_MATCH,
+ policy->entry[static_cast<size_t>(kNtFakeNone)]->opcodes[0].GetID());
+ EXPECT_EQ(OP_ACTION, policy->entry[static_cast<size_t>(kNtFakeNone)]
+ ->opcodes[tc1 - 1]
+ .GetID());
+ EXPECT_EQ(OP_WSTRING_MATCH,
+ policy->entry[static_cast<size_t>(kNtFakeCreateFile)]
+ ->opcodes[0]
+ .GetID());
+ EXPECT_EQ(OP_ACTION, policy->entry[static_cast<size_t>(kNtFakeCreateFile)]
+ ->opcodes[tc2 - 1]
+ .GetID());
+ EXPECT_EQ(
+ OP_WSTRING_MATCH,
+ policy->entry[static_cast<size_t>(kNtFakeOpenFile)]->opcodes[0].GetID());
+ EXPECT_EQ(OP_ACTION, policy->entry[static_cast<size_t>(kNtFakeOpenFile)]
+ ->opcodes[tc3 - 1]
+ .GetID());
+
+ // Test the policy evaluation.
+
+ const wchar_t* filename = L"";
+ uint32_t creation_mode = OPEN_EXISTING;
+ uint32_t flags = FILE_ATTRIBUTE_NORMAL;
+ void* security_descriptor = nullptr;
+
+ POLPARAMS_BEGIN(params)
+ POLPARAM(filename) // Argument 0
+ POLPARAM(creation_mode) // Argument 1
+ POLPARAM(flags) // Argument 2
+ POLPARAM(security_descriptor)
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor eval_CreateFile(
+ policy->entry[static_cast<size_t>(kNtFakeCreateFile)]);
+ PolicyProcessor eval_OpenFile(
+ policy->entry[static_cast<size_t>(kNtFakeOpenFile)]);
+ PolicyProcessor eval_None(policy->entry[static_cast<size_t>(kNtFakeNone)]);
+
+ result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_None.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"\\\\??\\c:\\Windows\\System32\\calc.exe";
+ flags = FILE_ATTRIBUTE_SYSTEM;
+ result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_None.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ flags += FILE_ATTRIBUTE_READONLY;
+ result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_None.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(GIVE_FIRST, eval_None.GetAction());
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ flags = FILE_ATTRIBUTE_NORMAL;
+ result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(SIGNAL_ALARM, eval_CreateFile.GetAction());
+ result = eval_None.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"c:\\adobe\\ver3.2\\temp";
+ result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_None.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(GIVE_CACHED, eval_OpenFile.GetAction());
+
+ filename = L"c:\\adobe\\ver3.22\\temp";
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"\\\\??\\c:\\some path\\other path\\crash reports\\some path";
+ creation_mode = CREATE_ALWAYS;
+ result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, eval_CreateFile.GetAction());
+ result = eval_None.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ filename = L"\\\\??\\Pipe\\Chrome.12345";
+ creation_mode = OPEN_EXISTING;
+ result = eval_CreateFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(FAKE_SUCCESS, eval_CreateFile.GetAction());
+ result = eval_None.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+ result = eval_OpenFile.Evaluate(kShortEval, params, _countof(params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(FAKE_SUCCESS, eval_OpenFile.GetAction());
+
+ delete[] reinterpret_cast<char*>(policy);
+}
+
+TEST(PolicyEngineTest, PolicyRuleCopyConstructorTwoStrings) {
+ SetupNtdllImports();
+ // Both pr_orig and pr_copy should allow hello.* but not *.txt files.
+ PolicyRule pr_orig(ASK_BROKER);
+ EXPECT_TRUE(pr_orig.AddStringMatch(IF, 0, L"hello.*", CASE_SENSITIVE));
+
+ PolicyRule pr_copy(pr_orig);
+ EXPECT_TRUE(pr_orig.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+ EXPECT_TRUE(pr_copy.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ LowLevelPolicy policyGen(policy);
+ EXPECT_TRUE(policyGen.AddRule(IpcTag::PING1, &pr_orig));
+ EXPECT_TRUE(policyGen.AddRule(IpcTag::PING2, &pr_copy));
+ EXPECT_TRUE(policyGen.Done());
+
+ const wchar_t* name = nullptr;
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(name)
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev_orig(policy->entry[1]);
+ name = L"domo.txt";
+ result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ name = L"hello.bmp";
+ result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev_orig.GetAction());
+
+ PolicyProcessor pol_ev_copy(policy->entry[2]);
+ name = L"domo.txt";
+ result = pol_ev_copy.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ name = L"hello.bmp";
+ result = pol_ev_copy.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev_copy.GetAction());
+}
+
+TEST(PolicyEngineTest, PolicyGenDoneCalledTwice) {
+ SetupNtdllImports();
+ // The specific rules here are not important.
+ PolicyRule pr_orig(ASK_BROKER);
+ EXPECT_TRUE(pr_orig.AddStringMatch(IF, 0, L"hello.*", CASE_SENSITIVE));
+
+ PolicyRule pr_copy(pr_orig);
+ EXPECT_TRUE(pr_orig.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+ EXPECT_TRUE(pr_copy.AddStringMatch(IF_NOT, 0, L"*.txt", CASE_SENSITIVE));
+
+ PolicyGlobal* policy = MakePolicyMemory();
+ LowLevelPolicy policyGen(policy);
+ const IpcTag tag1 = IpcTag::PING1;
+ const IpcTag tag2 = IpcTag::PING2;
+ EXPECT_TRUE(policyGen.AddRule(tag1, &pr_orig));
+ EXPECT_TRUE(policyGen.AddRule(tag2, &pr_copy));
+ EXPECT_TRUE(policyGen.Done());
+
+ // Obtain opcode counts.
+ size_t tc1 = policy->entry[static_cast<size_t>(IpcTag::PING1)]->opcode_count;
+ size_t tc2 = policy->entry[static_cast<size_t>(IpcTag::PING2)]->opcode_count;
+
+ // Call Done() again.
+ EXPECT_TRUE(policyGen.Done());
+
+ // Expect same opcode counts.
+ EXPECT_EQ(tc1,
+ policy->entry[static_cast<size_t>(IpcTag::PING1)]->opcode_count);
+ EXPECT_EQ(tc2,
+ policy->entry[static_cast<size_t>(IpcTag::PING2)]->opcode_count);
+
+ // Confirm the rules work as before.
+ const wchar_t* name = nullptr;
+ POLPARAMS_BEGIN(eval_params)
+ POLPARAM(name)
+ POLPARAMS_END;
+
+ PolicyResult result;
+ PolicyProcessor pol_ev_orig(policy->entry[1]);
+ name = L"domo.txt";
+ result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(NO_POLICY_MATCH, result);
+
+ name = L"hello.bmp";
+ result = pol_ev_orig.Evaluate(kShortEval, eval_params, _countof(eval_params));
+ EXPECT_EQ(POLICY_MATCH, result);
+ EXPECT_EQ(ASK_BROKER, pol_ev_orig.GetAction());
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_opcodes_unittest.cc b/security/sandbox/chromium/sandbox/win/src/policy_opcodes_unittest.cc
new file mode 100644
index 0000000000..c83efcba18
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_opcodes_unittest.cc
@@ -0,0 +1,364 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/policy_engine_opcodes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define INIT_GLOBAL_RTL(member) \
+ g_nt.member = \
+ reinterpret_cast<member##Function>(::GetProcAddress(ntdll, #member)); \
+ if (!g_nt.member) \
+ return false
+
+namespace sandbox {
+
+const size_t kOpcodeMemory = 1024;
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+bool SetupNtdllImports() {
+ HMODULE ntdll = ::GetModuleHandle(kNtdllName);
+
+ INIT_GLOBAL_RTL(RtlAllocateHeap);
+ INIT_GLOBAL_RTL(RtlAnsiStringToUnicodeString);
+ INIT_GLOBAL_RTL(RtlCompareUnicodeString);
+ INIT_GLOBAL_RTL(RtlCreateHeap);
+ INIT_GLOBAL_RTL(RtlDestroyHeap);
+ INIT_GLOBAL_RTL(RtlFreeHeap);
+ INIT_GLOBAL_RTL(_strnicmp);
+ INIT_GLOBAL_RTL(strlen);
+ INIT_GLOBAL_RTL(wcslen);
+
+ return true;
+}
+
+TEST(PolicyEngineTest, ParameterSetTest) {
+ void* pv1 = reinterpret_cast<void*>(0x477EAA5);
+ const void* pv2 = reinterpret_cast<void*>(0x987654);
+ ParameterSet pset1 = ParamPickerMake(pv1);
+ ParameterSet pset2 = ParamPickerMake(pv2);
+
+ // Test that we can store and retrieve a void pointer:
+ const void* result1 = 0;
+ uint32_t result2 = 0;
+ EXPECT_TRUE(pset1.Get(&result1));
+ EXPECT_TRUE(pv1 == result1);
+ EXPECT_FALSE(pset1.Get(&result2));
+ EXPECT_TRUE(pset2.Get(&result1));
+ EXPECT_TRUE(pv2 == result1);
+ EXPECT_FALSE(pset2.Get(&result2));
+
+ // Test that we can store and retrieve a uint32_t:
+ uint32_t number = 12747;
+ ParameterSet pset3 = ParamPickerMake(number);
+ EXPECT_FALSE(pset3.Get(&result1));
+ EXPECT_TRUE(pset3.Get(&result2));
+ EXPECT_EQ(number, result2);
+
+ // Test that we can store and retrieve a string:
+ const wchar_t* txt = L"S231L";
+ ParameterSet pset4 = ParamPickerMake(txt);
+ const wchar_t* result3 = nullptr;
+ EXPECT_TRUE(pset4.Get(&result3));
+ EXPECT_EQ(0, wcscmp(txt, result3));
+}
+
+TEST(PolicyEngineTest, OpcodeConstraints) {
+ // Test that PolicyOpcode has no virtual functions
+ // because these objects are copied over to other processes
+ // so they cannot have vtables.
+ EXPECT_FALSE(__is_polymorphic(PolicyOpcode));
+ // Keep developers from adding smarts to the opcodes which should
+ // be pretty much a bag of bytes with a OO interface.
+ EXPECT_TRUE(__has_trivial_destructor(PolicyOpcode));
+ EXPECT_TRUE(__has_trivial_constructor(PolicyOpcode));
+ EXPECT_TRUE(__has_trivial_copy(PolicyOpcode));
+}
+
+TEST(PolicyEngineTest, TrueFalseOpcodes) {
+ void* dummy = nullptr;
+ ParameterSet ppb1 = ParamPickerMake(dummy);
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+ // This opcode always evaluates to true.
+ PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone);
+ ASSERT_NE(nullptr, op1);
+ EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&ppb1, 1, nullptr));
+ EXPECT_FALSE(op1->IsAction());
+
+ // This opcode always evaluates to false.
+ PolicyOpcode* op2 = opcode_maker.MakeOpAlwaysTrue(kPolNone);
+ ASSERT_NE(nullptr, op2);
+ EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, nullptr));
+
+ // Nulls not allowed on the params.
+ EXPECT_EQ(EVAL_ERROR, op2->Evaluate(nullptr, 0, nullptr));
+ EXPECT_EQ(EVAL_ERROR, op2->Evaluate(nullptr, 1, nullptr));
+
+ // True and False opcodes do not 'require' a number of parameters
+ EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 0, nullptr));
+ EXPECT_EQ(EVAL_TRUE, op2->Evaluate(&ppb1, 1, nullptr));
+
+ // Test Inverting the logic. Note that inversion is done outside
+ // any particular opcode evaluation so no need to repeat for all
+ // opcodes.
+ PolicyOpcode* op3 = opcode_maker.MakeOpAlwaysFalse(kPolNegateEval);
+ ASSERT_NE(nullptr, op3);
+ EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&ppb1, 1, nullptr));
+ PolicyOpcode* op4 = opcode_maker.MakeOpAlwaysTrue(kPolNegateEval);
+ ASSERT_NE(nullptr, op4);
+ EXPECT_EQ(EVAL_FALSE, op4->Evaluate(&ppb1, 1, nullptr));
+
+ // Test that we clear the match context
+ PolicyOpcode* op5 = opcode_maker.MakeOpAlwaysTrue(kPolClearContext);
+ ASSERT_NE(nullptr, op5);
+ MatchContext context;
+ context.position = 1;
+ context.options = kPolUseOREval;
+ EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&ppb1, 1, &context));
+ EXPECT_EQ(0u, context.position);
+ MatchContext context2;
+ EXPECT_EQ(context2.options, context.options);
+}
+
+TEST(PolicyEngineTest, OpcodeMakerCase1) {
+ // Testing that the opcode maker does not overrun the
+ // supplied buffer. It should only be able to make 'count' opcodes.
+ void* dummy = nullptr;
+ ParameterSet ppb1 = ParamPickerMake(dummy);
+
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+ size_t count = sizeof(memory) / sizeof(PolicyOpcode);
+
+ for (size_t ix = 0; ix != count; ++ix) {
+ PolicyOpcode* op = opcode_maker.MakeOpAlwaysFalse(kPolNone);
+ ASSERT_NE(nullptr, op);
+ EXPECT_EQ(EVAL_FALSE, op->Evaluate(&ppb1, 1, nullptr));
+ }
+ // There should be no room more another opcode:
+ PolicyOpcode* op1 = opcode_maker.MakeOpAlwaysFalse(kPolNone);
+ ASSERT_EQ(nullptr, op1);
+}
+
+TEST(PolicyEngineTest, OpcodeMakerCase2) {
+ SetupNtdllImports();
+ // Testing that the opcode maker does not overrun the
+ // supplied buffer. It should only be able to make 'count' opcodes.
+ // The difference with the previous test is that this opcodes allocate
+ // the string 'txt2' inside the same buffer.
+ const wchar_t* txt1 = L"1234";
+ const wchar_t txt2[] = L"123";
+
+ ParameterSet ppb1 = ParamPickerMake(txt1);
+ MatchContext mc1;
+
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+ size_t count = sizeof(memory) / (sizeof(PolicyOpcode) + sizeof(txt2));
+
+ // Test that it does not overrun the buffer.
+ for (size_t ix = 0; ix != count; ++ix) {
+ PolicyOpcode* op = opcode_maker.MakeOpWStringMatch(
+ 0, txt2, 0, CASE_SENSITIVE, kPolClearContext);
+ ASSERT_NE(nullptr, op);
+ EXPECT_EQ(EVAL_TRUE, op->Evaluate(&ppb1, 1, &mc1));
+ }
+
+ // There should be no room more another opcode:
+ PolicyOpcode* op1 =
+ opcode_maker.MakeOpWStringMatch(0, txt2, 0, CASE_SENSITIVE, kPolNone);
+ ASSERT_EQ(nullptr, op1);
+}
+
+TEST(PolicyEngineTest, IntegerOpcodes) {
+ const wchar_t* txt = L"abcdef";
+ uint32_t num1 = 42;
+ uint32_t num2 = 113377;
+
+ ParameterSet pp_wrong1 = ParamPickerMake(txt);
+ ParameterSet pp_num1 = ParamPickerMake(num1);
+ ParameterSet pp_num2 = ParamPickerMake(num2);
+
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+ // Test basic match for uint32s 42 == 42 and 42 != 113377.
+ PolicyOpcode* op_m42 = opcode_maker.MakeOpNumberMatch(0, 42UL, kPolNone);
+ ASSERT_NE(nullptr, op_m42);
+ EXPECT_EQ(EVAL_TRUE, op_m42->Evaluate(&pp_num1, 1, nullptr));
+ EXPECT_EQ(EVAL_FALSE, op_m42->Evaluate(&pp_num2, 1, nullptr));
+ EXPECT_EQ(EVAL_ERROR, op_m42->Evaluate(&pp_wrong1, 1, nullptr));
+
+ // Test basic match for void pointers.
+ const void* vp = nullptr;
+ ParameterSet pp_num3 = ParamPickerMake(vp);
+ PolicyOpcode* op_vp_null =
+ opcode_maker.MakeOpVoidPtrMatch(0, nullptr, kPolNone);
+ ASSERT_NE(nullptr, op_vp_null);
+ EXPECT_EQ(EVAL_TRUE, op_vp_null->Evaluate(&pp_num3, 1, nullptr));
+ EXPECT_EQ(EVAL_FALSE, op_vp_null->Evaluate(&pp_num1, 1, nullptr));
+ EXPECT_EQ(EVAL_ERROR, op_vp_null->Evaluate(&pp_wrong1, 1, nullptr));
+
+ // Basic range test [41 43] (inclusive).
+ PolicyOpcode* op_range1 =
+ opcode_maker.MakeOpNumberMatchRange(0, 41, 43, kPolNone);
+ ASSERT_NE(nullptr, op_range1);
+ EXPECT_EQ(EVAL_TRUE, op_range1->Evaluate(&pp_num1, 1, nullptr));
+ EXPECT_EQ(EVAL_FALSE, op_range1->Evaluate(&pp_num2, 1, nullptr));
+ EXPECT_EQ(EVAL_ERROR, op_range1->Evaluate(&pp_wrong1, 1, nullptr));
+}
+
+TEST(PolicyEngineTest, LogicalOpcodes) {
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+ uint32_t num1 = 0x10100702;
+ ParameterSet pp_num1 = ParamPickerMake(num1);
+
+ PolicyOpcode* op_and1 =
+ opcode_maker.MakeOpNumberAndMatch(0, 0x00100000, kPolNone);
+ ASSERT_NE(nullptr, op_and1);
+ EXPECT_EQ(EVAL_TRUE, op_and1->Evaluate(&pp_num1, 1, nullptr));
+ PolicyOpcode* op_and2 =
+ opcode_maker.MakeOpNumberAndMatch(0, 0x00000001, kPolNone);
+ ASSERT_NE(nullptr, op_and2);
+ EXPECT_EQ(EVAL_FALSE, op_and2->Evaluate(&pp_num1, 1, nullptr));
+}
+
+TEST(PolicyEngineTest, WCharOpcodes1) {
+ SetupNtdllImports();
+
+ const wchar_t* txt1 = L"the quick fox jumps over the lazy dog";
+ const wchar_t txt2[] = L"the quick";
+ const wchar_t txt3[] = L" fox jumps";
+ const wchar_t txt4[] = L"the lazy dog";
+ const wchar_t txt5[] = L"jumps over";
+ const wchar_t txt6[] = L"g";
+
+ ParameterSet pp_tc1 = ParamPickerMake(txt1);
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+
+ PolicyOpcode* op1 =
+ opcode_maker.MakeOpWStringMatch(0, txt2, 0, CASE_SENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op1);
+
+ // Simplest substring match from pos 0. It should be a successful match
+ // and the match context should be updated.
+ MatchContext mc1;
+ EXPECT_EQ(EVAL_TRUE, op1->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_TRUE(_countof(txt2) == mc1.position + 1);
+
+ // Matching again should fail and the context should be unmodified.
+ EXPECT_EQ(EVAL_FALSE, op1->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_TRUE(_countof(txt2) == mc1.position + 1);
+
+ // Using the same match context we should continue where we left
+ // in the previous successful match,
+ PolicyOpcode* op3 =
+ opcode_maker.MakeOpWStringMatch(0, txt3, 0, CASE_SENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op3);
+ EXPECT_EQ(EVAL_TRUE, op3->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_TRUE(_countof(txt3) + _countof(txt2) == mc1.position + 2);
+
+ // We now keep on matching but now we skip 6 characters which means
+ // we skip the string ' over '. And we zero the match context. This is
+ // the primitive that we use to build '??'.
+ PolicyOpcode* op4 = opcode_maker.MakeOpWStringMatch(
+ 0, txt4, 6, CASE_SENSITIVE, kPolClearContext);
+ ASSERT_NE(nullptr, op4);
+ EXPECT_EQ(EVAL_TRUE, op4->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_EQ(0u, mc1.position);
+
+ // Test that we can properly match the last part of the string
+ PolicyOpcode* op4b = opcode_maker.MakeOpWStringMatch(
+ 0, txt4, kSeekToEnd, CASE_SENSITIVE, kPolClearContext);
+ ASSERT_NE(nullptr, op4b);
+ EXPECT_EQ(EVAL_TRUE, op4b->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_EQ(0u, mc1.position);
+
+ // Test matching 'jumps over' over the entire string. This is the
+ // primitive we build '*' from.
+ PolicyOpcode* op5 = opcode_maker.MakeOpWStringMatch(0, txt5, kSeekForward,
+ CASE_SENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op5);
+ EXPECT_EQ(EVAL_TRUE, op5->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_EQ(24u, mc1.position);
+
+ // Test that we don't match because it is not at the end of the string
+ PolicyOpcode* op5b = opcode_maker.MakeOpWStringMatch(
+ 0, txt5, kSeekToEnd, CASE_SENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op5b);
+ EXPECT_EQ(EVAL_FALSE, op5b->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_EQ(24u, mc1.position);
+
+ // Test that we function if the string does not fit. In this case we
+ // try to match 'the lazy dog' against 'he lazy dog'.
+ PolicyOpcode* op6 =
+ opcode_maker.MakeOpWStringMatch(0, txt4, 2, CASE_SENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op6);
+ EXPECT_EQ(EVAL_FALSE, op6->Evaluate(&pp_tc1, 1, &mc1));
+
+ // Testing matching against 'g' which should be the last char.
+ MatchContext mc2;
+ PolicyOpcode* op7 = opcode_maker.MakeOpWStringMatch(0, txt6, kSeekForward,
+ CASE_SENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op7);
+ EXPECT_EQ(EVAL_TRUE, op7->Evaluate(&pp_tc1, 1, &mc2));
+ EXPECT_EQ(37u, mc2.position);
+
+ // Trying to match again should fail since we are in the last char.
+ // This also covers a couple of boundary conditions.
+ EXPECT_EQ(EVAL_FALSE, op7->Evaluate(&pp_tc1, 1, &mc2));
+ EXPECT_EQ(37u, mc2.position);
+}
+
+TEST(PolicyEngineTest, WCharOpcodes2) {
+ SetupNtdllImports();
+
+ const wchar_t* path1 = L"c:\\documents and settings\\Microsoft\\BLAH.txt";
+ const wchar_t txt1[] = L"Settings\\microsoft";
+ ParameterSet pp_tc1 = ParamPickerMake(path1);
+
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+ MatchContext mc1;
+
+ // Testing case-insensitive does not buy us much since it this option
+ // is just passed to the Microsoft API that we use normally, but just for
+ // coverage, here it is:
+ PolicyOpcode* op1s = opcode_maker.MakeOpWStringMatch(
+ 0, txt1, kSeekForward, CASE_SENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op1s);
+ PolicyOpcode* op1i = opcode_maker.MakeOpWStringMatch(
+ 0, txt1, kSeekForward, CASE_INSENSITIVE, kPolNone);
+ ASSERT_NE(nullptr, op1i);
+ EXPECT_EQ(EVAL_FALSE, op1s->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_EQ(EVAL_TRUE, op1i->Evaluate(&pp_tc1, 1, &mc1));
+ EXPECT_EQ(35u, mc1.position);
+}
+
+TEST(PolicyEngineTest, ActionOpcodes) {
+ char memory[kOpcodeMemory];
+ OpcodeFactory opcode_maker(memory, sizeof(memory));
+ MatchContext mc1;
+ void* dummy = nullptr;
+ ParameterSet ppb1 = ParamPickerMake(dummy);
+
+ PolicyOpcode* op1 = opcode_maker.MakeOpAction(ASK_BROKER, kPolNone);
+ ASSERT_NE(nullptr, op1);
+ EXPECT_TRUE(op1->IsAction());
+ EXPECT_EQ(ASK_BROKER, op1->Evaluate(&ppb1, 1, &mc1));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_params.h b/security/sandbox/chromium/sandbox/win/src/policy_params.h
new file mode 100644
index 0000000000..aeec6d7edc
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_params.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_POLICY_PARAMS_H__
+#define SANDBOX_SRC_POLICY_PARAMS_H__
+
+#include "sandbox/win/src/policy_engine_params.h"
+
+namespace sandbox {
+
+class ParameterSet;
+
+// Warning: The following macros store the address to the actual variables, in
+// other words, the values are not copied.
+#define POLPARAMS_BEGIN(type) class type { public: enum Args {
+#define POLPARAM(arg) arg,
+#define POLPARAMS_END(type) PolParamLast }; }; \
+ typedef sandbox::ParameterSet type##Array [type::PolParamLast];
+
+// Policy parameters for file open / create.
+POLPARAMS_BEGIN(OpenFile)
+ POLPARAM(NAME)
+ POLPARAM(BROKER) // true if called from the broker.
+ POLPARAM(ACCESS)
+ POLPARAM(DISPOSITION)
+ POLPARAM(OPTIONS)
+POLPARAMS_END(OpenFile)
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(FileName)
+ POLPARAM(NAME)
+ POLPARAM(BROKER) // true if called from the broker.
+POLPARAMS_END(FileName)
+
+static_assert(OpenFile::NAME == static_cast<int>(FileName::NAME),
+ "to simplify fs policies");
+static_assert(OpenFile::BROKER == static_cast<int>(FileName::BROKER),
+ "to simplify fs policies");
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(NameBased)
+ POLPARAM(NAME)
+POLPARAMS_END(NameBased)
+
+// Policy parameters for open event.
+POLPARAMS_BEGIN(OpenEventParams)
+ POLPARAM(NAME)
+ POLPARAM(ACCESS)
+POLPARAMS_END(OpenEventParams)
+
+// Policy Parameters for reg open / create.
+POLPARAMS_BEGIN(OpenKey)
+ POLPARAM(NAME)
+ POLPARAM(ACCESS)
+POLPARAMS_END(OpenKey)
+
+// Policy parameter for name-based policies.
+POLPARAMS_BEGIN(HandleTarget)
+ POLPARAM(NAME)
+ POLPARAM(TARGET)
+POLPARAMS_END(HandleTarget)
+
+// Policy parameters where no parameter based checks are done.
+POLPARAMS_BEGIN(EmptyParams)
+POLPARAMS_END(EmptyParams)
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_POLICY_PARAMS_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_target.cc b/security/sandbox/chromium/sandbox/win/src/policy_target.cc
new file mode 100644
index 0000000000..0a16022e70
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_target.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/policy_target.h"
+
+#include <stddef.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+// Handle for our private heap.
+extern void* g_heap;
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// Policy data.
+extern void* volatile g_shared_policy_memory;
+SANDBOX_INTERCEPT size_t g_shared_policy_size;
+
+bool QueryBroker(IpcTag ipc_id, CountedParameterSetBase* params) {
+ DCHECK_NT(static_cast<size_t>(ipc_id) < kMaxServiceCount);
+ DCHECK_NT(g_shared_policy_memory);
+ DCHECK_NT(g_shared_policy_size > 0);
+
+ if (static_cast<size_t>(ipc_id) >= kMaxServiceCount)
+ return false;
+
+ PolicyGlobal* global_policy =
+ reinterpret_cast<PolicyGlobal*>(g_shared_policy_memory);
+
+ if (!global_policy->entry[static_cast<size_t>(ipc_id)])
+ return false;
+
+ PolicyBuffer* policy = reinterpret_cast<PolicyBuffer*>(
+ reinterpret_cast<char*>(g_shared_policy_memory) +
+ reinterpret_cast<size_t>(
+ global_policy->entry[static_cast<size_t>(ipc_id)]));
+
+ if ((reinterpret_cast<size_t>(
+ global_policy->entry[static_cast<size_t>(ipc_id)]) >
+ global_policy->data_size) ||
+ (g_shared_policy_size < global_policy->data_size)) {
+ NOTREACHED_NT();
+ return false;
+ }
+
+ for (size_t i = 0; i < params->count; i++) {
+ if (!params->parameters[i].IsValid()) {
+ NOTREACHED_NT();
+ return false;
+ }
+ }
+
+ PolicyProcessor processor(policy);
+ PolicyResult result =
+ processor.Evaluate(kShortEval, params->parameters, params->count);
+ DCHECK_NT(POLICY_ERROR != result);
+
+ return POLICY_MATCH == result && ASK_BROKER == processor.GetAction();
+}
+
+// -----------------------------------------------------------------------
+
+// Hooks NtImpersonateAnonymousToken so we can block until call to LowerToken.
+// This means a non-retricted token behaves the same as restricted one before
+// LowerToken and prevents us from being left with an anonymous logon token
+// because we are blocking the RevertToSelf that would undo it.
+NTSTATUS WINAPI TargetNtImpersonateAnonymousToken(
+ NtImpersonateAnonymousTokenFunction orig_ImpersonateAnonymousToken,
+ HANDLE thread) {
+ if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ return orig_ImpersonateAnonymousToken(thread);
+}
+
+// Hooks NtSetInformationThread to block RevertToSelf from being
+// called before the actual call to LowerToken.
+NTSTATUS WINAPI TargetNtSetInformationThread(
+ NtSetInformationThreadFunction orig_SetInformationThread,
+ HANDLE thread,
+ NT_THREAD_INFORMATION_CLASS thread_info_class,
+ PVOID thread_information,
+ ULONG thread_information_bytes) {
+ do {
+ if (SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf())
+ break;
+ if (ThreadImpersonationToken != thread_info_class)
+ break;
+ // This is a revert to self.
+ return STATUS_SUCCESS;
+ } while (false);
+
+ return orig_SetInformationThread(
+ thread, thread_info_class, thread_information, thread_information_bytes);
+}
+
+// Hooks NtOpenThreadToken to force the open_as_self parameter to be set to
+// false if we are still running with the impersonation token. open_as_self set
+// to true means that the token will be open using the process token instead of
+// the impersonation token. This is bad because the process token does not have
+// access to open the thread token.
+NTSTATUS WINAPI
+TargetNtOpenThreadToken(NtOpenThreadTokenFunction orig_OpenThreadToken,
+ HANDLE thread,
+ ACCESS_MASK desired_access,
+ BOOLEAN open_as_self,
+ PHANDLE token) {
+ if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf())
+ open_as_self = false;
+
+ return orig_OpenThreadToken(thread, desired_access, open_as_self, token);
+}
+
+// See comment for TargetNtOpenThreadToken
+NTSTATUS WINAPI
+TargetNtOpenThreadTokenEx(NtOpenThreadTokenExFunction orig_OpenThreadTokenEx,
+ HANDLE thread,
+ ACCESS_MASK desired_access,
+ BOOLEAN open_as_self,
+ ULONG handle_attributes,
+ PHANDLE token) {
+ if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf())
+ open_as_self = false;
+
+ return orig_OpenThreadTokenEx(thread, desired_access, open_as_self,
+ handle_attributes, token);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_target.h b/security/sandbox/chromium/sandbox/win/src/policy_target.h
new file mode 100644
index 0000000000..7eeabef386
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_target.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_POLICY_TARGET_H_
+#define SANDBOX_WIN_SRC_POLICY_TARGET_H_
+
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+struct CountedParameterSetBase;
+
+// Performs a policy lookup and returns true if the request should be passed to
+// the broker process.
+bool QueryBroker(IpcTag ipc_id, CountedParameterSetBase* params);
+
+extern "C" {
+
+// Interception of NtImpersonateAnonymousToken on the child process.
+// It should never be called directly.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtImpersonateAnonymousToken(
+ NtImpersonateAnonymousTokenFunction orig_ImpersonateAnonymousToken,
+ HANDLE thread);
+
+// Interception of NtSetInformationThread on the child process.
+// It should never be called directly.
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtSetInformationThread(
+ NtSetInformationThreadFunction orig_SetInformationThread, HANDLE thread,
+ NT_THREAD_INFORMATION_CLASS thread_info_class, PVOID thread_information,
+ ULONG thread_information_bytes);
+
+// Interception of NtOpenThreadToken on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThreadToken(
+ NtOpenThreadTokenFunction orig_OpenThreadToken, HANDLE thread,
+ ACCESS_MASK desired_access, BOOLEAN open_as_self, PHANDLE token);
+
+// Interception of NtOpenThreadTokenEx on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenThreadTokenEx(
+ NtOpenThreadTokenExFunction orig_OpenThreadTokenEx, HANDLE thread,
+ ACCESS_MASK desired_access, BOOLEAN open_as_self, ULONG handle_attributes,
+ PHANDLE token);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_POLICY_TARGET_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/policy_target_test.cc b/security/sandbox/chromium/sandbox/win/src/policy_target_test.cc
new file mode 100644
index 0000000000..4ee03e19f6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/policy_target_test.cc
@@ -0,0 +1,486 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/writable_shared_memory_region.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
+namespace sandbox {
+
+#define BINDNTDLL(name) \
+ name##Function name = reinterpret_cast<name##Function>( \
+ ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
+
+// Reverts to self and verify that SetInformationToken was faked. Returns
+// SBOX_TEST_SUCCEEDED if faked and SBOX_TEST_FAILED if not faked.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token(int argc, wchar_t** argv) {
+ HANDLE thread_token;
+ // Get the thread token, using impersonation.
+ if (!::OpenThreadToken(GetCurrentThread(),
+ TOKEN_IMPERSONATE | TOKEN_DUPLICATE, false,
+ &thread_token))
+ return ::GetLastError();
+
+ ::RevertToSelf();
+ ::CloseHandle(thread_token);
+
+ int ret = SBOX_TEST_FAILED;
+ if (::OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+ false, &thread_token)) {
+ ret = SBOX_TEST_SUCCEEDED;
+ ::CloseHandle(thread_token);
+ }
+ return ret;
+}
+
+// Stores the high privilege token on a static variable, change impersonation
+// again to that one and verify that we are not interfering anymore with
+// RevertToSelf.
+SBOX_TESTS_COMMAND int PolicyTargetTest_steal(int argc, wchar_t** argv) {
+ static HANDLE thread_token;
+ if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) {
+ if (!::OpenThreadToken(GetCurrentThread(),
+ TOKEN_IMPERSONATE | TOKEN_DUPLICATE, false,
+ &thread_token))
+ return ::GetLastError();
+ } else {
+ if (!::SetThreadToken(nullptr, thread_token))
+ return ::GetLastError();
+
+ // See if we fake the call again.
+ int ret = PolicyTargetTest_token(argc, argv);
+ ::CloseHandle(thread_token);
+ return ret;
+ }
+ return 0;
+}
+
+// Opens the thread token with and without impersonation.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token2(int argc, wchar_t** argv) {
+ HANDLE thread_token;
+ // Get the thread token, using impersonation.
+ if (!::OpenThreadToken(GetCurrentThread(),
+ TOKEN_IMPERSONATE | TOKEN_DUPLICATE, false,
+ &thread_token))
+ return ::GetLastError();
+ ::CloseHandle(thread_token);
+
+ // Get the thread token, without impersonation.
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+ true, &thread_token))
+ return ::GetLastError();
+ ::CloseHandle(thread_token);
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Opens the thread token with and without impersonation, using
+// NtOpenThreadTokenEX.
+SBOX_TESTS_COMMAND int PolicyTargetTest_token3(int argc, wchar_t** argv) {
+ BINDNTDLL(NtOpenThreadTokenEx);
+ if (!NtOpenThreadTokenEx)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ HANDLE thread_token;
+ // Get the thread token, using impersonation.
+ NTSTATUS status = NtOpenThreadTokenEx(GetCurrentThread(),
+ TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
+ false, 0, &thread_token);
+ if (status == STATUS_NO_TOKEN)
+ return ERROR_NO_TOKEN;
+ if (!NT_SUCCESS(status))
+ return SBOX_TEST_FAILED;
+
+ ::CloseHandle(thread_token);
+
+ // Get the thread token, without impersonation.
+ status = NtOpenThreadTokenEx(GetCurrentThread(),
+ TOKEN_IMPERSONATE | TOKEN_DUPLICATE, true, 0,
+ &thread_token);
+ if (!NT_SUCCESS(status))
+ return SBOX_TEST_FAILED;
+
+ ::CloseHandle(thread_token);
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests that we can open the current thread.
+SBOX_TESTS_COMMAND int PolicyTargetTest_thread(int argc, wchar_t** argv) {
+ DWORD thread_id = ::GetCurrentThreadId();
+ HANDLE thread = ::OpenThread(SYNCHRONIZE, false, thread_id);
+ if (!thread)
+ return ::GetLastError();
+ if (!::CloseHandle(thread))
+ return ::GetLastError();
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// New thread entry point: do nothing.
+DWORD WINAPI PolicyTargetTest_thread_main(void* param) {
+ ::Sleep(INFINITE);
+ return 0;
+}
+
+// Tests that we can create a new thread, and open it.
+SBOX_TESTS_COMMAND int PolicyTargetTest_thread2(int argc, wchar_t** argv) {
+ // Use default values to create a new thread.
+ DWORD thread_id;
+ HANDLE thread = ::CreateThread(nullptr, 0, &PolicyTargetTest_thread_main, 0,
+ 0, &thread_id);
+ if (!thread)
+ return ::GetLastError();
+ if (!::CloseHandle(thread))
+ return ::GetLastError();
+
+ thread = ::OpenThread(SYNCHRONIZE, false, thread_id);
+ if (!thread)
+ return ::GetLastError();
+
+ if (!::CloseHandle(thread))
+ return ::GetLastError();
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Tests that we can call CreateProcess.
+SBOX_TESTS_COMMAND int PolicyTargetTest_process(int argc, wchar_t** argv) {
+ // Use default values to create a new process.
+ STARTUPINFO startup_info = {0};
+ startup_info.cb = sizeof(startup_info);
+ PROCESS_INFORMATION temp_process_info = {};
+ // Note: CreateProcessW() can write to its lpCommandLine, don't pass a
+ // raw string literal.
+ std::wstring writable_cmdline_str(L"foo.exe");
+ if (!::CreateProcessW(L"foo.exe", &writable_cmdline_str[0], nullptr, nullptr,
+ false, 0, nullptr, nullptr, &startup_info,
+ &temp_process_info))
+ return SBOX_TEST_SUCCEEDED;
+ base::win::ScopedProcessInformation process_info(temp_process_info);
+ return SBOX_TEST_FAILED;
+}
+
+TEST(PolicyTargetTest, SetInformationThread) {
+ TestRunner runner;
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token"));
+
+ runner.SetTestState(AFTER_REVERT);
+ EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token"));
+
+ runner.SetTestState(EVERY_STATE);
+ EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"PolicyTargetTest_steal"));
+}
+
+TEST(PolicyTargetTest, OpenThreadToken) {
+ TestRunner runner;
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token2"));
+
+ runner.SetTestState(AFTER_REVERT);
+ EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token2"));
+}
+
+TEST(PolicyTargetTest, OpenThreadTokenEx) {
+ TestRunner runner;
+
+ runner.SetTestState(BEFORE_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_token3"));
+
+ runner.SetTestState(AFTER_REVERT);
+ EXPECT_EQ(ERROR_NO_TOKEN, runner.RunTest(L"PolicyTargetTest_token3"));
+}
+
+TEST(PolicyTargetTest, OpenThread) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread"))
+ << "Opens the current thread";
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread2"))
+ << "Creates a new thread and opens it";
+}
+
+TEST(PolicyTargetTest, OpenProcess) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_process"))
+ << "Opens a process";
+}
+
+TEST(PolicyTargetTest, PolicyBaseNoJobLifetime) {
+ TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+ runner.SetReleasePolicyInRun(true);
+ // TargetPolicy and its SharedMemIPCServer should continue to exist until
+ // the child process dies.
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"PolicyTargetTest_thread"))
+ << "Opens the current thread";
+}
+
+// Launches the app in the sandbox and ask it to wait in an
+// infinite loop. Waits for 2 seconds and then check if the
+// desktop associated with the app thread is not the same as the
+// current desktop.
+TEST(PolicyTargetTest, DesktopPolicy) {
+ BrokerServices* broker = GetBroker();
+
+ // Precreate the desktop.
+ scoped_refptr<TargetPolicy> temp_policy = broker->CreatePolicy();
+ temp_policy->CreateAlternateDesktop(false);
+ temp_policy = nullptr;
+
+ ASSERT_TRUE(broker);
+
+ // Get the path to the sandboxed app.
+ wchar_t prog_name[MAX_PATH];
+ GetModuleFileNameW(nullptr, prog_name, MAX_PATH);
+
+ std::wstring arguments(L"\"");
+ arguments += prog_name;
+ arguments += L"\" -child 0 wait"; // Don't care about the "state" argument.
+
+ // Launch the app.
+ ResultCode result = SBOX_ALL_OK;
+ ResultCode warning_result = SBOX_ALL_OK;
+ DWORD last_error = ERROR_SUCCESS;
+ base::win::ScopedProcessInformation target;
+
+ scoped_refptr<TargetPolicy> policy = broker->CreatePolicy();
+ policy->SetAlternateDesktop(false);
+ policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+ PROCESS_INFORMATION temp_process_info = {};
+ result =
+ broker->SpawnTarget(prog_name, arguments.c_str(), policy, &warning_result,
+ &last_error, &temp_process_info);
+ std::wstring desktop_name = policy->GetAlternateDesktop();
+ policy = nullptr;
+
+ EXPECT_EQ(SBOX_ALL_OK, result);
+ if (result == SBOX_ALL_OK)
+ target.Set(temp_process_info);
+
+ EXPECT_EQ(1u, ::ResumeThread(target.thread_handle()));
+
+ EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+ ::WaitForSingleObject(target.process_handle(), 2000));
+
+ EXPECT_NE(::GetThreadDesktop(target.thread_id()),
+ ::GetThreadDesktop(::GetCurrentThreadId()));
+
+ HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, false, DESKTOP_ENUMERATE);
+ EXPECT_TRUE(desk);
+ EXPECT_TRUE(::CloseDesktop(desk));
+ EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
+
+ ::WaitForSingleObject(target.process_handle(), INFINITE);
+
+ // Close the desktop handle.
+ temp_policy = broker->CreatePolicy();
+ temp_policy->DestroyAlternateDesktop();
+ temp_policy = nullptr;
+
+ // Make sure the desktop does not exist anymore.
+ desk = ::OpenDesktop(desktop_name.c_str(), 0, false, DESKTOP_ENUMERATE);
+ EXPECT_FALSE(desk);
+}
+
+// Launches the app in the sandbox and ask it to wait in an
+// infinite loop. Waits for 2 seconds and then check if the
+// winstation associated with the app thread is not the same as the
+// current desktop.
+TEST(PolicyTargetTest, WinstaPolicy) {
+ BrokerServices* broker = GetBroker();
+
+ // Precreate the desktop.
+ scoped_refptr<TargetPolicy> temp_policy = broker->CreatePolicy();
+ temp_policy->CreateAlternateDesktop(true);
+ temp_policy = nullptr;
+
+ ASSERT_TRUE(broker);
+
+ // Get the path to the sandboxed app.
+ wchar_t prog_name[MAX_PATH];
+ GetModuleFileNameW(nullptr, prog_name, MAX_PATH);
+
+ std::wstring arguments(L"\"");
+ arguments += prog_name;
+ arguments += L"\" -child 0 wait"; // Don't care about the "state" argument.
+
+ // Launch the app.
+ ResultCode result = SBOX_ALL_OK;
+ ResultCode warning_result = SBOX_ALL_OK;
+ base::win::ScopedProcessInformation target;
+
+ scoped_refptr<TargetPolicy> policy = broker->CreatePolicy();
+ policy->SetAlternateDesktop(true);
+ policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+ PROCESS_INFORMATION temp_process_info = {};
+ DWORD last_error = ERROR_SUCCESS;
+ result =
+ broker->SpawnTarget(prog_name, arguments.c_str(), policy, &warning_result,
+ &last_error, &temp_process_info);
+ std::wstring desktop_name = policy->GetAlternateDesktop();
+ policy = nullptr;
+
+ EXPECT_EQ(SBOX_ALL_OK, result);
+ if (result == SBOX_ALL_OK)
+ target.Set(temp_process_info);
+
+ EXPECT_EQ(1u, ::ResumeThread(target.thread_handle()));
+
+ EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+ ::WaitForSingleObject(target.process_handle(), 2000));
+
+ EXPECT_NE(::GetThreadDesktop(target.thread_id()),
+ ::GetThreadDesktop(::GetCurrentThreadId()));
+
+ ASSERT_FALSE(desktop_name.empty());
+
+ // Make sure there is a backslash, for the window station name.
+ EXPECT_NE(desktop_name.find_first_of(L'\\'), std::wstring::npos);
+
+ // Isolate the desktop name.
+ desktop_name = desktop_name.substr(desktop_name.find_first_of(L'\\') + 1);
+
+ HDESK desk = ::OpenDesktop(desktop_name.c_str(), 0, false, DESKTOP_ENUMERATE);
+ // This should fail if the desktop is really on another window station.
+ EXPECT_FALSE(desk);
+ EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
+
+ ::WaitForSingleObject(target.process_handle(), INFINITE);
+
+ // Close the desktop handle.
+ temp_policy = broker->CreatePolicy();
+ temp_policy->DestroyAlternateDesktop();
+ temp_policy = nullptr;
+}
+
+// Creates multiple policies, with alternate desktops on both local and
+// alternate winstations.
+TEST(PolicyTargetTest, BothLocalAndAlternateWinstationDesktop) {
+ BrokerServices* broker = GetBroker();
+
+ scoped_refptr<TargetPolicy> policy1 = broker->CreatePolicy();
+ scoped_refptr<TargetPolicy> policy2 = broker->CreatePolicy();
+ scoped_refptr<TargetPolicy> policy3 = broker->CreatePolicy();
+
+ ResultCode result;
+ result = policy1->SetAlternateDesktop(false);
+ EXPECT_EQ(SBOX_ALL_OK, result);
+ result = policy2->SetAlternateDesktop(true);
+ EXPECT_EQ(SBOX_ALL_OK, result);
+ result = policy3->SetAlternateDesktop(false);
+ EXPECT_EQ(SBOX_ALL_OK, result);
+
+ std::wstring policy1_desktop_name = policy1->GetAlternateDesktop();
+ std::wstring policy2_desktop_name = policy2->GetAlternateDesktop();
+
+ // Extract only the "desktop name" portion of
+ // "{winstation name}\\{desktop name}"
+ EXPECT_NE(policy1_desktop_name.substr(
+ policy1_desktop_name.find_first_of(L'\\') + 1),
+ policy2_desktop_name.substr(
+ policy2_desktop_name.find_first_of(L'\\') + 1));
+
+ policy1->DestroyAlternateDesktop();
+ policy2->DestroyAlternateDesktop();
+ policy3->DestroyAlternateDesktop();
+}
+
+// Launches the app in the sandbox and share a handle with it. The app should
+// be able to use the handle.
+TEST(PolicyTargetTest, ShareHandleTest) {
+ BrokerServices* broker = GetBroker();
+ ASSERT_TRUE(broker);
+
+ base::StringPiece contents = "Hello World";
+ base::WritableSharedMemoryRegion writable_region =
+ base::WritableSharedMemoryRegion::Create(contents.size());
+ ASSERT_TRUE(writable_region.IsValid());
+ base::WritableSharedMemoryMapping writable_mapping = writable_region.Map();
+ ASSERT_TRUE(writable_mapping.IsValid());
+ memcpy(writable_mapping.memory(), contents.data(), contents.size());
+
+ // Get the path to the sandboxed app.
+ wchar_t prog_name[MAX_PATH];
+ GetModuleFileNameW(nullptr, prog_name, MAX_PATH);
+
+ base::ReadOnlySharedMemoryRegion read_only_region =
+ base::WritableSharedMemoryRegion::ConvertToReadOnly(
+ std::move(writable_region));
+ ASSERT_TRUE(read_only_region.IsValid());
+
+ scoped_refptr<TargetPolicy> policy = broker->CreatePolicy();
+ policy->AddHandleToShare(read_only_region.GetPlatformHandle());
+
+ std::wstring arguments(L"\"");
+ arguments += prog_name;
+ arguments += L"\" -child 0 shared_memory_handle ";
+ arguments += base::AsWString(base::NumberToString16(
+ base::win::HandleToUint32(read_only_region.GetPlatformHandle())));
+
+ // Launch the app.
+ ResultCode result = SBOX_ALL_OK;
+ ResultCode warning_result = SBOX_ALL_OK;
+ base::win::ScopedProcessInformation target;
+
+ policy->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+ PROCESS_INFORMATION temp_process_info = {};
+ DWORD last_error = ERROR_SUCCESS;
+ result =
+ broker->SpawnTarget(prog_name, arguments.c_str(), policy, &warning_result,
+ &last_error, &temp_process_info);
+ policy = nullptr;
+
+ EXPECT_EQ(SBOX_ALL_OK, result);
+ if (result == SBOX_ALL_OK)
+ target.Set(temp_process_info);
+
+ EXPECT_EQ(1u, ::ResumeThread(target.thread_handle()));
+
+ EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+ ::WaitForSingleObject(target.process_handle(), 2000));
+
+ EXPECT_TRUE(::TerminateProcess(target.process_handle(), 0));
+
+ ::WaitForSingleObject(target.process_handle(), INFINITE);
+}
+
+// Dummy target that just reports that's it spawned correctly.
+SBOX_TESTS_COMMAND int PolicyTargetTest_SetEffectiveToken(int argc,
+ wchar_t** argv) {
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Test whether after using SetEffectiveToken spawning a target works as
+// expected.
+TEST(PolicyTargetTest, SetEffectiveToken) {
+ TestRunner runner;
+ HANDLE token;
+
+ // Get current process token.
+ EXPECT_TRUE(
+ ::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
+
+ // Setup token guard.
+ base::win::ScopedHandle token_guard(token);
+
+ // Set token and run target.
+ runner.GetPolicy()->SetEffectiveToken(token_guard.Get());
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"PolicyTargetTest_SetEffectiveToken"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
new file mode 100644
index 0000000000..557296c93f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
@@ -0,0 +1,622 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations.h"
+
+#include <stddef.h>
+#include <windows.h>
+#include <wow64apiset.h>
+
+#include <algorithm>
+
+#include "base/win/windows_version.h"
+#include "build/build_config.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/sandbox_rand.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// API defined in libloaderapi.h >= Win8.
+using SetDefaultDllDirectoriesFunction = decltype(&SetDefaultDllDirectories);
+
+// APIs defined in processthreadsapi.h >= Win8.
+using SetProcessMitigationPolicyFunction =
+ decltype(&SetProcessMitigationPolicy);
+using GetProcessMitigationPolicyFunction =
+ decltype(&GetProcessMitigationPolicy);
+using SetThreadInformationFunction = decltype(&SetThreadInformation);
+
+// Returns a two-element array of mitigation flags supported on this machine.
+// - This function is only useful on >= base::win::Version::WIN8.
+const ULONG64* GetSupportedMitigations() {
+ static ULONG64 mitigations[2] = {};
+
+ // This static variable will only be initialized once.
+ if (!mitigations[0] && !mitigations[1]) {
+ GetProcessMitigationPolicyFunction get_process_mitigation_policy =
+ reinterpret_cast<GetProcessMitigationPolicyFunction>(::GetProcAddress(
+ ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy"));
+ if (get_process_mitigation_policy) {
+ // NOTE: the two-element-sized input array is only supported on >= Win10
+ // RS2.
+ // If an earlier version, the second element will be left 0.
+ size_t mits_size =
+ (base::win::GetVersion() >= base::win::Version::WIN10_RS2)
+ ? (sizeof(mitigations[0]) * 2)
+ : sizeof(mitigations[0]);
+ if (!get_process_mitigation_policy(::GetCurrentProcess(),
+ ProcessMitigationOptionsMask,
+ &mitigations, mits_size)) {
+ NOTREACHED();
+ }
+ }
+ }
+
+ return &mitigations[0];
+}
+
+// Returns true if this is 32-bit Chrome running on ARM64 with emulation.
+// Needed because ACG does not work with emulated code.
+// See
+// https://docs.microsoft.com/en-us/windows/uwp/porting/apps-on-arm-troubleshooting-x86.
+// See https://crbug.com/977723.
+// TODO(wfh): Move this code into base. See https://crbug.com/978257.
+bool IsRunning32bitEmulatedOnArm64() {
+#if defined(ARCH_CPU_X86)
+ using IsWow64Process2Function = decltype(&IsWow64Process2);
+
+ IsWow64Process2Function is_wow64_process2 =
+ reinterpret_cast<IsWow64Process2Function>(::GetProcAddress(
+ ::GetModuleHandleA("kernel32.dll"), "IsWow64Process2"));
+ if (!is_wow64_process2)
+ return false;
+ USHORT process_machine;
+ USHORT native_machine;
+ bool retval = is_wow64_process2(::GetCurrentProcess(), &process_machine,
+ &native_machine);
+ if (!retval)
+ return false;
+ if (native_machine == IMAGE_FILE_MACHINE_ARM64)
+ return true;
+#endif // defined(ARCH_CPU_X86)
+ return false;
+}
+
+// Returns true if user-mode Hardware-enforced Stack Protection is available for
+// the Win32 environment.
+bool IsUserCetWin32Available() {
+ static bool cetAvailable = []() -> bool {
+ using IsUserCetAvailableInEnvironmentFunction =
+ decltype(&IsUserCetAvailableInEnvironment);
+
+ IsUserCetAvailableInEnvironmentFunction is_user_cet_available =
+ reinterpret_cast<IsUserCetAvailableInEnvironmentFunction>(
+ ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"),
+ "IsUserCetAvailableInEnvironment"));
+ if (!is_user_cet_available) {
+ return false;
+ }
+
+ return is_user_cet_available(USER_CET_ENVIRONMENT_WIN32_PROCESS);
+ }();
+
+ return cetAvailable;
+}
+
+} // namespace
+
+namespace sandbox {
+
+bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags) {
+ if (!CanSetProcessMitigationsPostStartup(flags))
+ return false;
+
+ base::win::Version version = base::win::GetVersion();
+ HMODULE module = ::GetModuleHandleA("kernel32.dll");
+
+ if (flags & MITIGATION_DLL_SEARCH_ORDER) {
+ SetDefaultDllDirectoriesFunction set_default_dll_directories =
+ reinterpret_cast<SetDefaultDllDirectoriesFunction>(
+ ::GetProcAddress(module, "SetDefaultDllDirectories"));
+
+ // Check for SetDefaultDllDirectories since it requires KB2533623.
+ if (set_default_dll_directories) {
+ if (!set_default_dll_directories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+ }
+
+ // Set the heap to terminate on corruption
+ if (flags & MITIGATION_HEAP_TERMINATE) {
+ if (!::HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption,
+ nullptr, 0) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ if (flags & MITIGATION_HARDEN_TOKEN_IL_POLICY) {
+ DWORD error = HardenProcessIntegrityLevelPolicy();
+ if ((error != ERROR_SUCCESS) && (error != ERROR_ACCESS_DENIED))
+ return false;
+ }
+
+#if !defined(_WIN64) // DEP is always enabled on 64-bit.
+ if (flags & MITIGATION_DEP) {
+ DWORD dep_flags = PROCESS_DEP_ENABLE;
+
+ if (flags & MITIGATION_DEP_NO_ATL_THUNK)
+ dep_flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
+
+ if (!::SetProcessDEPPolicy(dep_flags) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+#endif
+
+ // This is all we can do in Win7 and below.
+ if (version < base::win::Version::WIN8)
+ return true;
+
+ SetProcessMitigationPolicyFunction set_process_mitigation_policy =
+ reinterpret_cast<SetProcessMitigationPolicyFunction>(
+ ::GetProcAddress(module, "SetProcessMitigationPolicy"));
+ if (!set_process_mitigation_policy)
+ return false;
+
+ // Enable ASLR policies.
+ if (flags & MITIGATION_RELOCATE_IMAGE) {
+ PROCESS_MITIGATION_ASLR_POLICY policy = {};
+ policy.EnableForceRelocateImages = true;
+ policy.DisallowStrippedImages =
+ (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) ==
+ MITIGATION_RELOCATE_IMAGE_REQUIRED;
+
+ if (!set_process_mitigation_policy(ProcessASLRPolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ // Enable strict handle policies.
+ if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
+ PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {};
+ policy.HandleExceptionsPermanentlyEnabled =
+ policy.RaiseExceptionOnInvalidHandleReference = true;
+
+ if (!set_process_mitigation_policy(ProcessStrictHandleCheckPolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ // Enable system call policies.
+ if (flags & MITIGATION_WIN32K_DISABLE) {
+ PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {};
+ policy.DisallowWin32kSystemCalls = true;
+
+ if (!set_process_mitigation_policy(ProcessSystemCallDisablePolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ // Enable extension point policies.
+ if (flags & MITIGATION_EXTENSION_POINT_DISABLE) {
+ PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {};
+ policy.DisableExtensionPoints = true;
+
+ if (!set_process_mitigation_policy(ProcessExtensionPointDisablePolicy,
+ &policy, sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ if (version < base::win::Version::WIN8_1)
+ return true;
+
+ // Enable dynamic code policies.
+ if (!IsRunning32bitEmulatedOnArm64() &&
+ (flags & MITIGATION_DYNAMIC_CODE_DISABLE)) {
+ // Verify caller is not accidentally setting both mutually exclusive
+ // policies.
+ DCHECK(!(flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT));
+ PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {};
+ policy.ProhibitDynamicCode = true;
+
+ if (!set_process_mitigation_policy(ProcessDynamicCodePolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ if (version < base::win::Version::WIN10)
+ return true;
+
+ // Enable font policies.
+ if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) {
+ PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {};
+ policy.DisableNonSystemFonts = true;
+
+ if (!set_process_mitigation_policy(ProcessFontDisablePolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ if (version < base::win::Version::WIN10_TH2)
+ return true;
+
+ // Enable binary signing policies.
+ if (flags & MITIGATION_FORCE_MS_SIGNED_BINS) {
+ PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY policy = {};
+ // Allow only MS signed binaries.
+ policy.MicrosoftSignedOnly = true;
+ // NOTE: there are two other flags available to allow
+ // 1) Only Windows Store signed.
+ // 2) MS-signed, Win Store signed, and WHQL signed binaries.
+ // Support not added at the moment.
+ if (!set_process_mitigation_policy(ProcessSignaturePolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ // Enable image load policies.
+ if (flags & MITIGATION_IMAGE_LOAD_NO_REMOTE ||
+ flags & MITIGATION_IMAGE_LOAD_NO_LOW_LABEL ||
+ flags & MITIGATION_IMAGE_LOAD_PREFER_SYS32) {
+ PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {};
+ if (flags & MITIGATION_IMAGE_LOAD_NO_REMOTE)
+ policy.NoRemoteImages = true;
+ if (flags & MITIGATION_IMAGE_LOAD_NO_LOW_LABEL)
+ policy.NoLowMandatoryLabelImages = true;
+ // PreferSystem32 is only supported on >= Anniversary.
+ if (version >= base::win::Version::WIN10_RS1 &&
+ flags & MITIGATION_IMAGE_LOAD_PREFER_SYS32) {
+ policy.PreferSystem32Images = true;
+ }
+
+ if (!set_process_mitigation_policy(ProcessImageLoadPolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ if (version < base::win::Version::WIN10_RS1)
+ return true;
+
+ // Enable dynamic code policies.
+ // Per-thread opt-out is only supported on >= Anniversary (RS1).
+ if (!IsRunning32bitEmulatedOnArm64() &&
+ (flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT)) {
+ // Verify caller is not accidentally setting both mutually exclusive
+ // policies.
+ DCHECK(!(flags & MITIGATION_DYNAMIC_CODE_DISABLE));
+ PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {};
+ policy.ProhibitDynamicCode = true;
+ policy.AllowThreadOptOut = true;
+
+ if (!set_process_mitigation_policy(ProcessDynamicCodePolicy, &policy,
+ sizeof(policy)) &&
+ ERROR_ACCESS_DENIED != ::GetLastError()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ApplyMitigationsToCurrentThread(MitigationFlags flags) {
+ if (!CanSetMitigationsPerThread(flags))
+ return false;
+
+ base::win::Version version = base::win::GetVersion();
+
+ if (version < base::win::Version::WIN10_RS1)
+ return true;
+
+ // Enable dynamic code per-thread policies.
+ if (flags & MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD) {
+ DWORD thread_policy = THREAD_DYNAMIC_CODE_ALLOW;
+
+ // NOTE: SetThreadInformation API only exists on >= Win8. Dynamically
+ // get function handle.
+ SetThreadInformationFunction set_thread_info_function =
+ reinterpret_cast<SetThreadInformationFunction>(::GetProcAddress(
+ ::GetModuleHandleA("kernel32.dll"), "SetThreadInformation"));
+ if (!set_thread_info_function)
+ return false;
+
+ // NOTE: Must use the pseudo-handle here, a thread HANDLE won't work.
+ if (!set_thread_info_function(::GetCurrentThread(), ThreadDynamicCodePolicy,
+ &thread_policy, sizeof(thread_policy))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
+ DWORD64* policy_flags,
+ size_t* size) {
+ base::win::Version version = base::win::GetVersion();
+
+ // |policy_flags| is a two-element array of DWORD64s. Ensure mitigation flags
+ // from PROCESS_CREATION_MITIGATION_POLICY2_* go into the second value. If
+ // any flags are set in value 2, update |size| to include both elements.
+ DWORD64* policy_value_1 = &policy_flags[0];
+ DWORD64* policy_value_2 = &policy_flags[1];
+ *policy_value_1 = 0;
+ *policy_value_2 = 0;
+
+#if defined(_WIN64)
+ *size = sizeof(*policy_flags);
+#elif defined(_M_IX86)
+ // A 64-bit flags attribute is illegal on 32-bit Win 7.
+ if (version < base::win::Version::WIN8)
+ *size = sizeof(DWORD);
+ else
+ *size = sizeof(*policy_flags);
+#else
+#error This platform is not supported.
+#endif
+
+// DEP and SEHOP are not valid for 64-bit Windows
+#if !defined(_WIN64)
+ if (flags & MITIGATION_DEP) {
+ *policy_value_1 |= PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE;
+ if (!(flags & MITIGATION_DEP_NO_ATL_THUNK))
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE;
+ }
+
+ if (flags & MITIGATION_SEHOP)
+ *policy_value_1 |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE;
+#endif
+
+ // Win 7
+ if (version < base::win::Version::WIN8)
+ return;
+
+ // Everything >= Win8, do not return before the end of the function where
+ // the final policy bitmap is sanity checked against what is supported on this
+ // machine. The API required to do so is only available since Win8.
+
+ // Mitigations >= Win8:
+ //----------------------------------------------------------------------------
+ if (version >= base::win::Version::WIN8) {
+ if (flags & MITIGATION_RELOCATE_IMAGE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON;
+ if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS;
+ }
+ }
+
+ if (flags & MITIGATION_HEAP_TERMINATE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_BOTTOM_UP_ASLR) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_HIGH_ENTROPY_ASLR) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_STRICT_HANDLE_CHECKS) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_WIN32K_DISABLE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_EXTENSION_POINT_DISABLE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON;
+ }
+ }
+
+ // Mitigations >= Win8.1:
+ //----------------------------------------------------------------------------
+ if (version >= base::win::Version::WIN8_1) {
+ if (flags & MITIGATION_DYNAMIC_CODE_DISABLE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_CONTROL_FLOW_GUARD_DISABLE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF;
+ }
+ }
+
+ // Mitigations >= Win10:
+ //----------------------------------------------------------------------------
+ if (version >= base::win::Version::WIN10) {
+ if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON;
+ }
+ }
+
+ // Mitigations >= Win10 TH2:
+ //----------------------------------------------------------------------------
+ if (version >= base::win::Version::WIN10_TH2) {
+ if (flags & MITIGATION_FORCE_MS_SIGNED_BINS) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_IMAGE_LOAD_NO_REMOTE) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON;
+ }
+
+ if (flags & MITIGATION_IMAGE_LOAD_NO_LOW_LABEL) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON;
+ }
+ }
+
+ // Mitigations >= Win10 RS1 ("Anniversary"):
+ //----------------------------------------------------------------------------
+ if (version >= base::win::Version::WIN10_RS1) {
+ if (flags & MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON_ALLOW_OPT_OUT;
+ }
+
+ if (flags & MITIGATION_IMAGE_LOAD_PREFER_SYS32) {
+ *policy_value_1 |=
+ PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON;
+ }
+ }
+
+ // Mitigations >= Win10 RS3 ("Fall Creator's"):
+ //----------------------------------------------------------------------------
+ if (version >= base::win::Version::WIN10_RS3) {
+ // Note: This mitigation requires not only Win10 1709, but also the January
+ // 2018 security updates and any applicable firmware updates from the
+ // OEM device manufacturer.
+ // Note: Applying this mitigation attribute on creation will succeed, even
+ // if
+ // the underlying hardware does not support the implementation.
+ // Windows just does its best under the hood for the given hardware.
+ if (flags & MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION) {
+ *policy_value_2 |=
+ PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON;
+ }
+ }
+
+ // Mitigations >= Win10 20H1
+ //----------------------------------------------------------------------------
+ if (version >= base::win::Version::WIN10_20H1) {
+ if (flags & MITIGATION_CET_COMPAT_MODE && IsUserCetWin32Available()) {
+ *policy_value_2 |=
+ PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_ALWAYS_ON;
+ }
+ }
+
+ // When done setting policy flags, sanity check supported policies on this
+ // machine, and then update |size|.
+
+ const ULONG64* supported = GetSupportedMitigations();
+
+ *policy_value_1 = *policy_value_1 & supported[0];
+ *policy_value_2 = *policy_value_2 & supported[1];
+
+ // Only include the second element in |size| if it is non-zero. Else,
+ // UpdateProcThreadAttribute() will return a failure when setting policies.
+ if (*policy_value_2 && version >= base::win::Version::WIN10_RS2) {
+ *size = sizeof(*policy_flags) * 2;
+ }
+
+ return;
+}
+
+MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) {
+ base::win::Version version = base::win::GetVersion();
+
+ // Windows 7.
+ if (version < base::win::Version::WIN8) {
+ return flags & (MITIGATION_BOTTOM_UP_ASLR | MITIGATION_DLL_SEARCH_ORDER |
+ MITIGATION_HEAP_TERMINATE);
+ }
+
+ // Windows 8 and above.
+ return flags & (MITIGATION_BOTTOM_UP_ASLR | MITIGATION_DLL_SEARCH_ORDER);
+}
+
+bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
+ MitigationFlags flags) {
+// This is a hack to fake a weak bottom-up ASLR on 32-bit Windows.
+#if !defined(_WIN64)
+ if (flags & MITIGATION_BOTTOM_UP_ASLR) {
+ unsigned int limit;
+ GetRandom(&limit);
+ char* ptr = 0;
+ const size_t kMask64k = 0xFFFF;
+ // Random range (512k-16.5mb) in 64k steps.
+ const char* end = ptr + ((((limit % 16384) + 512) * 1024) & ~kMask64k);
+ while (ptr < end) {
+ MEMORY_BASIC_INFORMATION memory_info;
+ if (!::VirtualQueryEx(process, ptr, &memory_info, sizeof(memory_info)))
+ break;
+ size_t size = std::min((memory_info.RegionSize + kMask64k) & ~kMask64k,
+ static_cast<SIZE_T>(end - ptr));
+ if (ptr && memory_info.State == MEM_FREE)
+ ::VirtualAllocEx(process, ptr, size, MEM_RESERVE, PAGE_NOACCESS);
+ ptr += size;
+ }
+ }
+#endif
+
+ return true;
+}
+
+MitigationFlags GetAllowedPostStartupProcessMitigations() {
+ return MITIGATION_HEAP_TERMINATE |
+ MITIGATION_DEP |
+ MITIGATION_DEP_NO_ATL_THUNK |
+ MITIGATION_RELOCATE_IMAGE |
+ MITIGATION_RELOCATE_IMAGE_REQUIRED |
+ MITIGATION_BOTTOM_UP_ASLR |
+ MITIGATION_STRICT_HANDLE_CHECKS |
+ MITIGATION_EXTENSION_POINT_DISABLE |
+ MITIGATION_DLL_SEARCH_ORDER |
+ MITIGATION_HARDEN_TOKEN_IL_POLICY |
+ MITIGATION_WIN32K_DISABLE |
+ MITIGATION_DYNAMIC_CODE_DISABLE |
+ MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT |
+ MITIGATION_FORCE_MS_SIGNED_BINS |
+ MITIGATION_NONSYSTEM_FONT_DISABLE |
+ MITIGATION_IMAGE_LOAD_NO_REMOTE |
+ MITIGATION_IMAGE_LOAD_NO_LOW_LABEL |
+ MITIGATION_IMAGE_LOAD_PREFER_SYS32;
+}
+
+bool CanSetProcessMitigationsPostStartup(MitigationFlags flags) {
+ // All of these mitigations can be enabled after startup.
+ return !(flags & ~GetAllowedPostStartupProcessMitigations());
+}
+
+bool CanSetProcessMitigationsPreStartup(MitigationFlags flags) {
+ // These mitigations cannot be enabled prior to startup.
+ return !(flags &
+ (MITIGATION_STRICT_HANDLE_CHECKS | MITIGATION_DLL_SEARCH_ORDER));
+}
+
+bool CanSetMitigationsPerThread(MitigationFlags flags) {
+ // If any flags EXCEPT these are set, fail.
+ if (flags & ~(MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD))
+ return false;
+
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations.h b/security/sandbox/chromium/sandbox/win/src/process_mitigations.h
new file mode 100644
index 0000000000..26dc42e358
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_
+#define SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_
+
+#include <windows.h>
+
+#include <stddef.h>
+
+#include "sandbox/win/src/security_level.h"
+
+namespace sandbox {
+
+// Sets the mitigation policy for the current process, ignoring any settings
+// that are invalid for the current version of Windows.
+bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags flags);
+
+// Sets the mitigation policy for the current thread, ignoring any settings
+// that are invalid for the current version of Windows.
+bool ApplyMitigationsToCurrentThread(MitigationFlags flags);
+
+// Returns the flags that must be enforced after startup for the current OS
+// version.
+MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags);
+
+// Converts sandbox flags to the PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES
+// policy flags used by UpdateProcThreadAttribute().
+// - |policy_flags| must be a two-element DWORD64 array.
+// - |size| is a size_t so that it can be passed directly into
+// UpdateProcThreadAttribute().
+void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
+ DWORD64* policy_flags,
+ size_t* size);
+
+// Adds mitigations that need to be performed on the suspended target process
+// before execution begins.
+bool ApplyProcessMitigationsToSuspendedProcess(HANDLE process,
+ MitigationFlags flags);
+
+// Returns the list of process mitigations which can be enabled post startup.
+MitigationFlags GetAllowedPostStartupProcessMitigations();
+
+// Returns true if all the supplied flags can be set after a process starts.
+bool CanSetProcessMitigationsPostStartup(MitigationFlags flags);
+
+// Returns true if all the supplied flags can be set before a process starts.
+bool CanSetProcessMitigationsPreStartup(MitigationFlags flags);
+
+// Returns true if all the supplied flags can be set on the current thread.
+bool CanSetMitigationsPerThread(MitigationFlags flags);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_WIN_PROCESS_MITIGATIONS_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.cc
new file mode 100644
index 0000000000..4d2d94b865
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.cc
@@ -0,0 +1,592 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/unsafe_shared_memory_region.h"
+#include "base/unguessable_token.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+
+namespace sandbox {
+
+namespace {
+
+base::UnsafeSharedMemoryRegion GetSharedMemoryRegion(
+ const ClientInfo& client_info,
+ HANDLE handle,
+ size_t size) {
+ HANDLE dup_handle = nullptr;
+ intptr_t handle_int = reinterpret_cast<intptr_t>(handle);
+ if (handle_int <= 0 ||
+ !::DuplicateHandle(client_info.process, handle, ::GetCurrentProcess(),
+ &dup_handle, 0, false, DUPLICATE_SAME_ACCESS)) {
+ return {};
+ }
+ // The raw handle returned from ::DuplicateHandle() must be wrapped in a
+ // base::PlatformSharedMemoryRegion.
+ base::subtle::PlatformSharedMemoryRegion platform_region =
+ base::subtle::PlatformSharedMemoryRegion::Take(
+ base::win::ScopedHandle(dup_handle),
+ base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe, size,
+ base::UnguessableToken::Create());
+ // |platform_region| can now be wrapped in a base::UnsafeSharedMemoryRegion.
+ return base::UnsafeSharedMemoryRegion::Deserialize(
+ std::move(platform_region));
+}
+
+} // namespace
+
+ProtectedVideoOutput::~ProtectedVideoOutput() {
+ ProcessMitigationsWin32KLockdownPolicy::DestroyOPMProtectedOutputAction(
+ handle_);
+}
+
+scoped_refptr<ProtectedVideoOutput>
+ProcessMitigationsWin32KDispatcher::GetProtectedVideoOutput(
+ HANDLE handle,
+ bool destroy_output) {
+ base::AutoLock lock(protected_outputs_lock_);
+ scoped_refptr<ProtectedVideoOutput> result;
+ auto it = protected_outputs_.find(handle);
+ if (it != protected_outputs_.end()) {
+ result = it->second;
+ if (destroy_output)
+ protected_outputs_.erase(it);
+ }
+ return result;
+}
+
+ProcessMitigationsWin32KDispatcher::ProcessMitigationsWin32KDispatcher(
+ PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall enum_display_monitors_params = {
+ {IpcTag::USER_ENUMDISPLAYMONITORS, {INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::EnumDisplayMonitors)};
+ static const IPCCall get_monitor_info_params = {
+ {IpcTag::USER_GETMONITORINFO, {VOIDPTR_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::GetMonitorInfo)};
+ static const IPCCall get_suggested_output_size_params = {
+ {IpcTag::GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE, {WCHAR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::
+ GetSuggestedOPMProtectedOutputArraySize)};
+ static const IPCCall create_protected_outputs_params = {
+ {IpcTag::GDI_CREATEOPMPROTECTEDOUTPUTS, {WCHAR_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::CreateOPMProtectedOutputs)};
+ static const IPCCall get_cert_size_params = {
+ {IpcTag::GDI_GETCERTIFICATESIZE, {WCHAR_TYPE, VOIDPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::GetCertificateSize)};
+ static const IPCCall get_cert_params = {
+ {IpcTag::GDI_GETCERTIFICATE,
+ {WCHAR_TYPE, VOIDPTR_TYPE, VOIDPTR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::GetCertificate)};
+ static const IPCCall destroy_protected_output_params = {
+ {IpcTag::GDI_DESTROYOPMPROTECTEDOUTPUT, {VOIDPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::DestroyOPMProtectedOutput)};
+ static const IPCCall get_random_number_params = {
+ {IpcTag::GDI_GETOPMRANDOMNUMBER, {VOIDPTR_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::GetOPMRandomNumber)};
+ static const IPCCall set_signing_key_params = {
+ {IpcTag::GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS,
+ {VOIDPTR_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::
+ SetOPMSigningKeyAndSequenceNumbers)};
+ static const IPCCall configure_protected_output_params = {
+ {IpcTag::GDI_CONFIGUREOPMPROTECTEDOUTPUT, {VOIDPTR_TYPE, VOIDPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::ConfigureOPMProtectedOutput)};
+ static const IPCCall get_information_params = {
+ {IpcTag::GDI_GETOPMINFORMATION, {VOIDPTR_TYPE, VOIDPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ProcessMitigationsWin32KDispatcher::GetOPMInformation)};
+
+ ipc_calls_.push_back(enum_display_monitors_params);
+ ipc_calls_.push_back(get_monitor_info_params);
+ ipc_calls_.push_back(get_suggested_output_size_params);
+ ipc_calls_.push_back(create_protected_outputs_params);
+ ipc_calls_.push_back(get_cert_size_params);
+ ipc_calls_.push_back(get_cert_params);
+ ipc_calls_.push_back(destroy_protected_output_params);
+ ipc_calls_.push_back(get_random_number_params);
+ ipc_calls_.push_back(set_signing_key_params);
+ ipc_calls_.push_back(configure_protected_output_params);
+ ipc_calls_.push_back(get_information_params);
+}
+
+ProcessMitigationsWin32KDispatcher::~ProcessMitigationsWin32KDispatcher() {}
+
+bool ProcessMitigationsWin32KDispatcher::SetupService(
+ InterceptionManager* manager,
+ IpcTag service) {
+ if (!(policy_base_->GetProcessMitigations() &
+ sandbox::MITIGATION_WIN32K_DISABLE)) {
+ return false;
+ }
+
+ switch (service) {
+ case IpcTag::GDI_GDIDLLINITIALIZE: {
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GdiDllInitialize,
+ GDIINITIALIZE_ID, 12)) {
+ return false;
+ }
+ return true;
+ }
+
+ case IpcTag::GDI_GETSTOCKOBJECT: {
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetStockObject,
+ GETSTOCKOBJECT_ID, 8)) {
+ return false;
+ }
+ return true;
+ }
+
+ case IpcTag::USER_REGISTERCLASSW: {
+ if (!INTERCEPT_EAT(manager, L"user32.dll", RegisterClassW,
+ REGISTERCLASSW_ID, 8)) {
+ return false;
+ }
+ return true;
+ }
+
+ case IpcTag::USER_ENUMDISPLAYMONITORS: {
+ if (!INTERCEPT_EAT(manager, L"user32.dll", EnumDisplayMonitors,
+ ENUMDISPLAYMONITORS_ID, 20)) {
+ return false;
+ }
+ return true;
+ }
+
+ case IpcTag::USER_ENUMDISPLAYDEVICES: {
+ if (!INTERCEPT_EAT(manager, L"user32.dll", EnumDisplayDevicesA,
+ ENUMDISPLAYDEVICESA_ID, 20)) {
+ return false;
+ }
+ return true;
+ }
+
+ case IpcTag::USER_GETMONITORINFO: {
+ if (!INTERCEPT_EAT(manager, L"user32.dll", GetMonitorInfoA,
+ GETMONITORINFOA_ID, 12)) {
+ return false;
+ }
+
+ if (!INTERCEPT_EAT(manager, L"user32.dll", GetMonitorInfoW,
+ GETMONITORINFOW_ID, 12)) {
+ return false;
+ }
+ return true;
+ }
+
+ case IpcTag::GDI_CREATEOPMPROTECTEDOUTPUTS:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", CreateOPMProtectedOutputs,
+ CREATEOPMPROTECTEDOUTPUTS_ID, 24)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_GETCERTIFICATE:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetCertificate,
+ GETCERTIFICATE_ID, 20)) {
+ return false;
+ }
+ if (base::win::GetVersion() < base::win::Version::WIN10_TH2)
+ return true;
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetCertificateByHandle,
+ GETCERTIFICATEBYHANDLE_ID, 20)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_GETCERTIFICATESIZE:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetCertificateSize,
+ GETCERTIFICATESIZE_ID, 16)) {
+ return false;
+ }
+ if (base::win::GetVersion() < base::win::Version::WIN10_TH2)
+ return true;
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetCertificateSizeByHandle,
+ GETCERTIFICATESIZEBYHANDLE_ID, 16)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_DESTROYOPMPROTECTEDOUTPUT:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", DestroyOPMProtectedOutput,
+ DESTROYOPMPROTECTEDOUTPUT_ID, 8)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_CONFIGUREOPMPROTECTEDOUTPUT:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", ConfigureOPMProtectedOutput,
+ CONFIGUREOPMPROTECTEDOUTPUT_ID, 20)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_GETOPMINFORMATION:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetOPMInformation,
+ GETOPMINFORMATION_ID, 16)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_GETOPMRANDOMNUMBER:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll", GetOPMRandomNumber,
+ GETOPMRANDOMNUMBER_ID, 12)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll",
+ GetSuggestedOPMProtectedOutputArraySize,
+ GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE_ID, 12)) {
+ return false;
+ }
+ return true;
+
+ case IpcTag::GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS:
+ if (!INTERCEPT_EAT(manager, L"gdi32.dll",
+ SetOPMSigningKeyAndSequenceNumbers,
+ SETOPMSIGNINGKEYANDSEQUENCENUMBERS_ID, 12)) {
+ return false;
+ }
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool ProcessMitigationsWin32KDispatcher::EnumDisplayMonitors(
+ IPCInfo* ipc,
+ CountedBuffer* buffer) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.win32_result = ERROR_ACCESS_DENIED;
+ return true;
+ }
+
+ if (buffer->Size() != sizeof(EnumMonitorsResult)) {
+ ipc->return_info.win32_result = ERROR_INVALID_PARAMETER;
+ return true;
+ }
+ HMONITOR monitor_list[kMaxEnumMonitors] = {};
+
+ uint32_t monitor_list_count =
+ ProcessMitigationsWin32KLockdownPolicy::EnumDisplayMonitorsAction(
+ *ipc->client_info, monitor_list, kMaxEnumMonitors);
+ DCHECK(monitor_list_count <= kMaxEnumMonitors);
+
+ EnumMonitorsResult* result =
+ static_cast<EnumMonitorsResult*>(buffer->Buffer());
+ for (uint32_t monitor_pos = 0; monitor_pos < monitor_list_count;
+ ++monitor_pos) {
+ result->monitors[monitor_pos] = monitor_list[monitor_pos];
+ }
+ result->monitor_count = monitor_list_count;
+ ipc->return_info.win32_result = 0;
+
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::GetMonitorInfo(IPCInfo* ipc,
+ void* monitor,
+ CountedBuffer* buffer) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.win32_result = ERROR_ACCESS_DENIED;
+ return true;
+ }
+ if (buffer->Size() != sizeof(MONITORINFOEXW)) {
+ ipc->return_info.win32_result = ERROR_INVALID_PARAMETER;
+ return true;
+ }
+ MONITORINFO* monitor_info = static_cast<MONITORINFO*>(buffer->Buffer());
+ // Ensure size is valid and represents what we've been passed.
+ monitor_info->cbSize = buffer->Size();
+ HMONITOR monitor_handle = static_cast<HMONITOR>(monitor);
+ bool success = ProcessMitigationsWin32KLockdownPolicy::GetMonitorInfoAction(
+ *ipc->client_info, monitor_handle, monitor_info);
+ ipc->return_info.win32_result =
+ success ? ERROR_SUCCESS : ERROR_INVALID_PARAMETER;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::
+ GetSuggestedOPMProtectedOutputArraySize(IPCInfo* ipc,
+ std::wstring* device_name) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ NTSTATUS status = ProcessMitigationsWin32KLockdownPolicy::
+ GetSuggestedOPMProtectedOutputArraySizeAction(
+ *ipc->client_info, *device_name,
+ &ipc->return_info.extended[0].unsigned_int);
+ if (!status) {
+ ipc->return_info.extended_count = 1;
+ }
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::CreateOPMProtectedOutputs(
+ IPCInfo* ipc,
+ std::wstring* device_name,
+ CountedBuffer* protected_outputs) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ uint32_t output_array_size = 0;
+ uint32_t input_array_size = protected_outputs->Size() / sizeof(HANDLE);
+ HANDLE* handles = static_cast<HANDLE*>(protected_outputs->Buffer());
+ NTSTATUS status =
+ ProcessMitigationsWin32KLockdownPolicy::CreateOPMProtectedOutputsAction(
+ *ipc->client_info, *device_name, handles, input_array_size,
+ &output_array_size);
+ if (!status && (output_array_size <= input_array_size)) {
+ base::AutoLock lock(protected_outputs_lock_);
+ ipc->return_info.extended_count = 1;
+ ipc->return_info.extended[0].unsigned_int = output_array_size;
+ for (uint32_t handle_pos = 0; handle_pos < output_array_size;
+ handle_pos++) {
+ HANDLE handle = handles[handle_pos];
+ protected_outputs_[handle] = new ProtectedVideoOutput(handle);
+ }
+ }
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::GetCertificateSize(
+ IPCInfo* ipc,
+ std::wstring* device_name,
+ void* protected_output) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (device_name->size() > 0) {
+ status = ProcessMitigationsWin32KLockdownPolicy::GetCertificateSizeAction(
+ *ipc->client_info, *device_name,
+ &ipc->return_info.extended[0].unsigned_int);
+ } else {
+ scoped_refptr<ProtectedVideoOutput> output =
+ GetProtectedVideoOutput(protected_output, false);
+ if (output) {
+ status = ProcessMitigationsWin32KLockdownPolicy::
+ GetCertificateSizeByHandleAction(
+ *ipc->client_info, output.get()->handle(),
+ &ipc->return_info.extended[0].unsigned_int);
+ }
+ }
+ if (!status) {
+ ipc->return_info.extended_count = 1;
+ }
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::GetCertificate(
+ IPCInfo* ipc,
+ std::wstring* device_name,
+ void* protected_output,
+ void* shared_buffer_handle,
+ uint32_t shared_buffer_size) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ // Don't let caller map an arbitrarily large buffer into memory.
+ if (shared_buffer_size > kProtectedVideoOutputSectionSize) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ base::UnsafeSharedMemoryRegion region = GetSharedMemoryRegion(
+ *ipc->client_info, shared_buffer_handle, shared_buffer_size);
+ if (!region.IsValid()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ base::WritableSharedMemoryMapping cert_data = region.Map();
+ if (!cert_data.IsValid()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (device_name->size() > 0) {
+ status = ProcessMitigationsWin32KLockdownPolicy::GetCertificateAction(
+ *ipc->client_info, *device_name,
+ cert_data.GetMemoryAsSpan<BYTE>().data(), shared_buffer_size);
+ } else {
+ scoped_refptr<ProtectedVideoOutput> output =
+ GetProtectedVideoOutput(protected_output, false);
+ if (output) {
+ status =
+ ProcessMitigationsWin32KLockdownPolicy::GetCertificateByHandleAction(
+ *ipc->client_info, output.get()->handle(),
+ cert_data.GetMemoryAsSpan<BYTE>().data(), shared_buffer_size);
+ }
+ }
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::DestroyOPMProtectedOutput(
+ IPCInfo* ipc,
+ void* protected_output) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ scoped_refptr<ProtectedVideoOutput> output =
+ GetProtectedVideoOutput(protected_output, true);
+ NTSTATUS status = STATUS_INVALID_HANDLE;
+ if (output)
+ status = STATUS_SUCCESS;
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::GetOPMRandomNumber(
+ IPCInfo* ipc,
+ void* protected_output,
+ CountedBuffer* random_number) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ scoped_refptr<ProtectedVideoOutput> output =
+ GetProtectedVideoOutput(protected_output, false);
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (!output || random_number->Size() != sizeof(DXGKMDT_OPM_RANDOM_NUMBER)) {
+ status = STATUS_INVALID_PARAMETER;
+ } else {
+ status = ProcessMitigationsWin32KLockdownPolicy::GetOPMRandomNumberAction(
+ *ipc->client_info, output.get()->handle(), random_number->Buffer());
+ }
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::SetOPMSigningKeyAndSequenceNumbers(
+ IPCInfo* ipc,
+ void* protected_output,
+ CountedBuffer* parameters) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ scoped_refptr<ProtectedVideoOutput> output =
+ GetProtectedVideoOutput(protected_output, false);
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ if (!output ||
+ parameters->Size() != sizeof(DXGKMDT_OPM_ENCRYPTED_PARAMETERS)) {
+ status = STATUS_INVALID_PARAMETER;
+ } else {
+ status = ProcessMitigationsWin32KLockdownPolicy::
+ SetOPMSigningKeyAndSequenceNumbersAction(
+ *ipc->client_info, output.get()->handle(), parameters->Buffer());
+ }
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::ConfigureOPMProtectedOutput(
+ IPCInfo* ipc,
+ void* protected_output,
+ void* shared_buffer_handle) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ scoped_refptr<ProtectedVideoOutput> output =
+ GetProtectedVideoOutput(protected_output, false);
+ if (!output) {
+ ipc->return_info.nt_status = STATUS_INVALID_HANDLE;
+ return true;
+ };
+ base::UnsafeSharedMemoryRegion region =
+ GetSharedMemoryRegion(*ipc->client_info, shared_buffer_handle,
+ sizeof(DXGKMDT_OPM_CONFIGURE_PARAMETERS));
+ if (!region.IsValid()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ base::WritableSharedMemoryMapping buffer = region.Map();
+ if (!buffer.IsValid()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ NTSTATUS status =
+ ProcessMitigationsWin32KLockdownPolicy::ConfigureOPMProtectedOutputAction(
+ *ipc->client_info, output.get()->handle(), buffer.memory());
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+bool ProcessMitigationsWin32KDispatcher::GetOPMInformation(
+ IPCInfo* ipc,
+ void* protected_output,
+ void* shared_buffer_handle) {
+ if (!policy_base_->GetEnableOPMRedirection()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ scoped_refptr<ProtectedVideoOutput> output =
+ GetProtectedVideoOutput(protected_output, false);
+ if (!output) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ size_t shared_buffer_size =
+ std::max(sizeof(DXGKMDT_OPM_GET_INFO_PARAMETERS),
+ sizeof(DXGKMDT_OPM_REQUESTED_INFORMATION));
+
+ base::UnsafeSharedMemoryRegion region = GetSharedMemoryRegion(
+ *ipc->client_info, shared_buffer_handle, shared_buffer_size);
+ if (!region.IsValid()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ base::WritableSharedMemoryMapping buffer = region.Map();
+ if (!buffer.IsValid()) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+ DXGKMDT_OPM_REQUESTED_INFORMATION requested_info = {};
+ NTSTATUS status =
+ ProcessMitigationsWin32KLockdownPolicy::GetOPMInformationAction(
+ *ipc->client_info, output.get()->handle(), buffer.memory(),
+ &requested_info);
+ if (!status) {
+ memcpy(buffer.memory(), &requested_info,
+ sizeof(DXGKMDT_OPM_REQUESTED_INFORMATION));
+ }
+ ipc->return_info.nt_status = status;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.h
new file mode 100644
index 0000000000..0714191fcf
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_dispatcher.h
@@ -0,0 +1,89 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
+
+#include <map>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// Class to maintain a reference to a OPM protected output handle.
+class ProtectedVideoOutput
+ : public base::RefCountedThreadSafe<ProtectedVideoOutput> {
+ public:
+ ProtectedVideoOutput(HANDLE handle) : handle_(handle) {}
+ HANDLE handle() { return handle_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<ProtectedVideoOutput>;
+ ~ProtectedVideoOutput();
+
+ HANDLE handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProtectedVideoOutput);
+};
+
+// This class sets up intercepts for the Win32K lockdown policy which is set
+// on Windows 8 and beyond.
+class ProcessMitigationsWin32KDispatcher : public Dispatcher {
+ public:
+ explicit ProcessMitigationsWin32KDispatcher(PolicyBase* policy_base);
+ ~ProcessMitigationsWin32KDispatcher() override;
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ bool EnumDisplayMonitors(IPCInfo* ipc, CountedBuffer* buffer);
+ bool GetMonitorInfo(IPCInfo* ipc, void* monitor, CountedBuffer* buffer);
+ bool GetSuggestedOPMProtectedOutputArraySize(IPCInfo* ipc,
+ std::wstring* device_name);
+ bool CreateOPMProtectedOutputs(IPCInfo* ipc,
+ std::wstring* device_name,
+ CountedBuffer* protected_outputs);
+ bool GetCertificateSize(IPCInfo* ipc,
+ std::wstring* device_name,
+ void* protected_output);
+ bool GetCertificate(IPCInfo* ipc,
+ std::wstring* device_name,
+ void* protected_output,
+ void* shared_buffer_handle,
+ uint32_t shared_buffer_size);
+ bool DestroyOPMProtectedOutput(IPCInfo* ipc, void* protected_output);
+ bool GetOPMRandomNumber(IPCInfo* ipc,
+ void* protected_output,
+ CountedBuffer* random_number);
+ bool SetOPMSigningKeyAndSequenceNumbers(IPCInfo* ipc,
+ void* protected_output,
+ CountedBuffer* parameters);
+ bool ConfigureOPMProtectedOutput(IPCInfo* ipc,
+ void* protected_output,
+ void* shared_buffer_handle);
+ bool GetOPMInformation(IPCInfo* ipc,
+ void* protected_output,
+ void* shared_buffer_handle);
+
+ private:
+ scoped_refptr<ProtectedVideoOutput> GetProtectedVideoOutput(
+ HANDLE handle,
+ bool destroy_output);
+
+ PolicyBase* policy_base_;
+ std::map<HANDLE, scoped_refptr<ProtectedVideoOutput>> protected_outputs_;
+ base::Lock protected_outputs_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMitigationsWin32KDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_DISPATCHER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.cc b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.cc
new file mode 100644
index 0000000000..1a16d85adf
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.cc
@@ -0,0 +1,523 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+
+#include <algorithm>
+
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+namespace {
+
+// Implement a simple shared memory class as we can't use the base one.
+class ScopedSharedMemory {
+ public:
+ ScopedSharedMemory(uint32_t size) : memory_(nullptr) {
+ handle_.Set(::CreateFileMapping(INVALID_HANDLE_VALUE, nullptr,
+ PAGE_READWRITE | SEC_COMMIT, 0, size,
+ nullptr));
+ if (handle_.IsValid()) {
+ memory_ = ::MapViewOfFile(handle_.Get(), FILE_MAP_READ | FILE_MAP_WRITE,
+ 0, 0, size);
+ }
+ }
+ ~ScopedSharedMemory() {
+ if (memory_)
+ ::UnmapViewOfFile(memory_);
+ }
+
+ void* handle() { return handle_.Get(); }
+ void* memory() { return memory_; }
+ bool IsValid() { return handle_.IsValid() && memory_; }
+
+ private:
+ base::win::ScopedHandle handle_;
+ void* memory_;
+};
+
+void UnicodeStringToString(PUNICODE_STRING unicode_string,
+ std::wstring* result) {
+ *result = std::wstring(
+ unicode_string->Buffer,
+ unicode_string->Buffer +
+ (unicode_string->Length / sizeof(unicode_string->Buffer[0])));
+}
+
+bool CallMonitorInfo(HMONITOR monitor, MONITORINFOEXW* monitor_info_ptr) {
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return false;
+
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return false;
+
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ InOutCountedBuffer buffer(monitor_info_ptr, sizeof(*monitor_info_ptr));
+ ResultCode code = CrossCall(ipc, IpcTag::USER_GETMONITORINFO,
+ static_cast<void*>(monitor), buffer, &answer);
+
+ if (code != SBOX_ALL_OK)
+ return false;
+
+ if (answer.win32_result != ERROR_SUCCESS)
+ return false;
+
+ return true;
+}
+
+} // namespace
+
+BOOL WINAPI
+TargetGdiDllInitialize(GdiDllInitializeFunction orig_gdi_dll_initialize,
+ HANDLE dll,
+ DWORD reason) {
+ return true;
+}
+
+HGDIOBJ WINAPI
+TargetGetStockObject(GetStockObjectFunction orig_get_stock_object, int object) {
+ return nullptr;
+}
+
+ATOM WINAPI
+TargetRegisterClassW(RegisterClassWFunction orig_register_class_function,
+ const WNDCLASS* wnd_class) {
+ return true;
+}
+
+BOOL WINAPI TargetEnumDisplayMonitors(EnumDisplayMonitorsFunction,
+ HDC hdc,
+ LPCRECT lprcClip,
+ MONITORENUMPROC lpfnEnum,
+ LPARAM dwData) {
+ if (!lpfnEnum || hdc || lprcClip) {
+ return false;
+ }
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return false;
+
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return false;
+
+ CrossCallReturn answer = {0};
+ answer.nt_status = 0;
+ EnumMonitorsResult result = {};
+ InOutCountedBuffer result_buffer(&result, sizeof(result));
+ SharedMemIPCClient ipc(ipc_memory);
+ ResultCode code =
+ CrossCall(ipc, IpcTag::USER_ENUMDISPLAYMONITORS, result_buffer, &answer);
+
+ if (code != SBOX_ALL_OK)
+ return false;
+
+ if (answer.win32_result)
+ return false;
+
+ if (result.monitor_count > kMaxEnumMonitors)
+ return false;
+
+ for (uint32_t monitor_pos = 0; monitor_pos < result.monitor_count;
+ ++monitor_pos) {
+ bool continue_enum =
+ lpfnEnum(result.monitors[monitor_pos], nullptr, nullptr, dwData);
+ if (!continue_enum)
+ return false;
+ }
+
+ return true;
+}
+
+BOOL WINAPI TargetEnumDisplayDevicesA(EnumDisplayDevicesAFunction,
+ LPCSTR lpDevice,
+ DWORD iDevNum,
+ PDISPLAY_DEVICEA lpDisplayDevice,
+ DWORD dwFlags) {
+ return false;
+}
+
+BOOL WINAPI TargetGetMonitorInfoA(GetMonitorInfoAFunction,
+ HMONITOR monitor,
+ MONITORINFO* monitor_info_ptr) {
+ if (!monitor_info_ptr)
+ return false;
+ DWORD size = monitor_info_ptr->cbSize;
+ if (size != sizeof(MONITORINFO) && size != sizeof(MONITORINFOEXA))
+ return false;
+ MONITORINFOEXW monitor_info_tmp = {};
+ monitor_info_tmp.cbSize = sizeof(monitor_info_tmp);
+ bool success = CallMonitorInfo(monitor, &monitor_info_tmp);
+ if (!success)
+ return false;
+ memcpy(monitor_info_ptr, &monitor_info_tmp, sizeof(*monitor_info_ptr));
+ if (size == sizeof(MONITORINFOEXA)) {
+ MONITORINFOEXA* monitor_info_exa =
+ reinterpret_cast<MONITORINFOEXA*>(monitor_info_ptr);
+ if (!::WideCharToMultiByte(CP_ACP, 0, monitor_info_tmp.szDevice, -1,
+ monitor_info_exa->szDevice,
+ sizeof(monitor_info_exa->szDevice), nullptr,
+ nullptr)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+BOOL WINAPI TargetGetMonitorInfoW(GetMonitorInfoWFunction,
+ HMONITOR monitor,
+ LPMONITORINFO monitor_info_ptr) {
+ if (!monitor_info_ptr)
+ return false;
+ DWORD size = monitor_info_ptr->cbSize;
+ if (size != sizeof(MONITORINFO) && size != sizeof(MONITORINFOEXW))
+ return false;
+ MONITORINFOEXW monitor_info_tmp = {};
+ monitor_info_tmp.cbSize = sizeof(monitor_info_tmp);
+ if (!CallMonitorInfo(monitor, &monitor_info_tmp))
+ return false;
+ memcpy(monitor_info_ptr, &monitor_info_tmp, size);
+ return true;
+}
+
+static NTSTATUS GetCertificateCommon(
+ PUNICODE_STRING device_name,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_size) {
+ // Don't support arbitrarily large certificate buffers.
+ if (certificate_size > kProtectedVideoOutputSectionSize)
+ return STATUS_INVALID_PARAMETER;
+ if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
+ return STATUS_INVALID_PARAMETER;
+ if (device_name && device_name->Length == 0)
+ return STATUS_INVALID_PARAMETER;
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ ScopedSharedMemory buffer(certificate_size);
+ if (!buffer.IsValid())
+ return STATUS_INVALID_PARAMETER;
+ std::wstring device_name_str;
+ void* protected_output_handle = nullptr;
+ if (device_name) {
+ if (device_name->Length == 0)
+ return STATUS_INVALID_PARAMETER;
+ UnicodeStringToString(device_name, &device_name_str);
+ } else {
+ protected_output_handle = protected_output;
+ }
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ ResultCode code =
+ CrossCall(ipc, IpcTag::GDI_GETCERTIFICATE, device_name_str.c_str(),
+ protected_output_handle, buffer.handle(),
+ static_cast<uint32_t>(certificate_size), &answer);
+
+ if (code != SBOX_ALL_OK) {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ if (!answer.nt_status)
+ memcpy(certificate, buffer.memory(), certificate_size);
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI TargetGetCertificate(GetCertificateFunction,
+ PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_size) {
+ return GetCertificateCommon(device_name, nullptr, certificate_type,
+ certificate, certificate_size);
+}
+
+static NTSTATUS GetCertificateSizeCommon(
+ PUNICODE_STRING device_name,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length) {
+ if (certificate_type != DXGKMDT_OPM_CERTIFICATE)
+ return STATUS_INVALID_PARAMETER;
+ if (device_name && device_name->Length == 0)
+ return STATUS_INVALID_PARAMETER;
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ std::wstring device_name_str;
+ void* protected_output_handle = nullptr;
+ if (device_name) {
+ UnicodeStringToString(device_name, &device_name_str);
+ } else {
+ protected_output_handle = protected_output;
+ }
+ ResultCode code =
+ CrossCall(ipc, IpcTag::GDI_GETCERTIFICATESIZE, device_name_str.c_str(),
+ protected_output_handle, &answer);
+
+ if (code != SBOX_ALL_OK) {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ if (!answer.nt_status)
+ *certificate_length = answer.extended[0].unsigned_int;
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI
+TargetGetCertificateSize(GetCertificateSizeFunction,
+ PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length) {
+ return GetCertificateSizeCommon(device_name, nullptr, certificate_type,
+ certificate_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetCertificateByHandle(
+ GetCertificateByHandleFunction orig_get_certificate_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length) {
+ return GetCertificateCommon(nullptr, protected_output, certificate_type,
+ certificate, certificate_length);
+}
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetCertificateSizeByHandle(
+ GetCertificateSizeByHandleFunction orig_get_certificate_size_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length) {
+ return GetCertificateSizeCommon(nullptr, protected_output, certificate_type,
+ certificate_length);
+}
+
+NTSTATUS WINAPI
+TargetDestroyOPMProtectedOutput(DestroyOPMProtectedOutputFunction,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output) {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ ResultCode code = CrossCall(ipc, IpcTag::GDI_DESTROYOPMPROTECTEDOUTPUT,
+ static_cast<void*>(protected_output), &answer);
+
+ if (code != SBOX_ALL_OK)
+ return STATUS_ACCESS_DENIED;
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI TargetConfigureOPMProtectedOutput(
+ ConfigureOPMProtectedOutputFunction,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
+ ULONG additional_parameters_size,
+ const BYTE* additional_parameters) {
+ // Don't support additional parameters.
+ if (additional_parameters_size > 0)
+ return STATUS_INVALID_PARAMETER;
+
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ ScopedSharedMemory buffer(sizeof(*parameters));
+ if (!buffer.IsValid())
+ return STATUS_INVALID_PARAMETER;
+ memcpy(buffer.memory(), parameters, sizeof(*parameters));
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ ResultCode code =
+ CrossCall(ipc, IpcTag::GDI_CONFIGUREOPMPROTECTEDOUTPUT,
+ static_cast<void*>(protected_output), buffer.handle(), &answer);
+
+ if (code != SBOX_ALL_OK) {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI TargetGetOPMInformation(
+ GetOPMInformationFunction,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
+ DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information) {
+ size_t max_size =
+ std::max(sizeof(*parameters), sizeof(*requested_information));
+
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ ScopedSharedMemory buffer(base::checked_cast<uint32_t>(max_size));
+ if (!buffer.IsValid())
+ return STATUS_INVALID_PARAMETER;
+ memcpy(buffer.memory(), parameters, sizeof(*parameters));
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ ResultCode code =
+ CrossCall(ipc, IpcTag::GDI_GETOPMINFORMATION,
+ static_cast<void*>(protected_output), buffer.handle(), &answer);
+
+ if (code != SBOX_ALL_OK)
+ return STATUS_ACCESS_DENIED;
+
+ if (!answer.nt_status) {
+ memcpy(requested_information, buffer.memory(),
+ sizeof(*requested_information));
+ }
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI
+TargetGetOPMRandomNumber(GetOPMRandomNumberFunction,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_OPM_RANDOM_NUMBER* random_number) {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ InOutCountedBuffer buffer(random_number, sizeof(*random_number));
+ ResultCode code =
+ CrossCall(ipc, IpcTag::GDI_GETOPMRANDOMNUMBER,
+ static_cast<void*>(protected_output), buffer, &answer);
+
+ if (code != SBOX_ALL_OK)
+ return STATUS_ACCESS_DENIED;
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI TargetGetSuggestedOPMProtectedOutputArraySize(
+ GetSuggestedOPMProtectedOutputArraySizeFunction,
+ PUNICODE_STRING device_name,
+ DWORD* suggested_output_size) {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ std::wstring device_name_str;
+ UnicodeStringToString(device_name, &device_name_str);
+ ResultCode code =
+ CrossCall(ipc, IpcTag::GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE,
+ device_name_str.c_str(), &answer);
+
+ if (code != SBOX_ALL_OK)
+ return STATUS_ACCESS_DENIED;
+
+ if (!answer.nt_status)
+ *suggested_output_size = answer.extended[0].unsigned_int;
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI TargetSetOPMSigningKeyAndSequenceNumbers(
+ SetOPMSigningKeyAndSequenceNumbersFunction,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters) {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ DXGKMDT_OPM_ENCRYPTED_PARAMETERS temp_parameters = *parameters;
+
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ InOutCountedBuffer buffer(&temp_parameters, sizeof(temp_parameters));
+ ResultCode code =
+ CrossCall(ipc, IpcTag::GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS,
+ static_cast<void*>(protected_output), buffer, &answer);
+
+ if (code != SBOX_ALL_OK)
+ return STATUS_ACCESS_DENIED;
+
+ return answer.nt_status;
+}
+
+NTSTATUS WINAPI
+TargetCreateOPMProtectedOutputs(CreateOPMProtectedOutputsFunction,
+ PUNICODE_STRING device_name,
+ DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
+ DWORD outputs_array_size,
+ DWORD* output_size,
+ OPM_PROTECTED_OUTPUT_HANDLE* outputs_array) {
+ if (vos != DXGKMDT_OPM_VOS_OPM_SEMANTICS)
+ return STATUS_INVALID_PARAMETER;
+
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return STATUS_ACCESS_DENIED;
+ void* ipc_memory = GetGlobalIPCMemory();
+ if (!ipc_memory)
+ return STATUS_ACCESS_DENIED;
+
+ CrossCallReturn answer = {};
+ SharedMemIPCClient ipc(ipc_memory);
+ base::CheckedNumeric<uint32_t> array_size = outputs_array_size;
+ array_size *= sizeof(HANDLE);
+ if (!array_size.IsValid())
+ return STATUS_INVALID_PARAMETER;
+
+ InOutCountedBuffer buffer(outputs_array, array_size.ValueOrDie());
+ std::wstring device_name_str;
+ UnicodeStringToString(device_name, &device_name_str);
+ ResultCode code = CrossCall(ipc, IpcTag::GDI_CREATEOPMPROTECTEDOUTPUTS,
+ device_name_str.c_str(), buffer, &answer);
+
+ if (code != SBOX_ALL_OK)
+ return STATUS_ACCESS_DENIED;
+
+ if (!answer.nt_status)
+ *output_size = answer.extended[0].unsigned_int;
+
+ return answer.nt_status;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.h b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.h
new file mode 100644
index 0000000000..befcda2767
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_interception.h
@@ -0,0 +1,151 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
+
+#include <windows.h>
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+const DWORD kProtectedVideoOutputSectionSize = 16 * 1024;
+const DWORD kMaxEnumMonitors = 32;
+
+struct EnumMonitorsResult {
+ DWORD monitor_count;
+ HMONITOR monitors[kMaxEnumMonitors];
+};
+
+typedef BOOL(WINAPI* GdiDllInitializeFunction)(HANDLE dll,
+ DWORD reason,
+ LPVOID reserved);
+
+using GetStockObjectFunction = decltype(&::GetStockObject);
+
+using RegisterClassWFunction = decltype(&::RegisterClassW);
+
+using EnumDisplayMonitorsFunction = decltype(&::EnumDisplayMonitors);
+
+using EnumDisplayDevicesAFunction = decltype(&::EnumDisplayDevicesA);
+
+using GetMonitorInfoWFunction = decltype(&::GetMonitorInfoW);
+using GetMonitorInfoAFunction = decltype(&::GetMonitorInfoA);
+
+extern "C" {
+
+// Interceptor for the GdiDllInitialize function.
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetGdiDllInitialize(GdiDllInitializeFunction orig_gdi_dll_initialize,
+ HANDLE dll,
+ DWORD reason);
+
+// Interceptor for the GetStockObject function.
+SANDBOX_INTERCEPT HGDIOBJ WINAPI
+TargetGetStockObject(GetStockObjectFunction orig_get_stock_object, int object);
+
+// Interceptor for the RegisterClassW function.
+SANDBOX_INTERCEPT ATOM WINAPI
+TargetRegisterClassW(RegisterClassWFunction orig_register_class_function,
+ const WNDCLASS* wnd_class);
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetEnumDisplayMonitors(
+ EnumDisplayMonitorsFunction orig_enum_display_monitors_function,
+ HDC hdc,
+ LPCRECT clip_rect,
+ MONITORENUMPROC enum_function,
+ LPARAM data);
+
+SANDBOX_INTERCEPT BOOL WINAPI TargetEnumDisplayDevicesA(
+ EnumDisplayDevicesAFunction orig_enum_display_devices_function,
+ LPCSTR device,
+ DWORD device_number,
+ PDISPLAY_DEVICEA display_device,
+ DWORD flags);
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetGetMonitorInfoA(GetMonitorInfoAFunction orig_get_monitor_info_function,
+ HMONITOR monitor,
+ LPMONITORINFO monitor_info);
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetGetMonitorInfoW(GetMonitorInfoWFunction orig_get_monitor_info_function,
+ HMONITOR monitor,
+ LPMONITORINFO monitor_info);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetCreateOPMProtectedOutputs(
+ CreateOPMProtectedOutputsFunction orig_create_proceted_outputs_function,
+ PUNICODE_STRING device_name,
+ DXGKMDT_OPM_VIDEO_OUTPUT_SEMANTICS vos,
+ DWORD protected_output_array_size,
+ DWORD* output_array_size,
+ OPM_PROTECTED_OUTPUT_HANDLE* protected_outputs);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetGetCertificate(GetCertificateFunction orig_get_certificate_function,
+ PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetCertificateSize(
+ GetCertificateSizeFunction orig_get_certificate_size_function,
+ PUNICODE_STRING device_name,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetCertificateByHandle(
+ GetCertificateByHandleFunction orig_get_certificate_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ BYTE* certificate,
+ ULONG certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetCertificateSizeByHandle(
+ GetCertificateSizeByHandleFunction orig_get_certificate_size_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_CERTIFICATE_TYPE certificate_type,
+ ULONG* certificate_length);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetDestroyOPMProtectedOutput(
+ DestroyOPMProtectedOutputFunction orig_destroy_protected_output_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetConfigureOPMProtectedOutput(
+ ConfigureOPMProtectedOutputFunction
+ origin_configure_protected_output_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_CONFIGURE_PARAMETERS* parameters,
+ ULONG additional_parameters_size,
+ const BYTE* additional_parameters);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetOPMInformation(
+ GetOPMInformationFunction origin_get_information_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_GET_INFO_PARAMETERS* parameters,
+ DXGKMDT_OPM_REQUESTED_INFORMATION* requested_information);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetOPMRandomNumber(
+ GetOPMRandomNumberFunction orig_get_random_number_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ DXGKMDT_OPM_RANDOM_NUMBER* random_number);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetGetSuggestedOPMProtectedOutputArraySize(
+ GetSuggestedOPMProtectedOutputArraySizeFunction
+ orig_get_suggested_size_function,
+ PUNICODE_STRING device_name,
+ DWORD* suggested_output_array_size);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetSetOPMSigningKeyAndSequenceNumbers(
+ SetOPMSigningKeyAndSequenceNumbersFunction orig_set_signing_keys_function,
+ OPM_PROTECTED_OUTPUT_HANDLE protected_output,
+ const DXGKMDT_OPM_ENCRYPTED_PARAMETERS* parameters);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.cc b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.cc
new file mode 100644
index 0000000000..8ab915ec33
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.cc
@@ -0,0 +1,410 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+
+#include <stddef.h>
+
+#include "sandbox/win/src/process_mitigations_win32k_interception.h"
+
+namespace sandbox {
+
+namespace {
+
+// Define GUIDs for OPM APIs
+const GUID DXGKMDT_OPM_GET_CONNECTOR_TYPE = {
+ 0x81d0bfd5,
+ 0x6afe,
+ 0x48c2,
+ {0x99, 0xc0, 0x95, 0xa0, 0x8f, 0x97, 0xc5, 0xda}};
+const GUID DXGKMDT_OPM_GET_SUPPORTED_PROTECTION_TYPES = {
+ 0x38f2a801,
+ 0x9a6c,
+ 0x48bb,
+ {0x91, 0x07, 0xb6, 0x69, 0x6e, 0x6f, 0x17, 0x97}};
+const GUID DXGKMDT_OPM_GET_VIRTUAL_PROTECTION_LEVEL = {
+ 0xb2075857,
+ 0x3eda,
+ 0x4d5d,
+ {0x88, 0xdb, 0x74, 0x8f, 0x8c, 0x1a, 0x05, 0x49}};
+const GUID DXGKMDT_OPM_GET_ACTUAL_PROTECTION_LEVEL = {
+ 0x1957210a,
+ 0x7766,
+ 0x452a,
+ {0xb9, 0x9a, 0xd2, 0x7a, 0xed, 0x54, 0xf0, 0x3a}};
+const GUID DXGKMDT_OPM_SET_PROTECTION_LEVEL = {
+ 0x9bb9327c,
+ 0x4eb5,
+ 0x4727,
+ {0x9f, 0x00, 0xb4, 0x2b, 0x09, 0x19, 0xc0, 0xda}};
+
+void StringToUnicodeString(PUNICODE_STRING unicode_string,
+ const std::wstring& device_name) {
+ static RtlInitUnicodeStringFunction RtlInitUnicodeString;
+ if (!RtlInitUnicodeString) {
+ HMODULE ntdll = ::GetModuleHandle(kNtdllName);
+ RtlInitUnicodeString = reinterpret_cast<RtlInitUnicodeStringFunction>(
+ GetProcAddress(ntdll, "RtlInitUnicodeString"));
+ }
+ RtlInitUnicodeString(unicode_string, device_name.c_str());
+}
+
+struct MonitorListState {
+ HMONITOR* monitor_list;
+ uint32_t monitor_list_size;
+ uint32_t monitor_list_pos;
+};
+
+BOOL CALLBACK DisplayMonitorEnumProc(HMONITOR monitor,
+ HDC hdc_monitor,
+ LPRECT rect_monitor,
+ LPARAM data) {
+ MonitorListState* state = reinterpret_cast<MonitorListState*>(data);
+ if (state->monitor_list_pos >= state->monitor_list_size)
+ return false;
+ state->monitor_list[state->monitor_list_pos++] = monitor;
+ return true;
+}
+
+template <typename T>
+T GetExportedFunc(const wchar_t* libname, const char* name) {
+ OverrideForTestFunction test_override =
+ ProcessMitigationsWin32KLockdownPolicy::GetOverrideForTestCallback();
+ if (test_override)
+ return reinterpret_cast<T>(test_override(name));
+
+ static T func = nullptr;
+ if (!func) {
+ func =
+ reinterpret_cast<T>(::GetProcAddress(::GetModuleHandle(libname), name));
+ DCHECK(!!func);
+ }
+ return func;
+}
+
+#define GDIFUNC(name) GetExportedFunc<name##Function>(L"gdi32.dll", #name)
+#define USERFUNC(name) GetExportedFunc<name##Function>(L"user32.dll", #name)
+
+struct ValidateMonitorParams {
+ HMONITOR monitor;
+ std::wstring device_name;
+ bool result;
+};
+
+bool GetMonitorDeviceName(HMONITOR monitor, std::wstring* device_name) {
+ MONITORINFOEXW monitor_info = {};
+ monitor_info.cbSize = sizeof(monitor_info);
+ if (!USERFUNC(GetMonitorInfoW)(monitor, &monitor_info))
+ return false;
+ if (monitor_info.szDevice[CCHDEVICENAME - 1] != 0)
+ return false;
+ *device_name = monitor_info.szDevice;
+ return true;
+}
+
+BOOL CALLBACK ValidateMonitorEnumProc(HMONITOR monitor,
+ HDC,
+ LPRECT,
+ LPARAM data) {
+ ValidateMonitorParams* valid_params =
+ reinterpret_cast<ValidateMonitorParams*>(data);
+ std::wstring device_name;
+ bool result = false;
+ if (valid_params->device_name.empty()) {
+ result = monitor == valid_params->monitor;
+ } else if (GetMonitorDeviceName(monitor, &device_name)) {
+ result = device_name == valid_params->device_name;
+ }
+ valid_params->result = result;
+ if (!result)
+ return true;
+ return false;
+}
+
+bool IsValidMonitorOrDeviceName(HMONITOR monitor, const wchar_t* device_name) {
+ ValidateMonitorParams params = {};
+ params.monitor = monitor;
+ if (device_name)
+ params.device_name = device_name;
+ USERFUNC(EnumDisplayMonitors)
+ (nullptr, nullptr, ValidateMonitorEnumProc,
+ reinterpret_cast<LPARAM>(&params));
+ return params.result;
+}
+
+} // namespace
+
+OverrideForTestFunction
+ ProcessMitigationsWin32KLockdownPolicy::override_callback_;
+
+bool ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+ const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ PolicyRule rule(FAKE_SUCCESS);
+ if (!policy->AddRule(IpcTag::GDI_GDIDLLINITIALIZE, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_GETSTOCKOBJECT, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::USER_REGISTERCLASSW, &rule))
+ return false;
+ if (semantics != TargetPolicy::IMPLEMENT_OPM_APIS)
+ return true;
+ if (!policy->AddRule(IpcTag::USER_ENUMDISPLAYMONITORS, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::USER_ENUMDISPLAYDEVICES, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::USER_GETMONITORINFO, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_CREATEOPMPROTECTEDOUTPUTS, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_GETCERTIFICATE, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_GETCERTIFICATESIZE, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_DESTROYOPMPROTECTEDOUTPUT, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_CONFIGUREOPMPROTECTEDOUTPUT, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_GETOPMINFORMATION, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_GETOPMRANDOMNUMBER, &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE,
+ &rule))
+ return false;
+ if (!policy->AddRule(IpcTag::GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS, &rule))
+ return false;
+ return true;
+}
+
+uint32_t ProcessMitigationsWin32KLockdownPolicy::EnumDisplayMonitorsAction(
+ const ClientInfo& client_info,
+ HMONITOR* monitor_list,
+ uint32_t monitor_list_size) {
+ MonitorListState state = {monitor_list, monitor_list_size, 0};
+ USERFUNC(EnumDisplayMonitors)
+ (nullptr, nullptr, DisplayMonitorEnumProc, reinterpret_cast<LPARAM>(&state));
+ return state.monitor_list_pos;
+}
+
+bool ProcessMitigationsWin32KLockdownPolicy::GetMonitorInfoAction(
+ const ClientInfo& client_info,
+ HMONITOR monitor,
+ MONITORINFO* monitor_info_ptr) {
+ if (!IsValidMonitorOrDeviceName(monitor, nullptr))
+ return false;
+ MONITORINFOEXW monitor_info = {};
+ monitor_info.cbSize = sizeof(MONITORINFOEXW);
+
+ bool success = USERFUNC(GetMonitorInfoW)(
+ monitor, reinterpret_cast<MONITORINFO*>(&monitor_info));
+ if (success)
+ memcpy(monitor_info_ptr, &monitor_info, sizeof(monitor_info));
+ return success;
+}
+
+NTSTATUS ProcessMitigationsWin32KLockdownPolicy::
+ GetSuggestedOPMProtectedOutputArraySizeAction(
+ const ClientInfo& client_info,
+ const std::wstring& device_name,
+ uint32_t* suggested_array_size) {
+ if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
+ return STATUS_ACCESS_DENIED;
+ }
+ UNICODE_STRING unicode_device_name;
+ StringToUnicodeString(&unicode_device_name, device_name);
+ DWORD suggested_array_size_dword = 0;
+ NTSTATUS status = GDIFUNC(GetSuggestedOPMProtectedOutputArraySize)(
+ &unicode_device_name, &suggested_array_size_dword);
+ if (!status)
+ *suggested_array_size = suggested_array_size_dword;
+ return status;
+}
+
+NTSTATUS
+ProcessMitigationsWin32KLockdownPolicy::CreateOPMProtectedOutputsAction(
+ const ClientInfo& client_info,
+ const std::wstring& device_name,
+ HANDLE* protected_outputs,
+ uint32_t array_input_size,
+ uint32_t* array_output_size) {
+ if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
+ return STATUS_ACCESS_DENIED;
+ }
+
+ UNICODE_STRING unicode_device_name;
+ StringToUnicodeString(&unicode_device_name, device_name);
+ DWORD output_size = 0;
+
+ NTSTATUS status = GDIFUNC(CreateOPMProtectedOutputs)(
+ &unicode_device_name, DXGKMDT_OPM_VOS_OPM_SEMANTICS, array_input_size,
+ &output_size,
+ reinterpret_cast<OPM_PROTECTED_OUTPUT_HANDLE*>(protected_outputs));
+ if (!status)
+ *array_output_size = output_size;
+ return status;
+}
+
+NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateSizeAction(
+ const ClientInfo& client_info,
+ const std::wstring& device_name,
+ uint32_t* cert_size) {
+ if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
+ return STATUS_ACCESS_DENIED;
+ }
+ UNICODE_STRING unicode_device_name;
+ StringToUnicodeString(&unicode_device_name, device_name);
+
+ return GDIFUNC(GetCertificateSize)(&unicode_device_name,
+ DXGKMDT_OPM_CERTIFICATE,
+ reinterpret_cast<DWORD*>(cert_size));
+}
+
+NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateAction(
+ const ClientInfo& client_info,
+ const std::wstring& device_name,
+ BYTE* cert_data,
+ uint32_t cert_size) {
+ if (!IsValidMonitorOrDeviceName(nullptr, device_name.c_str())) {
+ return STATUS_ACCESS_DENIED;
+ }
+ UNICODE_STRING unicode_device_name;
+ StringToUnicodeString(&unicode_device_name, device_name);
+
+ return GDIFUNC(GetCertificate)(&unicode_device_name, DXGKMDT_OPM_CERTIFICATE,
+ cert_data, cert_size);
+}
+
+NTSTATUS
+ProcessMitigationsWin32KLockdownPolicy::GetCertificateSizeByHandleAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ uint32_t* cert_size) {
+ auto get_certificate_size_func = GDIFUNC(GetCertificateSizeByHandle);
+ if (get_certificate_size_func) {
+ return get_certificate_size_func(protected_output, DXGKMDT_OPM_CERTIFICATE,
+ reinterpret_cast<DWORD*>(cert_size));
+ }
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetCertificateByHandleAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ BYTE* cert_data,
+ uint32_t cert_size) {
+ auto get_certificate_func = GDIFUNC(GetCertificateByHandle);
+ if (get_certificate_func) {
+ return get_certificate_func(protected_output, DXGKMDT_OPM_CERTIFICATE,
+ cert_data, cert_size);
+ }
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetOPMRandomNumberAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* random_number) {
+ return GDIFUNC(GetOPMRandomNumber)(
+ protected_output, static_cast<DXGKMDT_OPM_RANDOM_NUMBER*>(random_number));
+}
+
+NTSTATUS ProcessMitigationsWin32KLockdownPolicy::
+ SetOPMSigningKeyAndSequenceNumbersAction(const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* parameters) {
+ return GDIFUNC(SetOPMSigningKeyAndSequenceNumbers)(
+ protected_output,
+ static_cast<DXGKMDT_OPM_ENCRYPTED_PARAMETERS*>(parameters));
+}
+
+NTSTATUS
+ProcessMitigationsWin32KLockdownPolicy::ConfigureOPMProtectedOutputAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* parameters_ptr) {
+ DXGKMDT_OPM_CONFIGURE_PARAMETERS parameters;
+ memcpy(&parameters, parameters_ptr, sizeof(parameters));
+ if (parameters.guidSetting != DXGKMDT_OPM_SET_PROTECTION_LEVEL ||
+ parameters.cbParametersSize !=
+ sizeof(DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ DXGKMDT_OPM_SET_PROTECTION_LEVEL_PARAMETERS prot_level;
+ memcpy(&prot_level, parameters.abParameters, sizeof(prot_level));
+ if (prot_level.Reserved || prot_level.Reserved2)
+ return STATUS_INVALID_PARAMETER;
+
+ if (prot_level.ulProtectionType != DXGKMDT_OPM_PROTECTION_TYPE_HDCP &&
+ prot_level.ulProtectionType != DXGKMDT_OPM_PROTECTION_TYPE_DPCP) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // Protection levels are same for HDCP and DPCP.
+ if (prot_level.ulProtectionLevel != DXGKMDT_OPM_HDCP_OFF &&
+ prot_level.ulProtectionLevel != DXGKMDT_OPM_HDCP_ON) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ return GDIFUNC(ConfigureOPMProtectedOutput)(protected_output, &parameters, 0,
+ nullptr);
+}
+
+NTSTATUS ProcessMitigationsWin32KLockdownPolicy::GetOPMInformationAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* parameters_ptr,
+ void* requested_info_ptr) {
+ DXGKMDT_OPM_GET_INFO_PARAMETERS parameters;
+ memcpy(&parameters, parameters_ptr, sizeof(parameters));
+
+ bool valid_parameters = false;
+ // Validate sizes based on the type being requested.
+ if ((parameters.guidInformation == DXGKMDT_OPM_GET_CONNECTOR_TYPE ||
+ parameters.guidInformation ==
+ DXGKMDT_OPM_GET_SUPPORTED_PROTECTION_TYPES) &&
+ parameters.cbParametersSize == 0) {
+ valid_parameters = true;
+ } else if ((parameters.guidInformation ==
+ DXGKMDT_OPM_GET_VIRTUAL_PROTECTION_LEVEL ||
+ parameters.guidInformation ==
+ DXGKMDT_OPM_GET_ACTUAL_PROTECTION_LEVEL) &&
+ parameters.cbParametersSize == sizeof(uint32_t)) {
+ uint32_t param_value;
+ memcpy(&param_value, parameters.abParameters, sizeof(param_value));
+ if (param_value == DXGKMDT_OPM_PROTECTION_TYPE_HDCP ||
+ param_value == DXGKMDT_OPM_PROTECTION_TYPE_DPCP) {
+ valid_parameters = true;
+ }
+ }
+ if (!valid_parameters)
+ return STATUS_INVALID_PARAMETER;
+ DXGKMDT_OPM_REQUESTED_INFORMATION requested_info = {};
+ NTSTATUS status = GDIFUNC(GetOPMInformation)(protected_output, &parameters,
+ &requested_info);
+ if (!status)
+ memcpy(requested_info_ptr, &requested_info, sizeof(requested_info));
+
+ return status;
+}
+
+NTSTATUS
+ProcessMitigationsWin32KLockdownPolicy::DestroyOPMProtectedOutputAction(
+ HANDLE protected_output) {
+ return GDIFUNC(DestroyOPMProtectedOutput)(protected_output);
+}
+
+void ProcessMitigationsWin32KLockdownPolicy::SetOverrideForTestCallback(
+ OverrideForTestFunction callback) {
+ override_callback_ = callback;
+}
+
+OverrideForTestFunction
+ProcessMitigationsWin32KLockdownPolicy::GetOverrideForTestCallback() {
+ return override_callback_;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.h b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.h
new file mode 100644
index 0000000000..0c2b2dff95
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations_win32k_policy.h
@@ -0,0 +1,91 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+#define SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
+
+#include <string>
+
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+// A callback function type to get a function for testing.
+typedef void* (*OverrideForTestFunction)(const char* name);
+
+// This class centralizes most of the knowledge related to the process
+// mitigations Win32K lockdown policy.
+class ProcessMitigationsWin32KLockdownPolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level
+ // policy rule for the Win32K process mitigation policy.
+ // name is the object name, semantics is the desired semantics for the
+ // open or create and policy is the policy generator to which the rules are
+ // going to be added.
+ static bool GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ static uint32_t EnumDisplayMonitorsAction(const ClientInfo& client_info,
+ HMONITOR* monitor_list,
+ uint32_t monitor_list_size);
+ static bool GetMonitorInfoAction(const ClientInfo& client_info,
+ HMONITOR monitor,
+ MONITORINFO* monitor_info);
+
+ static NTSTATUS GetSuggestedOPMProtectedOutputArraySizeAction(
+ const ClientInfo& client_info,
+ const std::wstring& device_name,
+ uint32_t* suggested_array_size);
+
+ static NTSTATUS CreateOPMProtectedOutputsAction(
+ const ClientInfo& client_info,
+ const std::wstring& device_name,
+ HANDLE* protected_outputs,
+ uint32_t array_input_size,
+ uint32_t* array_output_size);
+
+ static NTSTATUS GetCertificateSizeAction(const ClientInfo& client_info,
+ const std::wstring& device_name,
+ uint32_t* cert_size);
+ static NTSTATUS GetCertificateAction(const ClientInfo& client_info,
+ const std::wstring& device_name,
+ BYTE* cert_data,
+ uint32_t cert_size);
+ static NTSTATUS GetCertificateSizeByHandleAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ uint32_t* cert_size);
+ static NTSTATUS GetCertificateByHandleAction(const ClientInfo& client_info,
+ HANDLE protected_output,
+ BYTE* cert_data,
+ uint32_t cert_size);
+ static NTSTATUS GetOPMRandomNumberAction(const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* random_number);
+ static NTSTATUS SetOPMSigningKeyAndSequenceNumbersAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* parameters);
+ static NTSTATUS ConfigureOPMProtectedOutputAction(
+ const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* parameters_ptr);
+ static NTSTATUS GetOPMInformationAction(const ClientInfo& client_info,
+ HANDLE protected_output,
+ void* parameters_ptr,
+ void* requested_information_ptr);
+ static NTSTATUS DestroyOPMProtectedOutputAction(HANDLE protected_output);
+ static void SetOverrideForTestCallback(OverrideForTestFunction callback);
+ static OverrideForTestFunction GetOverrideForTestCallback();
+
+ private:
+ static OverrideForTestFunction override_callback_;
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_PROCESS_MITIGATIONS_WIN32K_POLICY_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/process_policy_test.cc b/security/sandbox/chromium/sandbox/win/src/process_policy_test.cc
new file mode 100644
index 0000000000..c321c3a088
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_policy_test.cc
@@ -0,0 +1,548 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+#include <string>
+
+#include "base/memory/free_deleter.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/windows_version.h"
+#include "build/build_config.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Creates a process with the |exe| and |command| parameter using the
+// unicode and ascii version of the api.
+sandbox::SboxTestResult CreateProcessHelper(const std::wstring& exe,
+ const std::wstring& command) {
+ base::win::ScopedProcessInformation pi;
+ STARTUPINFOW si = {sizeof(si)};
+ const wchar_t* exe_name = nullptr;
+ if (!exe.empty())
+ exe_name = exe.c_str();
+
+ std::unique_ptr<wchar_t, base::FreeDeleter> writable_command(
+ _wcsdup(command.c_str()));
+
+ // Create the process with the unicode version of the API.
+ sandbox::SboxTestResult ret1 = sandbox::SBOX_TEST_FAILED;
+ PROCESS_INFORMATION temp_process_info = {};
+ if (::CreateProcessW(
+ exe_name, command.empty() ? nullptr : writable_command.get(), nullptr,
+ nullptr, false, 0, nullptr, nullptr, &si, &temp_process_info)) {
+ pi.Set(temp_process_info);
+ ret1 = sandbox::SBOX_TEST_SUCCEEDED;
+ } else {
+ DWORD last_error = GetLastError();
+ if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
+ (ERROR_ACCESS_DENIED == last_error) ||
+ (ERROR_FILE_NOT_FOUND == last_error)) {
+ ret1 = sandbox::SBOX_TEST_DENIED;
+ } else {
+ ret1 = sandbox::SBOX_TEST_FAILED;
+ }
+ }
+
+ pi.Close();
+
+ // Do the same with the ansi version of the api
+ STARTUPINFOA sia = {sizeof(sia)};
+ sandbox::SboxTestResult ret2 = sandbox::SBOX_TEST_FAILED;
+
+ std::string narrow_cmd_line =
+ base::SysWideToMultiByte(command.c_str(), CP_UTF8);
+ if (::CreateProcessA(
+ exe_name ? base::SysWideToMultiByte(exe_name, CP_UTF8).c_str()
+ : nullptr,
+ command.empty() ? nullptr : &narrow_cmd_line[0], nullptr, nullptr,
+ false, 0, nullptr, nullptr, &sia, &temp_process_info)) {
+ pi.Set(temp_process_info);
+ ret2 = sandbox::SBOX_TEST_SUCCEEDED;
+ } else {
+ DWORD last_error = GetLastError();
+ if ((ERROR_NOT_ENOUGH_QUOTA == last_error) ||
+ (ERROR_ACCESS_DENIED == last_error) ||
+ (ERROR_FILE_NOT_FOUND == last_error)) {
+ ret2 = sandbox::SBOX_TEST_DENIED;
+ } else {
+ ret2 = sandbox::SBOX_TEST_FAILED;
+ }
+ }
+
+ if (ret1 == ret2)
+ return ret1;
+
+ return sandbox::SBOX_TEST_FAILED;
+}
+
+} // namespace
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int Process_RunApp1(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ std::wstring path = MakePathToSys(argv[0], false);
+
+ // TEST 1: Try with the path in the app_name.
+ return CreateProcessHelper(path, std::wstring());
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp2(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ std::wstring path = MakePathToSys(argv[0], false);
+
+ // TEST 2: Try with the path in the cmd_line.
+ std::wstring cmd_line = L"\"";
+ cmd_line += path;
+ cmd_line += L"\"";
+ return CreateProcessHelper(std::wstring(), cmd_line);
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp3(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ // TEST 3: Try file name in the cmd_line.
+ return CreateProcessHelper(std::wstring(), argv[0]);
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp4(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ // TEST 4: Try file name in the app_name and current directory sets correctly.
+ std::wstring system32 = MakePathToSys(L"", false);
+ wchar_t current_directory[MAX_PATH + 1];
+ DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
+ if (!ret)
+ return SBOX_TEST_FIRST_ERROR;
+ if (ret >= MAX_PATH)
+ return SBOX_TEST_FAILED;
+
+ current_directory[ret] = L'\\';
+ current_directory[ret + 1] = L'\0';
+ if (!::SetCurrentDirectory(system32.c_str()))
+ return SBOX_TEST_SECOND_ERROR;
+
+ const int result4 = CreateProcessHelper(argv[0], std::wstring());
+ return ::SetCurrentDirectory(current_directory) ? result4 : SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp5(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ std::wstring path = MakePathToSys(argv[0], false);
+
+ // TEST 5: Try with the path in the cmd_line and arguments.
+ std::wstring cmd_line = L"\"";
+ cmd_line += path;
+ cmd_line += L"\" /I";
+ return CreateProcessHelper(std::wstring(), cmd_line);
+}
+
+SBOX_TESTS_COMMAND int Process_RunApp6(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ // TEST 6: Try with the file_name in the cmd_line and arguments.
+ std::wstring cmd_line = argv[0];
+ cmd_line += L" /I";
+ return CreateProcessHelper(std::wstring(), cmd_line);
+}
+
+// Creates a process and checks if it's possible to get a handle to it's token.
+SBOX_TESTS_COMMAND int Process_GetChildProcessToken(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ std::wstring path = MakePathToSys(argv[0], false);
+
+ STARTUPINFOW si = {sizeof(si)};
+
+ PROCESS_INFORMATION temp_process_info = {};
+ if (!::CreateProcessW(path.c_str(), nullptr, nullptr, nullptr, false,
+ CREATE_SUSPENDED, nullptr, nullptr, &si,
+ &temp_process_info)) {
+ return SBOX_TEST_FAILED;
+ }
+ base::win::ScopedProcessInformation pi(temp_process_info);
+
+ HANDLE token = nullptr;
+ bool result =
+ ::OpenProcessToken(pi.process_handle(), TOKEN_IMPERSONATE, &token);
+ DWORD error = ::GetLastError();
+
+ base::win::ScopedHandle token_handle(token);
+
+ if (!::TerminateProcess(pi.process_handle(), 0))
+ return SBOX_TEST_FAILED;
+
+ if (result && token)
+ return SBOX_TEST_SUCCEEDED;
+
+ if (ERROR_ACCESS_DENIED == error)
+ return SBOX_TEST_DENIED;
+
+ return SBOX_TEST_FAILED;
+}
+
+// Creates a suspended process using CreateProcessA then kill it.
+SBOX_TESTS_COMMAND int Process_CreateProcessA(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (!argv || !argv[0])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ STARTUPINFOA si = {sizeof(si)};
+
+ std::wstring path = MakePathToSys(argv[0], false);
+
+ PROCESS_INFORMATION temp_process_info = {};
+ // Create suspended to avoid popping calc.
+ if (!::CreateProcessA(base::SysWideToMultiByte(path, CP_UTF8).c_str(),
+ nullptr, nullptr, nullptr, false, CREATE_SUSPENDED,
+ nullptr, nullptr, &si, &temp_process_info)) {
+ return SBOX_TEST_FAILED;
+ }
+ base::win::ScopedProcessInformation pi(temp_process_info);
+
+ if (!::TerminateProcess(pi.process_handle(), 0))
+ return SBOX_TEST_FAILED;
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+SBOX_TESTS_COMMAND int Process_OpenToken(int argc, wchar_t** argv) {
+ HANDLE token;
+ if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
+ if (ERROR_ACCESS_DENIED == ::GetLastError()) {
+ return SBOX_TEST_DENIED;
+ }
+ } else {
+ ::CloseHandle(token);
+ return SBOX_TEST_SUCCEEDED;
+ }
+
+ return SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int Process_Crash(int argc, wchar_t** argv) {
+ __debugbreak();
+ return SBOX_TEST_FAILED;
+}
+// Generate a event name, used to test thread creation.
+std::wstring GenerateEventName(DWORD pid) {
+ wchar_t buff[30] = {0};
+ int res = swprintf_s(buff, sizeof(buff) / sizeof(buff[0]),
+ L"ProcessPolicyTest_%08x", pid);
+ if (-1 != res) {
+ return std::wstring(buff);
+ }
+ return std::wstring();
+}
+
+// This is the function that is called when testing thread creation.
+// It is expected to set an event that the caller is waiting on.
+DWORD WINAPI TestThreadFunc(LPVOID lpdwThreadParam) {
+ std::wstring event_name = GenerateEventName(
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(lpdwThreadParam)));
+ if (!event_name.length())
+ return 1;
+ HANDLE event = ::OpenEvent(EVENT_ALL_ACCESS | EVENT_MODIFY_STATE, false,
+ event_name.c_str());
+ if (!event)
+ return 1;
+ if (!SetEvent(event))
+ return 1;
+ return 0;
+}
+
+SBOX_TESTS_COMMAND int Process_CreateThread(int argc, wchar_t** argv) {
+ DWORD pid = ::GetCurrentProcessId();
+ std::wstring event_name = GenerateEventName(pid);
+ if (!event_name.length())
+ return SBOX_TEST_FIRST_ERROR;
+ HANDLE event = ::CreateEvent(nullptr, true, false, event_name.c_str());
+ if (!event)
+ return SBOX_TEST_SECOND_ERROR;
+
+ DWORD thread_id = 0;
+ HANDLE thread = nullptr;
+ thread = ::CreateThread(nullptr, 0, &TestThreadFunc,
+ reinterpret_cast<LPVOID>(static_cast<uintptr_t>(pid)),
+ 0, &thread_id);
+
+ if (!thread)
+ return SBOX_TEST_THIRD_ERROR;
+ if (!thread_id)
+ return SBOX_TEST_FOURTH_ERROR;
+ if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0)
+ return SBOX_TEST_FIFTH_ERROR;
+ DWORD exit_code = 0;
+ if (!GetExitCodeThread(thread, &exit_code))
+ return SBOX_TEST_SIXTH_ERROR;
+ if (exit_code)
+ return SBOX_TEST_SEVENTH_ERROR;
+ if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
+ return SBOX_TEST_FAILED;
+ return SBOX_TEST_SUCCEEDED;
+}
+
+// Creates a process and checks its exit code. Succeeds on exit code 0.
+SBOX_TESTS_COMMAND int Process_CheckExitCode(int argc, wchar_t** argv) {
+ if (argc != 3)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ if (!argv || !argv[0] || !argv[1] || !argv[2])
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ std::wstring path = MakePathToSys(argv[0], false);
+ std::wstring cmdline = argv[1];
+ std::wstring cwd = argv[2];
+
+ STARTUPINFOW si = {sizeof(si)};
+
+ PROCESS_INFORMATION temp_process_info = {};
+ if (!::CreateProcessW(path.c_str(), &cmdline[0], nullptr, nullptr, false, 0,
+ nullptr, cwd.c_str(), &si, &temp_process_info)) {
+ return SBOX_TEST_FAILED;
+ }
+ base::win::ScopedProcessInformation pi(temp_process_info);
+ DWORD ret = WaitForSingleObject(pi.process_handle(), 1000);
+ if (ret != WAIT_OBJECT_0)
+ return SBOX_TEST_FAILED;
+
+ DWORD exit_code;
+ if (!GetExitCodeProcess(pi.process_handle(), &exit_code))
+ return SBOX_TEST_FAILED;
+
+ if (exit_code != 0)
+ return SBOX_TEST_FAILED;
+
+ return SBOX_TEST_SUCCEEDED;
+}
+
+TEST(ProcessPolicyTest, TestAllAccess) {
+ // Check if the "all access" rule fails to be added when the token is too
+ // powerful.
+ TestRunner runner;
+
+ // Check the failing case.
+ runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_LOCKDOWN);
+ EXPECT_EQ(SBOX_ERROR_UNSUPPORTED,
+ runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_ALL_EXEC,
+ L"this is not important"));
+
+ // Check the working case.
+ runner.GetPolicy()->SetTokenLevel(USER_INTERACTIVE, USER_INTERACTIVE);
+
+ EXPECT_EQ(SBOX_ALL_OK,
+ runner.GetPolicy()->AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_ALL_EXEC,
+ L"this is not important"));
+}
+
+TEST(ProcessPolicyTest, CreateProcessAW) {
+ TestRunner runner;
+ std::wstring maybe_virtual_exe_path = MakePathToSys(L"findstr.exe", false);
+ std::wstring non_virtual_exe_path = MakePathToSys32(L"findstr.exe", false);
+ ASSERT_TRUE(!maybe_virtual_exe_path.empty());
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_MIN_EXEC,
+ maybe_virtual_exe_path.c_str()));
+
+ if (non_virtual_exe_path != maybe_virtual_exe_path) {
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_MIN_EXEC,
+ non_virtual_exe_path.c_str()));
+ }
+
+ // Need to add directory rules for the directories that we use in
+ // SetCurrentDirectory.
+ EXPECT_TRUE(runner.AddRuleSys32(TargetPolicy::FILES_ALLOW_DIR_ANY, L""));
+
+ wchar_t current_directory[MAX_PATH];
+ DWORD ret = ::GetCurrentDirectory(MAX_PATH, current_directory);
+ ASSERT_TRUE(0 != ret && ret < MAX_PATH);
+
+ wcscat_s(current_directory, MAX_PATH, L"\\");
+ EXPECT_TRUE(
+ runner.AddFsRule(TargetPolicy::FILES_ALLOW_DIR_ANY, current_directory));
+
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp1 calc.exe"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp2 calc.exe"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp3 calc.exe"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp4 calc.exe"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp5 calc.exe"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Process_RunApp6 calc.exe"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_RunApp1 findstr.exe"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_RunApp2 findstr.exe"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_RunApp3 findstr.exe"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_RunApp4 findstr.exe"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_RunApp5 findstr.exe"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_RunApp6 findstr.exe"));
+}
+
+// Tests that the broker correctly handles a process crashing within the job.
+// Fails on Windows ARM64: https://crbug.com/905526
+#if defined(ARCH_CPU_ARM64)
+#define MAYBE_CreateProcessCrashy DISABLED_CreateProcessCrashy
+#else
+#define MAYBE_CreateProcessCrashy CreateProcessCrashy
+#endif
+TEST(ProcessPolicyTest, MAYBE_CreateProcessCrashy) {
+ TestRunner runner;
+ EXPECT_EQ(static_cast<int>(STATUS_BREAKPOINT),
+ runner.RunTest(L"Process_Crash"));
+}
+
+TEST(ProcessPolicyTest, CreateProcessWithCWD) {
+ TestRunner runner;
+ std::wstring sys_path = MakePathToSys(L"", false);
+ while (!sys_path.empty() && sys_path.back() == L'\\')
+ sys_path.erase(sys_path.length() - 1);
+
+ std::wstring exe_path = MakePathToSys(L"cmd.exe", false);
+ std::wstring cmd_line =
+ L"\"/c if \\\"%CD%\\\" NEQ \\\"" + sys_path + L"\\\" exit 1\"";
+
+ ASSERT_TRUE(!exe_path.empty());
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_MIN_EXEC, exe_path.c_str()));
+
+ std::wstring command =
+ L"Process_CheckExitCode cmd.exe " + cmd_line + L" " + sys_path;
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(command.c_str()));
+}
+
+TEST(ProcessPolicyTest, OpenToken) {
+ TestRunner runner;
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_OpenToken"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMinAccess) {
+ TestRunner runner;
+ std::wstring exe_path = MakePathToSys(L"findstr.exe", false);
+ ASSERT_TRUE(!exe_path.empty());
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_MIN_EXEC, exe_path.c_str()));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccess) {
+ TestRunner runner(JOB_UNPROTECTED, USER_INTERACTIVE, USER_INTERACTIVE);
+ std::wstring exe_path = MakePathToSys(L"findstr.exe", false);
+ ASSERT_TRUE(!exe_path.empty());
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_ALL_EXEC, exe_path.c_str()));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMinAccessNoJob) {
+ TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN);
+ std::wstring exe_path = MakePathToSys(L"findstr.exe", false);
+ ASSERT_TRUE(!exe_path.empty());
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_MIN_EXEC, exe_path.c_str()));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+TEST(ProcessPolicyTest, TestGetProcessTokenMaxAccessNoJob) {
+ TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
+ std::wstring exe_path = MakePathToSys(L"findstr.exe", false);
+ ASSERT_TRUE(!exe_path.empty());
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_ALL_EXEC, exe_path.c_str()));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_GetChildProcessToken findstr.exe"));
+}
+
+TEST(ProcessPolicyTest, TestCreateProcessA) {
+ TestRunner runner;
+ sandbox::TargetPolicy* policy = runner.GetPolicy();
+ policy->SetJobLevel(JOB_NONE, 0);
+ policy->SetTokenLevel(USER_UNPROTECTED, USER_UNPROTECTED);
+ std::wstring exe_path = MakePathToSys(L"calc.exe", false);
+ ASSERT_TRUE(!exe_path.empty());
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_PROCESS,
+ TargetPolicy::PROCESS_ALL_EXEC, exe_path.c_str()));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Process_CreateProcessA calc.exe"));
+}
+
+// This tests that the CreateThread works with CSRSS not locked down.
+// In other words, that the interception passes through OK.
+TEST(ProcessPolicyTest, TestCreateThreadWithCsrss) {
+ TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
+ runner.SetDisableCsrss(false);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_CreateThread"));
+}
+
+// This tests that the CreateThread works with CSRSS locked down.
+// In other words, that the interception correctly works.
+TEST(ProcessPolicyTest, TestCreateThreadWithoutCsrss) {
+ TestRunner runner(JOB_NONE, USER_INTERACTIVE, USER_INTERACTIVE);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Process_CreateThread"));
+}
+
+// This tests that our CreateThread interceptors works when called directly.
+TEST(ProcessPolicyTest, TestCreateThreadOutsideSandbox) {
+ DWORD pid = ::GetCurrentProcessId();
+ std::wstring event_name = GenerateEventName(pid);
+ ASSERT_STRNE(nullptr, event_name.c_str());
+ HANDLE event = ::CreateEvent(nullptr, true, false, event_name.c_str());
+ EXPECT_NE(static_cast<HANDLE>(nullptr), event);
+
+ DWORD thread_id = 0;
+ HANDLE thread = nullptr;
+ thread = TargetCreateThread(
+ ::CreateThread, nullptr, 0, &TestThreadFunc,
+ reinterpret_cast<LPVOID>(static_cast<uintptr_t>(pid)), 0, &thread_id);
+ EXPECT_NE(static_cast<HANDLE>(nullptr), thread);
+ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(thread, INFINITE));
+ EXPECT_EQ(WAIT_OBJECT_0, WaitForSingleObject(event, INFINITE));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.cc
new file mode 100644
index 0000000000..7f0b0a6542
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.cc
@@ -0,0 +1,275 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_thread_dispatcher.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/process_thread_interception.h"
+#include "sandbox/win/src/process_thread_policy.h"
+#include "sandbox/win/src/sandbox.h"
+
+namespace {
+
+// Extracts the application name from a command line.
+//
+// The application name is the first element of the command line. If
+// there is no quotes, the first element is delimited by the first space.
+// If there are quotes, the first element is delimited by the quotes.
+//
+// The create process call is smarter than us. It tries really hard to launch
+// the process even if the command line is wrong. For example:
+// "c:\program files\test param" will first try to launch c:\program.exe then
+// c:\program files\test.exe. We don't do that, we stop after at the first
+// space when there is no quotes.
+std::wstring GetPathFromCmdLine(const std::wstring& cmd_line) {
+ std::wstring exe_name;
+ // Check if it starts with '"'.
+ if (cmd_line[0] == L'\"') {
+ // Find the position of the second '"', this terminates the path.
+ std::wstring::size_type pos = cmd_line.find(L'\"', 1);
+ if (std::wstring::npos == pos)
+ return cmd_line;
+ exe_name = cmd_line.substr(1, pos - 1);
+ } else {
+ // There is no '"', that means that the appname is terminated at the
+ // first space.
+ std::wstring::size_type pos = cmd_line.find(L' ');
+ if (std::wstring::npos == pos) {
+ // There is no space, the cmd_line contains only the app_name
+ exe_name = cmd_line;
+ } else {
+ exe_name = cmd_line.substr(0, pos);
+ }
+ }
+
+ return exe_name;
+}
+
+// Returns true is the path in parameter is relative. False if it's
+// absolute.
+bool IsPathRelative(const std::wstring& path) {
+ // A path is Relative if it's not a UNC path beginnning with \\ or a
+ // path beginning with a drive. (i.e. X:\)
+ if (path.find(L"\\\\") == 0 || path.find(L":\\") == 1)
+ return false;
+ return true;
+}
+
+// Converts a relative path to an absolute path.
+bool ConvertToAbsolutePath(const std::wstring& child_current_directory,
+ bool use_env_path,
+ std::wstring* path) {
+ wchar_t file_buffer[MAX_PATH];
+ wchar_t* file_part = nullptr;
+
+ // Here we should start by looking at the path where the child application was
+ // started. We don't have this information yet.
+ DWORD result = 0;
+ if (use_env_path) {
+ // Try with the complete path
+ result = ::SearchPath(nullptr, path->c_str(), nullptr, MAX_PATH,
+ file_buffer, &file_part);
+ }
+
+ if (0 == result) {
+ // Try with the current directory of the child
+ result = ::SearchPath(child_current_directory.c_str(), path->c_str(),
+ nullptr, MAX_PATH, file_buffer, &file_part);
+ }
+
+ if (0 == result || result >= MAX_PATH)
+ return false;
+
+ *path = file_buffer;
+ return true;
+}
+
+} // namespace
+namespace sandbox {
+
+ThreadProcessDispatcher::ThreadProcessDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall open_thread = {
+ {IpcTag::NTOPENTHREAD, {UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ThreadProcessDispatcher::NtOpenThread)};
+
+ static const IPCCall open_process = {
+ {IpcTag::NTOPENPROCESS, {UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ThreadProcessDispatcher::NtOpenProcess)};
+
+ static const IPCCall process_token = {
+ {IpcTag::NTOPENPROCESSTOKEN, {VOIDPTR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ThreadProcessDispatcher::NtOpenProcessToken)};
+
+ static const IPCCall process_tokenex = {
+ {IpcTag::NTOPENPROCESSTOKENEX, {VOIDPTR_TYPE, UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ThreadProcessDispatcher::NtOpenProcessTokenEx)};
+
+ static const IPCCall create_params = {
+ {IpcTag::CREATEPROCESSW,
+ {WCHAR_TYPE, WCHAR_TYPE, WCHAR_TYPE, WCHAR_TYPE, INOUTPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ThreadProcessDispatcher::CreateProcessW)};
+
+ // NOTE(liamjm): 2nd param is size_t: Using VOIDPTR_TYPE as they are
+ // the same size on windows.
+ static_assert(sizeof(size_t) == sizeof(void*),
+ "VOIDPTR_TYPE not same size as size_t");
+ static const IPCCall create_thread_params = {
+ {IpcTag::CREATETHREAD,
+ {VOIDPTR_TYPE, VOIDPTR_TYPE, VOIDPTR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(
+ &ThreadProcessDispatcher::CreateThread)};
+
+ ipc_calls_.push_back(open_thread);
+ ipc_calls_.push_back(open_process);
+ ipc_calls_.push_back(process_token);
+ ipc_calls_.push_back(process_tokenex);
+ ipc_calls_.push_back(create_params);
+ ipc_calls_.push_back(create_thread_params);
+}
+
+bool ThreadProcessDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ switch (service) {
+ case IpcTag::NTOPENTHREAD:
+ case IpcTag::NTOPENPROCESS:
+ case IpcTag::NTOPENPROCESSTOKEN:
+ case IpcTag::NTOPENPROCESSTOKENEX:
+ case IpcTag::CREATETHREAD:
+ // There is no explicit policy for these services.
+ NOTREACHED();
+ return false;
+
+ case IpcTag::CREATEPROCESSW:
+ return INTERCEPT_EAT(manager, kKerneldllName, CreateProcessW,
+ CREATE_PROCESSW_ID, 44) &&
+ INTERCEPT_EAT(manager, L"kernel32.dll", CreateProcessA,
+ CREATE_PROCESSA_ID, 44);
+
+ default:
+ return false;
+ }
+}
+
+bool ThreadProcessDispatcher::NtOpenThread(IPCInfo* ipc,
+ uint32_t desired_access,
+ uint32_t thread_id) {
+ HANDLE handle;
+ NTSTATUS ret = ProcessPolicy::OpenThreadAction(
+ *ipc->client_info, desired_access, thread_id, &handle);
+ ipc->return_info.nt_status = ret;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool ThreadProcessDispatcher::NtOpenProcess(IPCInfo* ipc,
+ uint32_t desired_access,
+ uint32_t process_id) {
+ HANDLE handle;
+ NTSTATUS ret = ProcessPolicy::OpenProcessAction(
+ *ipc->client_info, desired_access, process_id, &handle);
+ ipc->return_info.nt_status = ret;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool ThreadProcessDispatcher::NtOpenProcessToken(IPCInfo* ipc,
+ HANDLE process,
+ uint32_t desired_access) {
+ HANDLE handle;
+ NTSTATUS ret = ProcessPolicy::OpenProcessTokenAction(
+ *ipc->client_info, process, desired_access, &handle);
+ ipc->return_info.nt_status = ret;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool ThreadProcessDispatcher::NtOpenProcessTokenEx(IPCInfo* ipc,
+ HANDLE process,
+ uint32_t desired_access,
+ uint32_t attributes) {
+ HANDLE handle;
+ NTSTATUS ret = ProcessPolicy::OpenProcessTokenExAction(
+ *ipc->client_info, process, desired_access, attributes, &handle);
+ ipc->return_info.nt_status = ret;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool ThreadProcessDispatcher::CreateProcessW(IPCInfo* ipc,
+ std::wstring* name,
+ std::wstring* cmd_line,
+ std::wstring* cur_dir,
+ std::wstring* target_cur_dir,
+ CountedBuffer* info) {
+ if (sizeof(PROCESS_INFORMATION) != info->Size())
+ return false;
+
+ // Check if there is an application name.
+ std::wstring exe_name;
+ if (!name->empty())
+ exe_name = *name;
+ else
+ exe_name = GetPathFromCmdLine(*cmd_line);
+
+ if (IsPathRelative(exe_name)) {
+ if (!ConvertToAbsolutePath(*cur_dir, name->empty(), &exe_name)) {
+ // Cannot find the path. Maybe the file does not exist.
+ ipc->return_info.win32_result = ERROR_FILE_NOT_FOUND;
+ return true;
+ }
+ }
+
+ const wchar_t* const_exe_name = exe_name.c_str();
+ CountedParameterSet<NameBased> params;
+ params[NameBased::NAME] = ParamPickerMake(const_exe_name);
+
+ EvalResult eval =
+ policy_base_->EvalPolicy(IpcTag::CREATEPROCESSW, params.GetBase());
+
+ PROCESS_INFORMATION* proc_info =
+ reinterpret_cast<PROCESS_INFORMATION*>(info->Buffer());
+ // Here we force the app_name to be the one we used for the policy lookup.
+ // If our logic was wrong, at least we wont allow create a random process.
+ DWORD ret = ProcessPolicy::CreateProcessWAction(
+ eval, *ipc->client_info, exe_name, *cmd_line, *target_cur_dir, proc_info);
+
+ ipc->return_info.win32_result = ret;
+ return true;
+}
+
+bool ThreadProcessDispatcher::CreateThread(IPCInfo* ipc,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags) {
+ if (!start_address) {
+ return false;
+ }
+
+ HANDLE handle;
+ DWORD ret = ProcessPolicy::CreateThreadAction(
+ *ipc->client_info, stack_size, start_address, parameter, creation_flags,
+ nullptr, &handle);
+
+ ipc->return_info.nt_status = ret;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.h
new file mode 100644
index 0000000000..07466c46e2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_thread_dispatcher.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_THREAD_DISPATCHER_H_
+#define SANDBOX_SRC_PROCESS_THREAD_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles process and thread-related IPC calls.
+class ThreadProcessDispatcher : public Dispatcher {
+ public:
+ explicit ThreadProcessDispatcher(PolicyBase* policy_base);
+ ~ThreadProcessDispatcher() override {}
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to NtOpenThread() in the target.
+ bool NtOpenThread(IPCInfo* ipc, uint32_t desired_access, uint32_t thread_id);
+
+ // Processes IPC requests coming from calls to NtOpenProcess() in the target.
+ bool NtOpenProcess(IPCInfo* ipc,
+ uint32_t desired_access,
+ uint32_t process_id);
+
+ // Processes IPC requests from calls to NtOpenProcessToken() in the target.
+ bool NtOpenProcessToken(IPCInfo* ipc,
+ HANDLE process,
+ uint32_t desired_access);
+
+ // Processes IPC requests from calls to NtOpenProcessTokenEx() in the target.
+ bool NtOpenProcessTokenEx(IPCInfo* ipc,
+ HANDLE process,
+ uint32_t desired_access,
+ uint32_t attributes);
+
+ // Processes IPC requests coming from calls to CreateProcessW() in the target.
+ bool CreateProcessW(IPCInfo* ipc,
+ std::wstring* name,
+ std::wstring* cmd_line,
+ std::wstring* cur_dir,
+ std::wstring* target_cur_dir,
+ CountedBuffer* info);
+
+ // Processes IPC requests coming from calls to CreateThread() in the target.
+ bool CreateThread(IPCInfo* ipc,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags);
+
+ PolicyBase* policy_base_;
+ DISALLOW_COPY_AND_ASSIGN(ThreadProcessDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_PROCESS_THREAD_DISPATCHER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/process_thread_interception.cc b/security/sandbox/chromium/sandbox/win/src/process_thread_interception.cc
new file mode 100644
index 0000000000..0bd3d5a8d2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_thread_interception.cc
@@ -0,0 +1,520 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_thread_interception.h"
+
+#include <stdint.h>
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+// Hooks NtOpenThread and proxy the call to the broker if it's trying to
+// open a thread in the same process.
+NTSTATUS WINAPI TargetNtOpenThread(NtOpenThreadFunction orig_OpenThread,
+ PHANDLE thread,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id) {
+ NTSTATUS status =
+ orig_OpenThread(thread, desired_access, object_attributes, client_id);
+ if (NT_SUCCESS(status))
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtOpenThread");
+ do {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ break;
+ if (!client_id)
+ break;
+
+ uint32_t thread_id = 0;
+ bool should_break = false;
+ __try {
+ // We support only the calls for the current process
+ if (client_id->UniqueProcess)
+ should_break = true;
+
+ // Object attributes should be nullptr or empty.
+ if (!should_break && object_attributes) {
+ if (object_attributes->Attributes || object_attributes->ObjectName ||
+ object_attributes->RootDirectory ||
+ object_attributes->SecurityDescriptor ||
+ object_attributes->SecurityQualityOfService) {
+ should_break = true;
+ }
+ }
+
+ thread_id = static_cast<uint32_t>(
+ reinterpret_cast<ULONG_PTR>(client_id->UniqueThread));
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ if (should_break)
+ break;
+
+ if (!ValidParameter(thread, sizeof(HANDLE), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::NTOPENTHREAD, desired_access,
+ thread_id, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ // The nt_status here is most likely STATUS_INVALID_CID because
+ // in the broker we set the process id in the CID (client ID) param
+ // to be the current process. If you try to open a thread from another
+ // process you will get this INVALID_CID error. On the other hand, if you
+ // try to open a thread in your own process, it should return success.
+ // We don't want to return STATUS_INVALID_CID here, so we return the
+ // return of the original open thread status, which is most likely
+ // STATUS_ACCESS_DENIED.
+ break;
+
+ __try {
+ // Write the output parameters.
+ *thread = answer.handle;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ mozilla::sandboxing::LogAllowed("NtOpenThread");
+ return answer.nt_status;
+ } while (false);
+
+ return status;
+}
+
+// Hooks NtOpenProcess and proxy the call to the broker if it's trying to
+// open the current process.
+NTSTATUS WINAPI TargetNtOpenProcess(NtOpenProcessFunction orig_OpenProcess,
+ PHANDLE process,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id) {
+ NTSTATUS status =
+ orig_OpenProcess(process, desired_access, object_attributes, client_id);
+ if (NT_SUCCESS(status))
+ return status;
+
+ do {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ break;
+ if (!client_id)
+ break;
+
+ uint32_t process_id = 0;
+ bool should_break = false;
+ __try {
+ // Object attributes should be nullptr or empty.
+ if (!should_break && object_attributes) {
+ if (object_attributes->Attributes || object_attributes->ObjectName ||
+ object_attributes->RootDirectory ||
+ object_attributes->SecurityDescriptor ||
+ object_attributes->SecurityQualityOfService) {
+ should_break = true;
+ }
+ }
+
+ process_id = static_cast<uint32_t>(
+ reinterpret_cast<ULONG_PTR>(client_id->UniqueProcess));
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ if (should_break)
+ break;
+
+ if (!ValidParameter(process, sizeof(HANDLE), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::NTOPENPROCESS, desired_access,
+ process_id, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ return answer.nt_status;
+
+ __try {
+ // Write the output parameters.
+ *process = answer.handle;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ return answer.nt_status;
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI
+TargetNtOpenProcessToken(NtOpenProcessTokenFunction orig_OpenProcessToken,
+ HANDLE process,
+ ACCESS_MASK desired_access,
+ PHANDLE token) {
+ NTSTATUS status = orig_OpenProcessToken(process, desired_access, token);
+ if (NT_SUCCESS(status))
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtOpenProcessToken");
+ do {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ break;
+
+ if (CURRENT_PROCESS != process)
+ break;
+
+ if (!ValidParameter(token, sizeof(HANDLE), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::NTOPENPROCESSTOKEN, process,
+ desired_access, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ return answer.nt_status;
+
+ __try {
+ // Write the output parameters.
+ *token = answer.handle;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ mozilla::sandboxing::LogAllowed("NtOpenProcessToken");
+ return answer.nt_status;
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI
+TargetNtOpenProcessTokenEx(NtOpenProcessTokenExFunction orig_OpenProcessTokenEx,
+ HANDLE process,
+ ACCESS_MASK desired_access,
+ ULONG handle_attributes,
+ PHANDLE token) {
+ NTSTATUS status = orig_OpenProcessTokenEx(process, desired_access,
+ handle_attributes, token);
+ if (NT_SUCCESS(status))
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtOpenProcessTokenEx");
+ do {
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ break;
+
+ if (CURRENT_PROCESS != process)
+ break;
+
+ if (!ValidParameter(token, sizeof(HANDLE), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::NTOPENPROCESSTOKENEX, process,
+ desired_access, handle_attributes, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ return answer.nt_status;
+
+ __try {
+ // Write the output parameters.
+ *token = answer.handle;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ mozilla::sandboxing::LogAllowed("NtOpenProcessTokenEx");
+ return answer.nt_status;
+ } while (false);
+
+ return status;
+}
+
+BOOL WINAPI TargetCreateProcessW(CreateProcessWFunction orig_CreateProcessW,
+ LPCWSTR application_name,
+ LPWSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCWSTR current_directory,
+ LPSTARTUPINFOW startup_info,
+ LPPROCESS_INFORMATION process_information) {
+ if (SandboxFactory::GetTargetServices()->GetState()->IsCsrssConnected() &&
+ orig_CreateProcessW(application_name, command_line, process_attributes,
+ thread_attributes, inherit_handles, flags,
+ environment, current_directory, startup_info,
+ process_information)) {
+ return true;
+ }
+
+ mozilla::sandboxing::LogBlocked("CreateProcessW", application_name);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return false;
+
+ // Don't call GetLastError before InitCalled() succeeds because kernel32 may
+ // not be mapped yet.
+ DWORD original_error = ::GetLastError();
+
+ do {
+ if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
+ WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ const wchar_t* cur_dir = nullptr;
+
+ wchar_t this_current_directory[MAX_PATH];
+ DWORD result = ::GetCurrentDirectory(MAX_PATH, this_current_directory);
+ if (0 != result && result < MAX_PATH)
+ cur_dir = this_current_directory;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+
+ InOutCountedBuffer proc_info(process_information,
+ sizeof(PROCESS_INFORMATION));
+
+ ResultCode code =
+ CrossCall(ipc, IpcTag::CREATEPROCESSW, application_name, command_line,
+ cur_dir, current_directory, proc_info, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ ::SetLastError(answer.win32_result);
+ if (ERROR_SUCCESS != answer.win32_result)
+ return false;
+
+ mozilla::sandboxing::LogAllowed("CreateProcessW", application_name);
+ return true;
+ } while (false);
+
+ ::SetLastError(original_error);
+ return false;
+}
+
+BOOL WINAPI TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,
+ LPCSTR application_name,
+ LPSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCSTR current_directory,
+ LPSTARTUPINFOA startup_info,
+ LPPROCESS_INFORMATION process_information) {
+ if (SandboxFactory::GetTargetServices()->GetState()->IsCsrssConnected() &&
+ orig_CreateProcessA(application_name, command_line, process_attributes,
+ thread_attributes, inherit_handles, flags,
+ environment, current_directory, startup_info,
+ process_information)) {
+ return true;
+ }
+
+ mozilla::sandboxing::LogBlocked("CreateProcessA", application_name);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return false;
+
+ // Don't call GetLastError before InitCalled() succeeds because kernel32 may
+ // not be mapped yet.
+ DWORD original_error = ::GetLastError();
+
+ do {
+ if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
+ WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ // Convert the input params to unicode.
+ UNICODE_STRING* cmd_unicode = nullptr;
+ UNICODE_STRING* app_unicode = nullptr;
+ UNICODE_STRING* cwd_unicode = nullptr;
+ if (command_line) {
+ cmd_unicode = AnsiToUnicode(command_line);
+ if (!cmd_unicode)
+ break;
+ }
+
+ if (application_name) {
+ app_unicode = AnsiToUnicode(application_name);
+ if (!app_unicode) {
+ operator delete(cmd_unicode, NT_ALLOC);
+ break;
+ }
+ }
+
+ if (current_directory) {
+ cwd_unicode = AnsiToUnicode(current_directory);
+ if (!cwd_unicode) {
+ operator delete(cmd_unicode, NT_ALLOC);
+ operator delete(app_unicode, NT_ALLOC);
+ break;
+ }
+ }
+
+ const wchar_t* cmd_line = cmd_unicode ? cmd_unicode->Buffer : nullptr;
+ const wchar_t* app_name = app_unicode ? app_unicode->Buffer : nullptr;
+ const wchar_t* cwd = cwd_unicode ? cwd_unicode->Buffer : nullptr;
+ const wchar_t* cur_dir = nullptr;
+
+ wchar_t target_current_directory[MAX_PATH];
+ DWORD result = ::GetCurrentDirectory(MAX_PATH, target_current_directory);
+ if (0 != result && result < MAX_PATH)
+ cur_dir = target_current_directory;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+
+ InOutCountedBuffer proc_info(process_information,
+ sizeof(PROCESS_INFORMATION));
+
+ ResultCode code = CrossCall(ipc, IpcTag::CREATEPROCESSW, app_name, cmd_line,
+ cur_dir, cwd, proc_info, &answer);
+
+ operator delete(cmd_unicode, NT_ALLOC);
+ operator delete(app_unicode, NT_ALLOC);
+ operator delete(cwd_unicode, NT_ALLOC);
+
+ if (SBOX_ALL_OK != code)
+ break;
+
+ ::SetLastError(answer.win32_result);
+ if (ERROR_SUCCESS != answer.win32_result)
+ return false;
+
+ mozilla::sandboxing::LogAllowed("CreateProcessA", application_name);
+ return true;
+ } while (false);
+
+ ::SetLastError(original_error);
+ return false;
+}
+
+HANDLE WINAPI TargetCreateThread(CreateThreadFunction orig_CreateThread,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id) {
+ HANDLE hThread = nullptr;
+
+ TargetServices* target_services = SandboxFactory::GetTargetServices();
+ if (!target_services || target_services->GetState()->IsCsrssConnected()) {
+ hThread = orig_CreateThread(thread_attributes, stack_size, start_address,
+ parameter, creation_flags, thread_id);
+ if (hThread)
+ return hThread;
+ }
+
+ DWORD original_error = ::GetLastError();
+ do {
+ if (!target_services)
+ break;
+
+ // We don't trust that the IPC can work this early.
+ if (!target_services->GetState()->InitCalled())
+ break;
+
+ __try {
+ if (thread_id && !ValidParameter(thread_id, sizeof(*thread_id), WRITE))
+ break;
+
+ if (!start_address)
+ break;
+ // We don't support thread_attributes not being null.
+ if (thread_attributes)
+ break;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+
+ // NOTE: we don't pass the thread_attributes through. This matches the
+ // approach in CreateProcess and in CreateThreadInternal().
+ ResultCode code = CrossCall(ipc, IpcTag::CREATETHREAD,
+ reinterpret_cast<LPVOID>(stack_size),
+ reinterpret_cast<LPVOID>(start_address),
+ parameter, creation_flags, &answer);
+ if (SBOX_ALL_OK != code)
+ break;
+
+ ::SetLastError(answer.win32_result);
+ if (ERROR_SUCCESS != answer.win32_result)
+ return nullptr;
+
+ __try {
+ if (thread_id)
+ *thread_id = ::GetThreadId(answer.handle);
+ return answer.handle;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ } while (false);
+
+ ::SetLastError(original_error);
+ return nullptr;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_thread_interception.h b/security/sandbox/chromium/sandbox/win/src/process_thread_interception.h
new file mode 100644
index 0000000000..2608d7d31e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_thread_interception.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_PROCESS_THREAD_INTERCEPTION_H_
+#define SANDBOX_WIN_SRC_PROCESS_THREAD_INTERCEPTION_H_
+
+#include <windows.h>
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+namespace {
+
+using CreateProcessWFunction = decltype(&::CreateProcessW);
+
+using CreateProcessAFunction = decltype(&::CreateProcessA);
+
+using CreateThreadFunction = decltype(&::CreateThread);
+
+using GetUserDefaultLCIDFunction = decltype(&::GetUserDefaultLCID);
+
+} // namespace
+
+extern "C" {
+
+// Interception of NtOpenThread on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenThread(NtOpenThreadFunction orig_OpenThread,
+ PHANDLE thread,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id);
+
+// Interception of NtOpenProcess on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcess(NtOpenProcessFunction orig_OpenProcess,
+ PHANDLE process,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PCLIENT_ID client_id);
+
+// Interception of NtOpenProcessToken on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcessToken(NtOpenProcessTokenFunction orig_OpenProcessToken,
+ HANDLE process,
+ ACCESS_MASK desired_access,
+ PHANDLE token);
+
+// Interception of NtOpenProcessTokenEx on the child process.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenProcessTokenEx(NtOpenProcessTokenExFunction orig_OpenProcessTokenEx,
+ HANDLE process,
+ ACCESS_MASK desired_access,
+ ULONG handle_attributes,
+ PHANDLE token);
+
+// Interception of CreateProcessW and A in kernel32.dll.
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetCreateProcessW(CreateProcessWFunction orig_CreateProcessW,
+ LPCWSTR application_name,
+ LPWSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCWSTR current_directory,
+ LPSTARTUPINFOW startup_info,
+ LPPROCESS_INFORMATION process_information);
+
+SANDBOX_INTERCEPT BOOL WINAPI
+TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,
+ LPCSTR application_name,
+ LPSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD flags,
+ LPVOID environment,
+ LPCSTR current_directory,
+ LPSTARTUPINFOA startup_info,
+ LPPROCESS_INFORMATION process_information);
+
+// Interception of CreateThread in kernel32.dll.
+SANDBOX_INTERCEPT HANDLE WINAPI
+TargetCreateThread(CreateThreadFunction orig_CreateThread,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ LPVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_PROCESS_THREAD_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/process_thread_policy.cc b/security/sandbox/chromium/sandbox/win/src/process_thread_policy.cc
new file mode 100644
index 0000000000..20146a83df
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_thread_policy.cc
@@ -0,0 +1,269 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/process_thread_policy.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/memory/free_deleter.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// These are the only safe rights that can be given to a sandboxed
+// process for the process created by the broker. All others are potential
+// vectors of privilege elevation.
+const DWORD kProcessRights = SYNCHRONIZE | PROCESS_QUERY_INFORMATION |
+ PROCESS_QUERY_LIMITED_INFORMATION |
+ PROCESS_TERMINATE | PROCESS_SUSPEND_RESUME;
+
+const DWORD kThreadRights = SYNCHRONIZE | THREAD_TERMINATE |
+ THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION |
+ THREAD_QUERY_LIMITED_INFORMATION |
+ THREAD_SET_LIMITED_INFORMATION;
+
+// Creates a child process and duplicates the handles to 'target_process'. The
+// remaining parameters are the same as CreateProcess().
+bool CreateProcessExWHelper(HANDLE target_process,
+ bool give_full_access,
+ LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ bool bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCWSTR lpCurrentDirectory,
+ LPSTARTUPINFOW lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation) {
+ if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes,
+ lpThreadAttributes, bInheritHandles, dwCreationFlags,
+ lpEnvironment, lpCurrentDirectory, lpStartupInfo,
+ lpProcessInformation)) {
+ return false;
+ }
+
+ DWORD process_access = kProcessRights;
+ DWORD thread_access = kThreadRights;
+ if (give_full_access) {
+ process_access = PROCESS_ALL_ACCESS;
+ thread_access = THREAD_ALL_ACCESS;
+ }
+ if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess,
+ target_process, &lpProcessInformation->hProcess,
+ process_access, false, DUPLICATE_CLOSE_SOURCE)) {
+ ::CloseHandle(lpProcessInformation->hThread);
+ return false;
+ }
+ if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread,
+ target_process, &lpProcessInformation->hThread,
+ thread_access, false, DUPLICATE_CLOSE_SOURCE)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+namespace sandbox {
+
+bool ProcessPolicy::GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ std::unique_ptr<PolicyRule> process;
+ switch (semantics) {
+ case TargetPolicy::PROCESS_MIN_EXEC: {
+ process.reset(new PolicyRule(GIVE_READONLY));
+ break;
+ };
+ case TargetPolicy::PROCESS_ALL_EXEC: {
+ process.reset(new PolicyRule(GIVE_ALLACCESS));
+ break;
+ };
+ default: { return false; };
+ }
+
+ if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) {
+ return false;
+ }
+ if (!policy->AddRule(IpcTag::CREATEPROCESSW, process.get())) {
+ return false;
+ }
+ return true;
+}
+
+NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info,
+ uint32_t desired_access,
+ uint32_t thread_id,
+ HANDLE* handle) {
+ *handle = nullptr;
+
+ NtOpenThreadFunction NtOpenThread = nullptr;
+ ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread);
+
+ OBJECT_ATTRIBUTES attributes = {0};
+ attributes.Length = sizeof(attributes);
+ CLIENT_ID client_id = {0};
+ client_id.UniqueProcess =
+ reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(client_info.process_id));
+ client_id.UniqueThread =
+ reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id));
+
+ HANDLE local_handle = nullptr;
+ NTSTATUS status =
+ NtOpenThread(&local_handle, desired_access, &attributes, &client_id);
+ if (NT_SUCCESS(status)) {
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info,
+ uint32_t desired_access,
+ uint32_t process_id,
+ HANDLE* handle) {
+ *handle = nullptr;
+
+ NtOpenProcessFunction NtOpenProcess = nullptr;
+ ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess);
+
+ if (client_info.process_id != process_id)
+ return STATUS_ACCESS_DENIED;
+
+ OBJECT_ATTRIBUTES attributes = {0};
+ attributes.Length = sizeof(attributes);
+ CLIENT_ID client_id = {0};
+ client_id.UniqueProcess =
+ reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(client_info.process_id));
+ HANDLE local_handle = nullptr;
+ NTSTATUS status =
+ NtOpenProcess(&local_handle, desired_access, &attributes, &client_id);
+ if (NT_SUCCESS(status)) {
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info,
+ HANDLE process,
+ uint32_t desired_access,
+ HANDLE* handle) {
+ *handle = nullptr;
+ NtOpenProcessTokenFunction NtOpenProcessToken = nullptr;
+ ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken);
+
+ if (CURRENT_PROCESS != process)
+ return STATUS_ACCESS_DENIED;
+
+ HANDLE local_handle = nullptr;
+ NTSTATUS status =
+ NtOpenProcessToken(client_info.process, desired_access, &local_handle);
+ if (NT_SUCCESS(status)) {
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+ return status;
+}
+
+NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info,
+ HANDLE process,
+ uint32_t desired_access,
+ uint32_t attributes,
+ HANDLE* handle) {
+ *handle = nullptr;
+ NtOpenProcessTokenExFunction NtOpenProcessTokenEx = nullptr;
+ ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx);
+
+ if (CURRENT_PROCESS != process)
+ return STATUS_ACCESS_DENIED;
+
+ HANDLE local_handle = nullptr;
+ NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access,
+ attributes, &local_handle);
+ if (NT_SUCCESS(status)) {
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+ return status;
+}
+
+DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& app_name,
+ const std::wstring& command_line,
+ const std::wstring& current_dir,
+ PROCESS_INFORMATION* process_info) {
+ // The only action supported is ASK_BROKER which means create the process.
+ if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) {
+ return ERROR_ACCESS_DENIED;
+ }
+
+ STARTUPINFO startup_info = {0};
+ startup_info.cb = sizeof(startup_info);
+ std::unique_ptr<wchar_t, base::FreeDeleter> cmd_line(
+ _wcsdup(command_line.c_str()));
+
+ bool should_give_full_access = (GIVE_ALLACCESS == eval_result);
+
+ const wchar_t* cwd = current_dir.c_str();
+ if (current_dir.empty())
+ cwd = nullptr;
+
+ if (!CreateProcessExWHelper(client_info.process, should_give_full_access,
+ app_name.c_str(), cmd_line.get(), nullptr,
+ nullptr, false, 0, nullptr, cwd, &startup_info,
+ process_info)) {
+ return ERROR_ACCESS_DENIED;
+ }
+ return ERROR_SUCCESS;
+}
+
+DWORD ProcessPolicy::CreateThreadAction(
+ const ClientInfo& client_info,
+ const SIZE_T stack_size,
+ const LPTHREAD_START_ROUTINE start_address,
+ const LPVOID parameter,
+ const DWORD creation_flags,
+ LPDWORD thread_id,
+ HANDLE* handle) {
+ *handle = nullptr;
+ HANDLE local_handle =
+ ::CreateRemoteThread(client_info.process, nullptr, stack_size,
+ start_address, parameter, creation_flags, thread_id);
+ if (!local_handle) {
+ return ::GetLastError();
+ }
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return ERROR_ACCESS_DENIED;
+ }
+ return ERROR_SUCCESS;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/process_thread_policy.h b/security/sandbox/chromium/sandbox/win/src/process_thread_policy.h
new file mode 100644
index 0000000000..f6f96dd0ff
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/process_thread_policy.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_PROCESS_THREAD_POLICY_H_
+#define SANDBOX_SRC_PROCESS_THREAD_POLICY_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+// This class centralizes most of the knowledge related to process execution.
+class ProcessPolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level.
+ // policy rule for process creation
+ // 'name' is the executable to be spawn.
+ // 'semantics' is the desired semantics.
+ // 'policy' is the policy generator to which the rules are going to be added.
+ static bool GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ // Opens a thread from the child process and returns the handle.
+ // client_info contains the information about the child process,
+ // desired_access is the access requested by the child and thread_id
+ // is the thread_id to be opened.
+ // The function returns the return value of NtOpenThread.
+ static NTSTATUS OpenThreadAction(const ClientInfo& client_info,
+ uint32_t desired_access,
+ uint32_t thread_id,
+ HANDLE* handle);
+
+ // Opens the process id passed in and returns the duplicated handle to
+ // the child. We only allow the child processes to open themselves. Any other
+ // pid open is denied.
+ static NTSTATUS OpenProcessAction(const ClientInfo& client_info,
+ uint32_t desired_access,
+ uint32_t process_id,
+ HANDLE* handle);
+
+ // Opens the token associated with the process and returns the duplicated
+ // handle to the child. We only allow the child processes to open its own
+ // token (using ::GetCurrentProcess()).
+ static NTSTATUS OpenProcessTokenAction(const ClientInfo& client_info,
+ HANDLE process,
+ uint32_t desired_access,
+ HANDLE* handle);
+
+ // Opens the token associated with the process and returns the duplicated
+ // handle to the child. We only allow the child processes to open its own
+ // token (using ::GetCurrentProcess()).
+ static NTSTATUS OpenProcessTokenExAction(const ClientInfo& client_info,
+ HANDLE process,
+ uint32_t desired_access,
+ uint32_t attributes,
+ HANDLE* handle);
+
+ // Processes a 'CreateProcessW()' request from the target.
+ // 'client_info' : the target process that is making the request.
+ // 'eval_result' : The desired policy action to accomplish.
+ // 'app_name' : The full path of the process to be created.
+ // 'command_line' : The command line passed to the created process.
+ // 'current_dir' : The CWD with which to spawn the child process.
+ static DWORD CreateProcessWAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& app_name,
+ const std::wstring& command_line,
+ const std::wstring& current_dir,
+ PROCESS_INFORMATION* process_info);
+
+ // Processes a 'CreateThread()' request from the target.
+ // 'client_info' : the target process that is making the request.
+ static DWORD CreateThreadAction(const ClientInfo& client_info,
+ SIZE_T stack_size,
+ LPTHREAD_START_ROUTINE start_address,
+ PVOID parameter,
+ DWORD creation_flags,
+ LPDWORD thread_id,
+ HANDLE* handle);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_PROCESS_THREAD_POLICY_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/registry_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/registry_dispatcher.cc
new file mode 100644
index 0000000000..26d2bb3ffc
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/registry_dispatcher.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/registry_dispatcher.h"
+
+#include <stdint.h>
+
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/registry_interception.h"
+#include "sandbox/win/src/registry_policy.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+// Builds a path using the root directory and the name.
+bool GetCompletePath(HANDLE root,
+ const std::wstring& name,
+ std::wstring* complete_name) {
+ if (root) {
+ if (!sandbox::GetPathFromHandle(root, complete_name))
+ return false;
+
+ *complete_name += L"\\";
+ *complete_name += name;
+ } else {
+ *complete_name = name;
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace sandbox {
+
+RegistryDispatcher::RegistryDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall create_params = {
+ {IpcTag::NTCREATEKEY,
+ {WCHAR_TYPE, UINT32_TYPE, VOIDPTR_TYPE, UINT32_TYPE, UINT32_TYPE,
+ UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtCreateKey)};
+
+ static const IPCCall open_params = {
+ {IpcTag::NTOPENKEY, {WCHAR_TYPE, UINT32_TYPE, VOIDPTR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtOpenKey)};
+
+ ipc_calls_.push_back(create_params);
+ ipc_calls_.push_back(open_params);
+}
+
+bool RegistryDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ if (IpcTag::NTCREATEKEY == service)
+ return INTERCEPT_NT(manager, NtCreateKey, CREATE_KEY_ID, 32);
+
+ if (IpcTag::NTOPENKEY == service) {
+ bool result = INTERCEPT_NT(manager, NtOpenKey, OPEN_KEY_ID, 16);
+ result &= INTERCEPT_NT(manager, NtOpenKeyEx, OPEN_KEY_EX_ID, 20);
+ return result;
+ }
+
+ return false;
+}
+
+bool RegistryDispatcher::NtCreateKey(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ HANDLE root,
+ uint32_t desired_access,
+ uint32_t title_index,
+ uint32_t create_options) {
+ base::win::ScopedHandle root_handle;
+ std::wstring real_path = *name;
+
+ // If there is a root directory, we need to duplicate the handle to make
+ // it valid in this process.
+ if (root) {
+ if (!::DuplicateHandle(ipc->client_info->process, root,
+ ::GetCurrentProcess(), &root, 0, false,
+ DUPLICATE_SAME_ACCESS))
+ return false;
+
+ root_handle.Set(root);
+ }
+
+ if (!GetCompletePath(root, *name, &real_path))
+ return false;
+
+ const wchar_t* regname = real_path.c_str();
+ CountedParameterSet<OpenKey> params;
+ params[OpenKey::NAME] = ParamPickerMake(regname);
+ params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
+
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::NTCREATEKEY, params.GetBase());
+
+ HANDLE handle;
+ NTSTATUS nt_status;
+ ULONG disposition = 0;
+ if (!RegistryPolicy::CreateKeyAction(
+ result, *ipc->client_info, *name, attributes, root, desired_access,
+ title_index, create_options, &handle, &nt_status, &disposition)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ // Return operation status on the IPC.
+ ipc->return_info.extended[0].unsigned_int = disposition;
+ ipc->return_info.nt_status = nt_status;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool RegistryDispatcher::NtOpenKey(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ HANDLE root,
+ uint32_t desired_access) {
+ base::win::ScopedHandle root_handle;
+ std::wstring real_path = *name;
+
+ // If there is a root directory, we need to duplicate the handle to make
+ // it valid in this process.
+ if (root) {
+ if (!::DuplicateHandle(ipc->client_info->process, root,
+ ::GetCurrentProcess(), &root, 0, false,
+ DUPLICATE_SAME_ACCESS))
+ return false;
+ root_handle.Set(root);
+ }
+
+ if (!GetCompletePath(root, *name, &real_path))
+ return false;
+
+ const wchar_t* regname = real_path.c_str();
+ CountedParameterSet<OpenKey> params;
+ params[OpenKey::NAME] = ParamPickerMake(regname);
+ params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
+
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::NTOPENKEY, params.GetBase());
+ HANDLE handle;
+ NTSTATUS nt_status;
+ if (!RegistryPolicy::OpenKeyAction(result, *ipc->client_info, *name,
+ attributes, root, desired_access, &handle,
+ &nt_status)) {
+ ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
+ return true;
+ }
+
+ // Return operation status on the IPC.
+ ipc->return_info.nt_status = nt_status;
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/registry_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/registry_dispatcher.h
new file mode 100644
index 0000000000..c23b95098b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/registry_dispatcher.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_REGISTRY_DISPATCHER_H_
+#define SANDBOX_SRC_REGISTRY_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles registry-related IPC calls.
+class RegistryDispatcher : public Dispatcher {
+ public:
+ explicit RegistryDispatcher(PolicyBase* policy_base);
+ ~RegistryDispatcher() override {}
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to NtCreateKey in the target.
+ bool NtCreateKey(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ HANDLE root,
+ uint32_t desired_access,
+ uint32_t title_index,
+ uint32_t create_options);
+
+ // Processes IPC requests coming from calls to NtOpenKey in the target.
+ bool NtOpenKey(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t attributes,
+ HANDLE root,
+ uint32_t desired_access);
+
+ PolicyBase* policy_base_;
+ DISALLOW_COPY_AND_ASSIGN(RegistryDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_REGISTRY_DISPATCHER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/registry_interception.cc b/security/sandbox/chromium/sandbox/win/src/registry_interception.cc
new file mode 100644
index 0000000000..d8bb82949b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/registry_interception.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/registry_interception.h"
+
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+
+namespace sandbox {
+
+NTSTATUS WINAPI TargetNtCreateKey(NtCreateKeyFunction orig_CreateKey,
+ PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ ULONG title_index,
+ PUNICODE_STRING class_name,
+ ULONG create_options,
+ PULONG disposition) {
+ // Check if the process can create it first.
+ NTSTATUS status =
+ orig_CreateKey(key, desired_access, object_attributes, title_index,
+ class_name, create_options, disposition);
+ if (NT_SUCCESS(status))
+ return status;
+
+ if (STATUS_OBJECT_NAME_NOT_FOUND != status) {
+ mozilla::sandboxing::LogBlocked("NtCreateKey",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ }
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(key, sizeof(HANDLE), WRITE))
+ break;
+
+ if (disposition && !ValidParameter(disposition, sizeof(ULONG), WRITE))
+ break;
+
+ // At this point we don't support class_name.
+ if (class_name && class_name->Buffer && class_name->Length)
+ break;
+
+ // We don't support creating link keys, volatile keys and backup/restore.
+ if (create_options)
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes = 0;
+ HANDLE root_directory = 0;
+ NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+ &root_directory);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ uint32_t desired_access_uint32 = desired_access;
+ CountedParameterSet<OpenKey> params;
+ params[OpenKey::ACCESS] = ParamPickerMake(desired_access_uint32);
+
+ bool query_broker = false;
+ {
+ std::unique_ptr<wchar_t, NtAllocDeleter> full_name;
+ const wchar_t* name_ptr = name.get();
+ const wchar_t* full_name_ptr = nullptr;
+
+ if (root_directory) {
+ ret = sandbox::AllocAndGetFullPath(root_directory, name.get(),
+ &full_name);
+ if (!NT_SUCCESS(ret) || !full_name)
+ break;
+ full_name_ptr = full_name.get();
+ params[OpenKey::NAME] = ParamPickerMake(full_name_ptr);
+ } else {
+ params[OpenKey::NAME] = ParamPickerMake(name_ptr);
+ }
+
+ query_broker = QueryBroker(IpcTag::NTCREATEKEY, params.GetBase());
+ }
+
+ if (!query_broker)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+
+ ResultCode code = CrossCall(ipc, IpcTag::NTCREATEKEY, name.get(),
+ attributes, root_directory, desired_access,
+ title_index, create_options, &answer);
+
+ if (SBOX_ALL_OK != code)
+ break;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ // TODO(nsylvain): We should return answer.nt_status here instead
+ // of status. We can do this only after we checked the policy.
+ // otherwise we will returns ACCESS_DENIED for all paths
+ // that are not specified by a policy, even though your token allows
+ // access to that path, and the original call had a more meaningful
+ // error. Bug 4369
+ break;
+
+ __try {
+ *key = answer.handle;
+
+ if (disposition)
+ *disposition = answer.extended[0].unsigned_int;
+
+ status = answer.nt_status;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ mozilla::sandboxing::LogAllowed("NtCreateKey",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI CommonNtOpenKey(NTSTATUS status,
+ PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes) {
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(key, sizeof(HANDLE), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes;
+ HANDLE root_directory;
+ NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
+ &root_directory);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ uint32_t desired_access_uint32 = desired_access;
+ CountedParameterSet<OpenKey> params;
+ params[OpenKey::ACCESS] = ParamPickerMake(desired_access_uint32);
+
+ bool query_broker = false;
+ {
+ std::unique_ptr<wchar_t, NtAllocDeleter> full_name;
+ const wchar_t* name_ptr = name.get();
+ const wchar_t* full_name_ptr = nullptr;
+
+ if (root_directory) {
+ ret = sandbox::AllocAndGetFullPath(root_directory, name.get(),
+ &full_name);
+ if (!NT_SUCCESS(ret) || !full_name)
+ break;
+ full_name_ptr = full_name.get();
+ params[OpenKey::NAME] = ParamPickerMake(full_name_ptr);
+ } else {
+ params[OpenKey::NAME] = ParamPickerMake(name_ptr);
+ }
+
+ query_broker = QueryBroker(IpcTag::NTOPENKEY, params.GetBase());
+ }
+
+ if (!query_broker)
+ break;
+
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::NTOPENKEY, name.get(), attributes,
+ root_directory, desired_access, &answer);
+
+ if (SBOX_ALL_OK != code)
+ break;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ // TODO(nsylvain): We should return answer.nt_status here instead
+ // of status. We can do this only after we checked the policy.
+ // otherwise we will returns ACCESS_DENIED for all paths
+ // that are not specified by a policy, even though your token allows
+ // access to that path, and the original call had a more meaningful
+ // error. Bug 4369
+ break;
+
+ __try {
+ *key = answer.handle;
+ status = answer.nt_status;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ mozilla::sandboxing::LogAllowed("NtOpenKey[Ex]",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI TargetNtOpenKey(NtOpenKeyFunction orig_OpenKey,
+ PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes) {
+ // Check if the process can open it first.
+ NTSTATUS status = orig_OpenKey(key, desired_access, object_attributes);
+ if (NT_SUCCESS(status))
+ return status;
+
+ if (STATUS_OBJECT_NAME_NOT_FOUND != status) {
+ mozilla::sandboxing::LogBlocked("NtOpenKey",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ }
+
+ return CommonNtOpenKey(status, key, desired_access, object_attributes);
+}
+
+NTSTATUS WINAPI TargetNtOpenKeyEx(NtOpenKeyExFunction orig_OpenKeyEx,
+ PHANDLE key,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ ULONG open_options) {
+ // Check if the process can open it first.
+ NTSTATUS status =
+ orig_OpenKeyEx(key, desired_access, object_attributes, open_options);
+
+ // We do not support open_options at this time. The 2 current known values
+ // are REG_OPTION_CREATE_LINK, to open a symbolic link, and
+ // REG_OPTION_BACKUP_RESTORE to open the key with special privileges.
+ if (NT_SUCCESS(status) || open_options != 0)
+ return status;
+
+ if (STATUS_OBJECT_NAME_NOT_FOUND != status) {
+ mozilla::sandboxing::LogBlocked("NtOpenKeyEx",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ }
+
+ return CommonNtOpenKey(status, key, desired_access, object_attributes);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/registry_interception.h b/security/sandbox/chromium/sandbox/win/src/registry_interception.h
new file mode 100644
index 0000000000..f47e56ce39
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/registry_interception.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_REGISTRY_INTERCEPTION_H_
+#define SANDBOX_WIN_SRC_REGISTRY_INTERCEPTION_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtCreateKey on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtCreateKey(
+ NtCreateKeyFunction orig_CreateKey, PHANDLE key, ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes, ULONG title_index,
+ PUNICODE_STRING class_name, ULONG create_options, PULONG disposition);
+
+// Interception of NtOpenKey on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKey(
+ NtOpenKeyFunction orig_OpenKey, PHANDLE key, ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes);
+
+// Interception of NtOpenKeyEx on the child process.
+// It should never be called directly
+SANDBOX_INTERCEPT NTSTATUS WINAPI TargetNtOpenKeyEx(
+ NtOpenKeyExFunction orig_OpenKeyEx, PHANDLE key, ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes, ULONG open_options);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_REGISTRY_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/registry_policy.cc b/security/sandbox/chromium/sandbox/win/src/registry_policy.cc
new file mode 100644
index 0000000000..212ff713c4
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/registry_policy.cc
@@ -0,0 +1,230 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/registry_policy.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+static const uint32_t kAllowedRegFlags =
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY | KEY_READ |
+ GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL | KEY_WOW64_64KEY |
+ KEY_WOW64_32KEY;
+
+// Opens the key referenced by |obj_attributes| with |access| and
+// checks what permission was given. Remove the WRITE flags and update
+// |access| with the new value.
+NTSTATUS TranslateMaximumAllowed(OBJECT_ATTRIBUTES* obj_attributes,
+ DWORD* access) {
+ NtOpenKeyFunction NtOpenKey = nullptr;
+ ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
+
+ NtCloseFunction NtClose = nullptr;
+ ResolveNTFunctionPtr("NtClose", &NtClose);
+
+ NtQueryObjectFunction NtQueryObject = nullptr;
+ ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
+
+ // Open the key.
+ HANDLE handle;
+ NTSTATUS status = NtOpenKey(&handle, *access, obj_attributes);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ OBJECT_BASIC_INFORMATION info = {0};
+ status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info),
+ nullptr);
+ CHECK(NT_SUCCESS(NtClose(handle)));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ *access = info.GrantedAccess & kAllowedRegFlags;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NtCreateKeyInTarget(HANDLE* target_key_handle,
+ ACCESS_MASK desired_access,
+ OBJECT_ATTRIBUTES* obj_attributes,
+ ULONG title_index,
+ UNICODE_STRING* class_name,
+ ULONG create_options,
+ ULONG* disposition,
+ HANDLE target_process) {
+ *target_key_handle = nullptr;
+ NtCreateKeyFunction NtCreateKey = nullptr;
+ ResolveNTFunctionPtr("NtCreateKey", &NtCreateKey);
+
+ if (MAXIMUM_ALLOWED & desired_access) {
+ NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
+ if (!NT_SUCCESS(status))
+ return STATUS_ACCESS_DENIED;
+ }
+
+ HANDLE local_handle = INVALID_HANDLE_VALUE;
+ NTSTATUS status =
+ NtCreateKey(&local_handle, desired_access, obj_attributes, title_index,
+ class_name, create_options, disposition);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, target_process,
+ target_key_handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS NtOpenKeyInTarget(HANDLE* target_key_handle,
+ ACCESS_MASK desired_access,
+ OBJECT_ATTRIBUTES* obj_attributes,
+ HANDLE target_process) {
+ *target_key_handle = nullptr;
+ NtOpenKeyFunction NtOpenKey = nullptr;
+ ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
+
+ if (MAXIMUM_ALLOWED & desired_access) {
+ NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
+ if (!NT_SUCCESS(status))
+ return STATUS_ACCESS_DENIED;
+ }
+
+ HANDLE local_handle = INVALID_HANDLE_VALUE;
+ NTSTATUS status = NtOpenKey(&local_handle, desired_access, obj_attributes);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle, target_process,
+ target_key_handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ return STATUS_SUCCESS;
+}
+
+} // namespace
+
+namespace sandbox {
+
+bool RegistryPolicy::GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ std::wstring resolved_name(name);
+ if (resolved_name.empty()) {
+ return false;
+ }
+
+ if (!ResolveRegistryName(resolved_name, &resolved_name))
+ return false;
+
+ name = resolved_name.c_str();
+
+ EvalResult result = ASK_BROKER;
+
+ PolicyRule open(result);
+ PolicyRule create(result);
+
+ switch (semantics) {
+ case TargetPolicy::REG_ALLOW_READONLY: {
+ // We consider all flags that are not known to be readonly as potentially
+ // used for write. Here we also support MAXIMUM_ALLOWED, but we are going
+ // to expand it to read-only before the call.
+ uint32_t restricted_flags = ~(kAllowedRegFlags | MAXIMUM_ALLOWED);
+ open.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
+ create.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
+ break;
+ }
+ case TargetPolicy::REG_ALLOW_ANY: {
+ break;
+ }
+ default: {
+ NOTREACHED();
+ return false;
+ }
+ }
+
+ if (!create.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
+ !policy->AddRule(IpcTag::NTCREATEKEY, &create)) {
+ return false;
+ }
+
+ if (!open.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
+ !policy->AddRule(IpcTag::NTOPENKEY, &open)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool RegistryPolicy::CreateKeyAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& key,
+ uint32_t attributes,
+ HANDLE root_directory,
+ uint32_t desired_access,
+ uint32_t title_index,
+ uint32_t create_options,
+ HANDLE* handle,
+ NTSTATUS* nt_status,
+ ULONG* disposition) {
+ // The only action supported is ASK_BROKER which means create the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+
+ // We don't support creating link keys, volatile keys or backup/restore.
+ if (create_options) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+
+ UNICODE_STRING uni_name = {0};
+ OBJECT_ATTRIBUTES obj_attributes = {0};
+ InitObjectAttribs(key, attributes, root_directory, &obj_attributes, &uni_name,
+ nullptr);
+ *nt_status = NtCreateKeyInTarget(handle, desired_access, &obj_attributes,
+ title_index, nullptr, create_options,
+ disposition, client_info.process);
+ return true;
+}
+
+bool RegistryPolicy::OpenKeyAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& key,
+ uint32_t attributes,
+ HANDLE root_directory,
+ uint32_t desired_access,
+ HANDLE* handle,
+ NTSTATUS* nt_status) {
+ // The only action supported is ASK_BROKER which means open the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result) {
+ *nt_status = STATUS_ACCESS_DENIED;
+ return false;
+ }
+
+ UNICODE_STRING uni_name = {0};
+ OBJECT_ATTRIBUTES obj_attributes = {0};
+ InitObjectAttribs(key, attributes, root_directory, &obj_attributes, &uni_name,
+ nullptr);
+ *nt_status = NtOpenKeyInTarget(handle, desired_access, &obj_attributes,
+ client_info.process);
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/registry_policy.h b/security/sandbox/chromium/sandbox/win/src/registry_policy.h
new file mode 100644
index 0000000000..9a36932869
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/registry_policy.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_REGISTRY_POLICY_H__
+#define SANDBOX_SRC_REGISTRY_POLICY_H__
+
+#include <stdint.h>
+
+#include <string>
+
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+// This class centralizes most of the knowledge related to registry policy
+class RegistryPolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level
+ // policy rule for registry IO, in particular open or create actions.
+ static bool GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ // Performs the desired policy action on a create request with an
+ // API that is compatible with the IPC-received parameters.
+ static bool CreateKeyAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& key,
+ uint32_t attributes,
+ HANDLE root_directory,
+ uint32_t desired_access,
+ uint32_t title_index,
+ uint32_t create_options,
+ HANDLE* handle,
+ NTSTATUS* nt_status,
+ ULONG* disposition);
+
+ // Performs the desired policy action on an open request with an
+ // API that is compatible with the IPC-received parameters.
+ static bool OpenKeyAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& key,
+ uint32_t attributes,
+ HANDLE root_directory,
+ uint32_t desired_access,
+ HANDLE* handle,
+ NTSTATUS* nt_status);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_REGISTRY_POLICY_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/registry_policy_test.cc b/security/sandbox/chromium/sandbox/win/src/registry_policy_test.cc
new file mode 100644
index 0000000000..83ce586877
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/registry_policy_test.cc
@@ -0,0 +1,322 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <shlobj.h>
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/registry_policy.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static const DWORD kAllowedRegFlags = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS |
+ KEY_NOTIFY | KEY_READ | GENERIC_READ |
+ GENERIC_EXECUTE | READ_CONTROL;
+
+#define BINDNTDLL(name) \
+ name##Function name = reinterpret_cast<name##Function>( \
+ ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), #name))
+
+bool IsKeyOpenForRead(HKEY handle) {
+ BINDNTDLL(NtQueryObject);
+
+ OBJECT_BASIC_INFORMATION info = {0};
+ NTSTATUS status = NtQueryObject(handle, ObjectBasicInformation, &info,
+ sizeof(info), nullptr);
+
+ if (!NT_SUCCESS(status))
+ return false;
+
+ if ((info.GrantedAccess & (~kAllowedRegFlags)) != 0)
+ return false;
+ return true;
+}
+
+} // namespace
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int Reg_OpenKey(int argc, wchar_t** argv) {
+ if (argc != 4)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ REGSAM desired_access = 0;
+ ULONG options = 0;
+ if (wcscmp(argv[1], L"read") == 0) {
+ desired_access = KEY_READ;
+ } else if (wcscmp(argv[1], L"write") == 0) {
+ desired_access = KEY_ALL_ACCESS;
+ } else if (wcscmp(argv[1], L"link") == 0) {
+ options = REG_OPTION_CREATE_LINK;
+ desired_access = KEY_ALL_ACCESS;
+ } else {
+ desired_access = MAXIMUM_ALLOWED;
+ }
+
+ HKEY root = GetReservedKeyFromName(argv[2]);
+ HKEY key;
+ LRESULT result = 0;
+
+ if (wcscmp(argv[0], L"create") == 0)
+ result = ::RegCreateKeyEx(root, argv[3], 0, nullptr, options,
+ desired_access, nullptr, &key, nullptr);
+ else
+ result = ::RegOpenKeyEx(root, argv[3], 0, desired_access, &key);
+
+ if (ERROR_SUCCESS == result) {
+ if (MAXIMUM_ALLOWED == desired_access) {
+ if (!IsKeyOpenForRead(key)) {
+ ::RegCloseKey(key);
+ return SBOX_TEST_FAILED;
+ }
+ }
+ ::RegCloseKey(key);
+ return SBOX_TEST_SUCCEEDED;
+ } else if (ERROR_ACCESS_DENIED == result) {
+ return SBOX_TEST_DENIED;
+ }
+
+ return SBOX_TEST_FAILED;
+}
+
+TEST(RegistryPolicyTest, TestKeyAnyAccess) {
+ TestRunner runner;
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_LOCAL_MACHINE"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_ANY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Microsoft"));
+
+ // Tests read access on key allowed for read-write.
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(
+ L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software\\microsoft"));
+
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(
+ L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software\\microsoft"));
+
+ if (::IsUserAnAdmin()) {
+ // Tests write access on key allowed for read-write.
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Reg_OpenKey create write HKEY_LOCAL_MACHINE "
+ L"software\\microsoft"));
+
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(
+ L"Reg_OpenKey open write HKEY_LOCAL_MACHINE software\\microsoft"));
+ }
+
+ // Tests subdirectory access on keys where we don't have subdirectory acess.
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"Reg_OpenKey create read "
+ L"HKEY_LOCAL_MACHINE software\\microsoft\\Windows"));
+
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(L"Reg_OpenKey open read "
+ L"HKEY_LOCAL_MACHINE software\\microsoft\\windows"));
+
+ // Tests to see if we can create keys where we dont have subdirectory access.
+ // This is denied.
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(
+ L"Reg_OpenKey create write "
+ L"HKEY_LOCAL_MACHINE software\\Microsoft\\google_unit_tests"));
+
+ RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Microsoft\\google_unit_tests");
+
+ // Tests if we need to handle differently the "\\" at the end.
+ // This is denied. We need to add both rules.
+ EXPECT_EQ(
+ SBOX_TEST_DENIED,
+ runner.RunTest(
+ L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software\\microsoft\\"));
+
+ EXPECT_EQ(
+ SBOX_TEST_DENIED,
+ runner.RunTest(
+ L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software\\microsoft\\"));
+}
+
+TEST(RegistryPolicyTest, TestKeyNoAccess) {
+ TestRunner runner;
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_LOCAL_MACHINE"));
+
+ // Tests read access where we don't have access at all.
+ EXPECT_EQ(
+ SBOX_TEST_DENIED,
+ runner.RunTest(L"Reg_OpenKey create read HKEY_LOCAL_MACHINE software"));
+
+ EXPECT_EQ(
+ SBOX_TEST_DENIED,
+ runner.RunTest(L"Reg_OpenKey open read HKEY_LOCAL_MACHINE software"));
+}
+
+TEST(RegistryPolicyTest, TestKeyReadOnlyAccess) {
+ TestRunner runner;
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_LOCAL_MACHINE"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
+
+ // Tests subdirectory acess on keys where we have subdirectory acess.
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Reg_OpenKey create read "
+ L"HKEY_LOCAL_MACHINE software\\Policies\\microsoft"));
+
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Reg_OpenKey open read "
+ L"HKEY_LOCAL_MACHINE software\\Policies\\microsoft"));
+
+ // Tests to see if we can create keys where we have subdirectory access.
+ EXPECT_EQ(SBOX_TEST_DENIED,
+ runner.RunTest(
+ L"Reg_OpenKey create write "
+ L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
+
+ RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Policies\\google_unit_tests");
+}
+
+TEST(RegistryPolicyTest, TestKeyAllAccessSubDir) {
+ TestRunner runner;
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_LOCAL_MACHINE"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_ANY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_ANY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
+
+ if (::IsUserAnAdmin()) {
+ // Tests to see if we can create keys where we have subdirectory access.
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(
+ L"Reg_OpenKey create write "
+ L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
+
+ RegDeleteKey(HKEY_LOCAL_MACHINE, L"software\\Policies\\google_unit_tests");
+ }
+}
+
+TEST(RegistryPolicyTest, TestKeyCreateLink) {
+ TestRunner runner;
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_LOCAL_MACHINE"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_ANY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Policies"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_ANY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Policies\\*"));
+
+ // Tests to see if we can create a registry link key.
+ // NOTE: In theory here we should make sure to check for SBOX_TEST_DENIED
+ // instead of !SBOX_TEST_SUCCEEDED, but unfortunately the result is not
+ // access denied. Internally RegCreateKeyEx (At least on Vista 64) tries to
+ // create the link, and we return successfully access denied, then, it
+ // decides to try to break the path in multiple chunks, and create the links
+ // one by one. In this scenario, it tries to create "HKLM\Software" as a
+ // link key, which obviously fail with STATUS_OBJECT_NAME_COLLISION, and
+ // this is what is returned to the user.
+ EXPECT_NE(SBOX_TEST_SUCCEEDED,
+ runner.RunTest(
+ L"Reg_OpenKey create link "
+ L"HKEY_LOCAL_MACHINE software\\Policies\\google_unit_tests"));
+
+ // In case our code fails, and the call works, we need to delete the new
+ // link. There is no api for this, so we need to use the NT call.
+ HKEY key = nullptr;
+ LRESULT result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ L"software\\Policies\\google_unit_tests",
+ REG_OPTION_OPEN_LINK, MAXIMUM_ALLOWED, &key);
+
+ if (!result) {
+ HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
+ NtDeleteKeyFunction NtDeleteKey = reinterpret_cast<NtDeleteKeyFunction>(
+ GetProcAddress(ntdll, "NtDeleteKey"));
+ NtDeleteKey(key);
+ }
+}
+
+TEST(RegistryPolicyTest, TestKeyReadOnlyHKCU) {
+ TestRunner runner;
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_CURRENT_USER"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_CURRENT_USER\\Software"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_USERS\\.default"));
+
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_READONLY,
+ L"HKEY_USERS\\.default\\software"));
+
+ // Tests read access where we only have read-only access.
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Reg_OpenKey create read HKEY_CURRENT_USER software"));
+
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(L"Reg_OpenKey open read HKEY_CURRENT_USER software"));
+
+ // Tests write access where we only have read-only acess.
+ EXPECT_EQ(
+ SBOX_TEST_DENIED,
+ runner.RunTest(L"Reg_OpenKey create write HKEY_CURRENT_USER software"));
+
+ EXPECT_EQ(
+ SBOX_TEST_DENIED,
+ runner.RunTest(L"Reg_OpenKey open write HKEY_CURRENT_USER software"));
+
+ // Tests maximum allowed access where we only have read-only access.
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(
+ L"Reg_OpenKey create maximum_allowed HKEY_CURRENT_USER software"));
+
+ EXPECT_EQ(
+ SBOX_TEST_SUCCEEDED,
+ runner.RunTest(
+ L"Reg_OpenKey open maximum_allowed HKEY_CURRENT_USER software"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/resolver.cc b/security/sandbox/chromium/sandbox/win/src/resolver.cc
new file mode 100644
index 0000000000..6ed20e9b51
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/resolver.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/resolver.h"
+
+#include <stddef.h>
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+NTSTATUS ResolverThunk::Init(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes) {
+ if (!thunk_storage || 0 == storage_bytes || !target_module || !target_name)
+ return STATUS_INVALID_PARAMETER;
+
+ if (storage_bytes < GetThunkSize())
+ return STATUS_BUFFER_TOO_SMALL;
+
+ NTSTATUS ret = STATUS_SUCCESS;
+ if (!interceptor_entry_point) {
+ ret = ResolveInterceptor(interceptor_module, interceptor_name,
+ &interceptor_entry_point);
+ if (!NT_SUCCESS(ret))
+ return ret;
+ }
+
+ ret = ResolveTarget(target_module, target_name, &target_);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ interceptor_ = interceptor_entry_point;
+
+ return ret;
+}
+
+NTSTATUS ResolverThunk::ResolveInterceptor(const void* interceptor_module,
+ const char* interceptor_name,
+ const void** address) {
+ DCHECK_NT(address);
+ if (!interceptor_module)
+ return STATUS_INVALID_PARAMETER;
+
+ base::win::PEImage pe(interceptor_module);
+ if (!pe.VerifyMagic())
+ return STATUS_INVALID_IMAGE_FORMAT;
+
+ *address = reinterpret_cast<void*>(pe.GetProcAddress(interceptor_name));
+
+ if (!(*address))
+ return STATUS_PROCEDURE_NOT_FOUND;
+
+ return STATUS_SUCCESS;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/resolver.h b/security/sandbox/chromium/sandbox/win/src/resolver.h
new file mode 100644
index 0000000000..3ce427b74b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/resolver.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_RESOLVER_H_
+#define SANDBOX_WIN_SRC_RESOLVER_H_
+
+// Defines ResolverThunk, the interface for classes that perform interceptions.
+// For more details see
+// http://dev.chromium.org/developers/design-documents/sandbox .
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+// A resolver is the object in charge of performing the actual interception of
+// a function. There should be a concrete implementation of a resolver roughly
+// per type of interception.
+class ResolverThunk {
+ public:
+ ResolverThunk() {}
+ virtual ~ResolverThunk() {}
+
+ // Performs the actual interception of a function.
+ // target_name is an exported function from the module loaded at
+ // target_module, and must be replaced by interceptor_name, exported from
+ // interceptor_module. interceptor_entry_point can be provided instead of
+ // interceptor_name / interceptor_module.
+ // thunk_storage must point to a buffer on the child's address space, to hold
+ // the patch thunk, and related data. If provided, storage_used will receive
+ // the number of bytes used from thunk_storage.
+ //
+ // Example: (without error checking)
+ //
+ // size_t size = resolver.GetThunkSize();
+ // char* buffer = ::VirtualAllocEx(child_process, nullptr, size,
+ // MEM_COMMIT, PAGE_READWRITE);
+ // resolver.Setup(ntdll_module, nullptr, L"NtCreateFile", nullptr,
+ // &MyReplacementFunction, buffer, size, nullptr);
+ //
+ // In general, the idea is to allocate a single big buffer for all
+ // interceptions on the same dll, and call Setup n times.
+ // WARNING: This means that any data member that is specific to a single
+ // interception must be reset within this method.
+ virtual NTSTATUS Setup(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) = 0;
+
+ // Gets the address of function_name inside module (main exe).
+ virtual NTSTATUS ResolveInterceptor(const void* module,
+ const char* function_name,
+ const void** address);
+
+ // Gets the address of an exported function_name inside module.
+ virtual NTSTATUS ResolveTarget(const void* module,
+ const char* function_name,
+ void** address);
+
+ // Gets the required buffer size for this type of thunk.
+ virtual size_t GetThunkSize() const = 0;
+
+ protected:
+ // Performs basic initialization on behalf of a concrete instance of a
+ // resolver. That is, parameter validation and resolution of the target
+ // and the interceptor into the member variables.
+ //
+ // target_name is an exported function from the module loaded at
+ // target_module, and must be replaced by interceptor_name, exported from
+ // interceptor_module. interceptor_entry_point can be provided instead of
+ // interceptor_name / interceptor_module.
+ // thunk_storage must point to a buffer on the child's address space, to hold
+ // the patch thunk, and related data.
+ virtual NTSTATUS Init(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes);
+
+ // Gets the required buffer size for the internal part of the thunk.
+ size_t GetInternalThunkSize() const;
+
+ // Initializes the internal part of the thunk.
+ // interceptor is the function to be called instead of original_function.
+ bool SetInternalThunk(void* storage, size_t storage_bytes,
+ const void* original_function, const void* interceptor);
+
+ // Holds the resolved interception target.
+ void* target_;
+ // Holds the resolved interception interceptor.
+ const void* interceptor_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResolverThunk);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_RESOLVER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/resolver_32.cc b/security/sandbox/chromium/sandbox/win/src/resolver_32.cc
new file mode 100644
index 0000000000..ff78f53fb1
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/resolver_32.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/resolver.h"
+
+#include <stddef.h>
+
+// For placement new. This file must not depend on the CRT at runtime, but
+// placement operator new is inline.
+#include <new>
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+#pragma pack(push, 1)
+struct InternalThunk {
+ // This struct contains roughly the following code:
+ // sub esp, 8 // Create working space
+ // push edx // Save register
+ // mov edx, [esp + 0xc] // Get return adddress
+ // mov [esp + 8], edx // Store return address
+ // mov dword ptr [esp + 0xc], 0x7c401200 // Store extra argument
+ // mov dword ptr [esp + 4], 0x40010203 // Store address to jump to
+ // pop edx // Restore register
+ // ret // Jump to interceptor
+ //
+ // This code only modifies esp and eip so it must work with to normal calling
+ // convention. It is assembled as:
+ //
+ // 00 83ec08 sub esp,8
+ // 03 52 push edx
+ // 04 8b54240c mov edx,dword ptr [esp + 0Ch]
+ // 08 89542408 mov dword ptr [esp + 8], edx
+ // 0c c744240c0012407c mov dword ptr [esp + 0Ch], 7C401200h
+ // 14 c744240403020140 mov dword ptr [esp + 4], 40010203h
+ // 1c 5a pop edx
+ // 1d c3 ret
+ InternalThunk() {
+ opcodes_1 = 0x5208ec83;
+ opcodes_2 = 0x0c24548b;
+ opcodes_3 = 0x08245489;
+ opcodes_4 = 0x0c2444c7;
+ opcodes_5 = 0x042444c7;
+ opcodes_6 = 0xc35a;
+ extra_argument = 0;
+ interceptor_function = 0;
+ }
+ ULONG opcodes_1; // = 0x5208ec83
+ ULONG opcodes_2; // = 0x0c24548b
+ ULONG opcodes_3; // = 0x08245489
+ ULONG opcodes_4; // = 0x0c2444c7
+ ULONG extra_argument;
+ ULONG opcodes_5; // = 0x042444c7
+ ULONG interceptor_function;
+ USHORT opcodes_6; // = 0xc35a
+};
+#pragma pack(pop)
+
+} // namespace
+
+namespace sandbox {
+
+bool ResolverThunk::SetInternalThunk(void* storage,
+ size_t storage_bytes,
+ const void* original_function,
+ const void* interceptor) {
+ if (storage_bytes < sizeof(InternalThunk))
+ return false;
+
+ InternalThunk* thunk = new (storage) InternalThunk;
+
+#pragma warning(push)
+#pragma warning(disable : 4311)
+ // These casts generate warnings because they are 32 bit specific.
+ thunk->interceptor_function = reinterpret_cast<ULONG>(interceptor);
+ thunk->extra_argument = reinterpret_cast<ULONG>(original_function);
+#pragma warning(pop)
+
+ return true;
+}
+
+size_t ResolverThunk::GetInternalThunkSize() const {
+ return sizeof(InternalThunk);
+}
+
+NTSTATUS ResolverThunk::ResolveTarget(const void* module,
+ const char* function_name,
+ void** address) {
+ const void** casted = const_cast<const void**>(address);
+ return ResolverThunk::ResolveInterceptor(module, function_name, casted);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/resolver_64.cc b/security/sandbox/chromium/sandbox/win/src/resolver_64.cc
new file mode 100644
index 0000000000..573b2bc3a9
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/resolver_64.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/resolver.h"
+
+#include <stddef.h>
+
+// For placement new. This file must not depend on the CRT at runtime, but
+// placement operator new is inline.
+#include <new>
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+#if defined(_M_X64)
+
+const USHORT kMovRax = 0xB848;
+const USHORT kJmpRax = 0xe0ff;
+
+#pragma pack(push, 1)
+struct InternalThunk {
+ // This struct contains roughly the following code:
+ // 01 48b8f0debc9a78563412 mov rax,123456789ABCDEF0h
+ // ff e0 jmp rax
+ //
+ // The code modifies rax, but that's fine for x64 ABI.
+
+ InternalThunk() {
+ mov_rax = kMovRax;
+ jmp_rax = kJmpRax;
+ interceptor_function = 0;
+ }
+ USHORT mov_rax; // = 48 B8
+ ULONG_PTR interceptor_function;
+ USHORT jmp_rax; // = ff e0
+};
+#pragma pack(pop)
+
+#elif defined(_M_ARM64)
+
+const ULONG kLdrX16Pc4 = 0x58000050;
+const ULONG kBrX16 = 0xD61F0200;
+
+#pragma pack(push, 4)
+struct InternalThunk {
+ // This struct contains roughly the following code:
+ // 00 58000050 ldr x16, pc+4
+ // 04 D61F0200 br x16
+ // 08 123456789ABCDEF0H
+
+ InternalThunk() {
+ ldr_x16_pc4 = kLdrX16Pc4;
+ br_x16 = kBrX16;
+ interceptor_function = 0;
+ }
+ ULONG ldr_x16_pc4;
+ ULONG br_x16;
+ ULONG_PTR interceptor_function;
+};
+#pragma pack(pop)
+#else
+#error "Unsupported Windows 64-bit Arch"
+#endif
+
+} // namespace.
+
+namespace sandbox {
+
+size_t ResolverThunk::GetInternalThunkSize() const {
+ return sizeof(InternalThunk);
+}
+
+bool ResolverThunk::SetInternalThunk(void* storage,
+ size_t storage_bytes,
+ const void* original_function,
+ const void* interceptor) {
+ if (storage_bytes < sizeof(InternalThunk))
+ return false;
+
+ InternalThunk* thunk = new (storage) InternalThunk;
+ thunk->interceptor_function = reinterpret_cast<ULONG_PTR>(interceptor);
+
+ return true;
+}
+
+NTSTATUS ResolverThunk::ResolveTarget(const void* module,
+ const char* function_name,
+ void** address) {
+ // We don't support sidestep & co.
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token.cc b/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
new file mode 100644
index 0000000000..5b20e88264
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
@@ -0,0 +1,432 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/restricted_token.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+// Wrapper for utility version to unwrap ScopedHandle.
+std::unique_ptr<BYTE[]> GetTokenInfo(const base::win::ScopedHandle& token,
+ TOKEN_INFORMATION_CLASS info_class,
+ DWORD* error) {
+ std::unique_ptr<BYTE[]> buffer;
+ *error = sandbox::GetTokenInformation(token.Get(), info_class, &buffer);
+ if (*error != ERROR_SUCCESS)
+ return nullptr;
+ return buffer;
+}
+
+} // namespace
+
+namespace sandbox {
+
+RestrictedToken::RestrictedToken()
+ : integrity_level_(INTEGRITY_LEVEL_LAST),
+ init_(false),
+ lockdown_default_dacl_(false) {}
+
+RestrictedToken::~RestrictedToken() {}
+
+DWORD RestrictedToken::Init(const HANDLE effective_token) {
+ if (init_)
+ return ERROR_ALREADY_INITIALIZED;
+
+ HANDLE temp_token;
+ if (effective_token) {
+ // We duplicate the handle to be able to use it even if the original handle
+ // is closed.
+ if (!::DuplicateHandle(::GetCurrentProcess(), effective_token,
+ ::GetCurrentProcess(), &temp_token, 0, false,
+ DUPLICATE_SAME_ACCESS)) {
+ return ::GetLastError();
+ }
+ } else {
+ if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+ &temp_token)) {
+ return ::GetLastError();
+ }
+ }
+ effective_token_.Set(temp_token);
+
+ init_ = true;
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::GetRestrictedToken(
+ base::win::ScopedHandle* token) const {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ size_t deny_size = sids_for_deny_only_.size();
+ size_t restrict_size = sids_to_restrict_.size();
+ size_t privileges_size = privileges_to_disable_.size();
+
+ SID_AND_ATTRIBUTES* deny_only_array = nullptr;
+ if (deny_size) {
+ deny_only_array = new SID_AND_ATTRIBUTES[deny_size];
+
+ for (unsigned int i = 0; i < sids_for_deny_only_.size(); ++i) {
+ deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
+ deny_only_array[i].Sid = sids_for_deny_only_[i].GetPSID();
+ }
+ }
+
+ SID_AND_ATTRIBUTES* sids_to_restrict_array = nullptr;
+ if (restrict_size) {
+ sids_to_restrict_array = new SID_AND_ATTRIBUTES[restrict_size];
+
+ for (unsigned int i = 0; i < restrict_size; ++i) {
+ sids_to_restrict_array[i].Attributes = 0;
+ sids_to_restrict_array[i].Sid = sids_to_restrict_[i].GetPSID();
+ }
+ }
+
+ LUID_AND_ATTRIBUTES* privileges_to_disable_array = nullptr;
+ if (privileges_size) {
+ privileges_to_disable_array = new LUID_AND_ATTRIBUTES[privileges_size];
+
+ for (unsigned int i = 0; i < privileges_size; ++i) {
+ privileges_to_disable_array[i].Attributes = 0;
+ privileges_to_disable_array[i].Luid = privileges_to_disable_[i];
+ }
+ }
+
+ bool result = true;
+ HANDLE new_token_handle = nullptr;
+ if (deny_size || restrict_size || privileges_size) {
+ result = ::CreateRestrictedToken(
+ effective_token_.Get(), 0, static_cast<DWORD>(deny_size),
+ deny_only_array, static_cast<DWORD>(privileges_size),
+ privileges_to_disable_array, static_cast<DWORD>(restrict_size),
+ sids_to_restrict_array, &new_token_handle);
+ } else {
+ // Duplicate the token even if it's not modified at this point
+ // because any subsequent changes to this token would also affect the
+ // current process.
+ result = ::DuplicateTokenEx(effective_token_.Get(), TOKEN_ALL_ACCESS,
+ nullptr, SecurityIdentification, TokenPrimary,
+ &new_token_handle);
+ }
+ auto last_error = ::GetLastError();
+
+ if (deny_only_array)
+ delete[] deny_only_array;
+
+ if (sids_to_restrict_array)
+ delete[] sids_to_restrict_array;
+
+ if (privileges_to_disable_array)
+ delete[] privileges_to_disable_array;
+
+ if (!result)
+ return last_error;
+
+ base::win::ScopedHandle new_token(new_token_handle);
+
+ if (lockdown_default_dacl_) {
+ // Don't add Restricted sid and also remove logon sid access.
+ if (!RevokeLogonSidFromDefaultDacl(new_token.Get()))
+ return ::GetLastError();
+ } else {
+ // Modify the default dacl on the token to contain Restricted.
+ if (!AddSidToDefaultDacl(new_token.Get(), WinRestrictedCodeSid,
+ GRANT_ACCESS, GENERIC_ALL)) {
+ return ::GetLastError();
+ }
+ }
+
+ for (const auto& default_dacl_sid : sids_for_default_dacl_) {
+ if (!AddSidToDefaultDacl(new_token.Get(), std::get<0>(default_dacl_sid),
+ std::get<1>(default_dacl_sid),
+ std::get<2>(default_dacl_sid))) {
+ return ::GetLastError();
+ }
+ }
+
+ // Add user to default dacl.
+ if (!AddUserSidToDefaultDacl(new_token.Get(), GENERIC_ALL))
+ return ::GetLastError();
+
+ DWORD error = SetTokenIntegrityLevel(new_token.Get(), integrity_level_);
+ if (ERROR_SUCCESS != error)
+ return error;
+
+ HANDLE token_handle;
+ if (!::DuplicateHandle(::GetCurrentProcess(), new_token.Get(),
+ ::GetCurrentProcess(), &token_handle, TOKEN_ALL_ACCESS,
+ false, // Don't inherit.
+ 0)) {
+ return ::GetLastError();
+ }
+
+ token->Set(token_handle);
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::GetRestrictedTokenForImpersonation(
+ base::win::ScopedHandle* token) const {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ base::win::ScopedHandle restricted_token;
+ DWORD err_code = GetRestrictedToken(&restricted_token);
+ if (ERROR_SUCCESS != err_code)
+ return err_code;
+
+ HANDLE impersonation_token_handle;
+ if (!::DuplicateToken(restricted_token.Get(), SecurityImpersonation,
+ &impersonation_token_handle)) {
+ return ::GetLastError();
+ }
+ base::win::ScopedHandle impersonation_token(impersonation_token_handle);
+
+ HANDLE token_handle;
+ if (!::DuplicateHandle(::GetCurrentProcess(), impersonation_token.Get(),
+ ::GetCurrentProcess(), &token_handle, TOKEN_ALL_ACCESS,
+ false, // Don't inherit.
+ 0)) {
+ return ::GetLastError();
+ }
+
+ token->Set(token_handle);
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::AddAllSidsForDenyOnly(std::vector<Sid>* exceptions) {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ DWORD error;
+ std::unique_ptr<BYTE[]> buffer =
+ GetTokenInfo(effective_token_, TokenGroups, &error);
+
+ if (!buffer)
+ return error;
+
+ TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
+
+ // Build the list of the deny only group SIDs
+ for (unsigned int i = 0; i < token_groups->GroupCount; ++i) {
+ if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
+ (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0) {
+ bool should_ignore = false;
+ if (exceptions) {
+ for (unsigned int j = 0; j < exceptions->size(); ++j) {
+ if (::EqualSid((*exceptions)[j].GetPSID(),
+ token_groups->Groups[i].Sid)) {
+ should_ignore = true;
+ break;
+ }
+ }
+ }
+ if (!should_ignore) {
+ sids_for_deny_only_.push_back(
+ reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
+ }
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::AddSidForDenyOnly(const Sid& sid) {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ sids_for_deny_only_.push_back(sid);
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::AddUserSidForDenyOnly() {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+ std::unique_ptr<BYTE[]> buffer(new BYTE[size]);
+ TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(buffer.get());
+
+ bool result = ::GetTokenInformation(effective_token_.Get(), TokenUser,
+ token_user, size, &size);
+
+ if (!result)
+ return ::GetLastError();
+
+ Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
+ sids_for_deny_only_.push_back(user);
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::DeleteAllPrivileges(
+ const std::vector<std::wstring>* exceptions) {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ DWORD error;
+ std::unique_ptr<BYTE[]> buffer =
+ GetTokenInfo(effective_token_, TokenPrivileges, &error);
+
+ if (!buffer)
+ return error;
+
+ TOKEN_PRIVILEGES* token_privileges =
+ reinterpret_cast<TOKEN_PRIVILEGES*>(buffer.get());
+
+ // Build the list of privileges to disable
+ for (unsigned int i = 0; i < token_privileges->PrivilegeCount; ++i) {
+ bool should_ignore = false;
+ if (exceptions) {
+ for (unsigned int j = 0; j < exceptions->size(); ++j) {
+ LUID luid = {0};
+ ::LookupPrivilegeValue(nullptr, (*exceptions)[j].c_str(), &luid);
+ if (token_privileges->Privileges[i].Luid.HighPart == luid.HighPart &&
+ token_privileges->Privileges[i].Luid.LowPart == luid.LowPart) {
+ should_ignore = true;
+ break;
+ }
+ }
+ }
+ if (!should_ignore) {
+ privileges_to_disable_.push_back(token_privileges->Privileges[i].Luid);
+ }
+ }
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::DeletePrivilege(const wchar_t* privilege) {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ LUID luid = {0};
+ if (LookupPrivilegeValue(nullptr, privilege, &luid))
+ privileges_to_disable_.push_back(luid);
+ else
+ return ::GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::AddRestrictingSid(const Sid& sid) {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ sids_to_restrict_.push_back(sid); // No attributes
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::AddRestrictingSidLogonSession() {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ DWORD error;
+ std::unique_ptr<BYTE[]> buffer =
+ GetTokenInfo(effective_token_, TokenGroups, &error);
+
+ if (!buffer)
+ return error;
+
+ TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
+
+ SID* logon_sid = nullptr;
+ for (unsigned int i = 0; i < token_groups->GroupCount; ++i) {
+ if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) != 0) {
+ logon_sid = static_cast<SID*>(token_groups->Groups[i].Sid);
+ break;
+ }
+ }
+
+ if (logon_sid)
+ sids_to_restrict_.push_back(logon_sid);
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::AddRestrictingSidCurrentUser() {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+ std::unique_ptr<BYTE[]> buffer(new BYTE[size]);
+ TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(buffer.get());
+
+ bool result = ::GetTokenInformation(effective_token_.Get(), TokenUser,
+ token_user, size, &size);
+
+ if (!result)
+ return ::GetLastError();
+
+ Sid user = reinterpret_cast<SID*>(token_user->User.Sid);
+ sids_to_restrict_.push_back(user);
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::AddRestrictingSidAllSids() {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ // Add the current user to the list.
+ DWORD error = AddRestrictingSidCurrentUser();
+ if (ERROR_SUCCESS != error)
+ return error;
+
+ std::unique_ptr<BYTE[]> buffer =
+ GetTokenInfo(effective_token_, TokenGroups, &error);
+
+ if (!buffer)
+ return error;
+
+ TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer.get());
+
+ // Build the list of restricting sids from all groups.
+ for (unsigned int i = 0; i < token_groups->GroupCount; ++i) {
+ if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0)
+ AddRestrictingSid(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
+ }
+
+ return ERROR_SUCCESS;
+}
+
+DWORD RestrictedToken::SetIntegrityLevel(IntegrityLevel integrity_level) {
+ integrity_level_ = integrity_level;
+ return ERROR_SUCCESS;
+}
+
+void RestrictedToken::SetLockdownDefaultDacl() {
+ lockdown_default_dacl_ = true;
+}
+
+DWORD RestrictedToken::AddDefaultDaclSid(const Sid& sid,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access) {
+ DCHECK(init_);
+ if (!init_)
+ return ERROR_NO_TOKEN;
+
+ sids_for_default_dacl_.push_back(std::make_tuple(sid, access_mode, access));
+ return ERROR_SUCCESS;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token.h b/security/sandbox/chromium/sandbox/win/src/restricted_token.h
new file mode 100644
index 0000000000..c89427af14
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_RESTRICTED_TOKEN_H_
+#define SANDBOX_SRC_RESTRICTED_TOKEN_H_
+
+#include <windows.h>
+
+#include <tuple>
+#include <vector>
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/security_level.h"
+#include "sandbox/win/src/sid.h"
+
+// Flags present in the Group SID list. These 2 flags are new in Windows Vista
+#ifndef SE_GROUP_INTEGRITY
+#define SE_GROUP_INTEGRITY (0x00000020L)
+#endif
+#ifndef SE_GROUP_INTEGRITY_ENABLED
+#define SE_GROUP_INTEGRITY_ENABLED (0x00000040L)
+#endif
+
+namespace sandbox {
+
+// Handles the creation of a restricted token using the effective token or
+// any token handle.
+// Sample usage:
+// RestrictedToken restricted_token;
+// DWORD err_code = restricted_token.Init(nullptr); // Use the current
+// // effective token
+// if (ERROR_SUCCESS != err_code) {
+// // handle error.
+// }
+//
+// restricted_token.AddRestrictingSid(ATL::Sids::Users().GetPSID());
+// base::win::ScopedHandle token_handle;
+// err_code = restricted_token.GetRestrictedToken(&token_handle);
+// if (ERROR_SUCCESS != err_code) {
+// // handle error.
+// }
+// [...]
+class RestrictedToken {
+ public:
+ // Init() has to be called before calling any other method in the class.
+ RestrictedToken();
+ ~RestrictedToken();
+
+ // Initializes the RestrictedToken object with effective_token.
+ // If effective_token is nullptr, it initializes the RestrictedToken object
+ // with the effective token of the current process.
+ DWORD Init(HANDLE effective_token);
+
+ // Creates a restricted token.
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD GetRestrictedToken(base::win::ScopedHandle* token) const;
+
+ // Creates a restricted token and uses this new token to create a new token
+ // for impersonation. Returns this impersonation token.
+ //
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ //
+ // The sample usage is the same as the GetRestrictedToken function.
+ DWORD GetRestrictedTokenForImpersonation(
+ base::win::ScopedHandle* token) const;
+
+ // Lists all sids in the token and mark them as Deny Only except for those
+ // present in the exceptions parameter. If there is no exception needed,
+ // the caller can pass an empty list or nullptr for the exceptions
+ // parameter.
+ //
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ //
+ // Sample usage:
+ // std::vector<Sid> sid_exceptions;
+ // sid_exceptions.push_back(ATL::Sids::Users().GetPSID());
+ // sid_exceptions.push_back(ATL::Sids::World().GetPSID());
+ // restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
+ // Note: A Sid marked for Deny Only in a token cannot be used to grant
+ // access to any resource. It can only be used to deny access.
+ DWORD AddAllSidsForDenyOnly(std::vector<Sid>* exceptions);
+
+ // Adds a user or group SID for Deny Only in the restricted token.
+ // Parameter: sid is the SID to add in the Deny Only list.
+ // The return value is always ERROR_SUCCESS.
+ //
+ // Sample Usage:
+ // restricted_token.AddSidForDenyOnly(ATL::Sids::Admins().GetPSID());
+ DWORD AddSidForDenyOnly(const Sid& sid);
+
+ // Adds the user sid of the token for Deny Only in the restricted token.
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD AddUserSidForDenyOnly();
+
+ // Lists all privileges in the token and add them to the list of privileges
+ // to remove except for those present in the exceptions parameter. If
+ // there is no exception needed, the caller can pass an empty list or nullptr
+ // for the exceptions parameter.
+ //
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ //
+ // Sample usage:
+ // std::vector<std::wstring> privilege_exceptions;
+ // privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+ // restricted_token.DeleteAllPrivileges(&privilege_exceptions);
+ DWORD DeleteAllPrivileges(const std::vector<std::wstring>* exceptions);
+
+ // Adds a privilege to the list of privileges to remove in the restricted
+ // token.
+ // Parameter: privilege is the privilege name to remove. This is the string
+ // representing the privilege. (e.g. "SeChangeNotifyPrivilege").
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ //
+ // Sample usage:
+ // restricted_token.DeletePrivilege(SE_LOAD_DRIVER_NAME);
+ DWORD DeletePrivilege(const wchar_t* privilege);
+
+ // Adds a SID to the list of restricting sids in the restricted token.
+ // Parameter: sid is the sid to add to the list restricting sids.
+ // The return value is always ERROR_SUCCESS.
+ //
+ // Sample usage:
+ // restricted_token.AddRestrictingSid(ATL::Sids::Users().GetPSID());
+ // Note: The list of restricting is used to force Windows to perform all
+ // access checks twice. The first time using your user SID and your groups,
+ // and the second time using your list of restricting sids. The access has
+ // to be granted in both places to get access to the resource requested.
+ DWORD AddRestrictingSid(const Sid& sid);
+
+ // Adds the logon sid of the token in the list of restricting sids for the
+ // restricted token.
+ //
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD AddRestrictingSidLogonSession();
+
+ // Adds the owner sid of the token in the list of restricting sids for the
+ // restricted token.
+ //
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD AddRestrictingSidCurrentUser();
+
+ // Adds all group sids and the user sid to the restricting sids list.
+ //
+ // If the function succeeds, the return value is ERROR_SUCCESS. If the
+ // function fails, the return value is the win32 error code corresponding to
+ // the error.
+ DWORD AddRestrictingSidAllSids();
+
+ // Sets the token integrity level. This is only valid on Vista. The integrity
+ // level cannot be higher than your current integrity level.
+ DWORD SetIntegrityLevel(IntegrityLevel integrity_level);
+
+ // Set a flag which indicates the created token should have a locked down
+ // default DACL when created.
+ void SetLockdownDefaultDacl();
+
+ // Add a SID to the default DACL. These SIDs are added regardless of the
+ // SetLockdownDefaultDacl state.
+ DWORD AddDefaultDaclSid(const Sid& sid,
+ ACCESS_MODE access_mode,
+ ACCESS_MASK access);
+
+ private:
+ // The list of restricting sids in the restricted token.
+ std::vector<Sid> sids_to_restrict_;
+ // The list of privileges to remove in the restricted token.
+ std::vector<LUID> privileges_to_disable_;
+ // The list of sids to mark as Deny Only in the restricted token.
+ std::vector<Sid> sids_for_deny_only_;
+ // The list of sids to add to the default DACL of the restricted token.
+ std::vector<std::tuple<Sid, ACCESS_MODE, ACCESS_MASK>> sids_for_default_dacl_;
+ // The token to restrict. Can only be set in a constructor.
+ base::win::ScopedHandle effective_token_;
+ // The token integrity level. Only valid on Vista.
+ IntegrityLevel integrity_level_;
+ // Tells if the object is initialized or not (if Init() has been called)
+ bool init_;
+ // Lockdown the default DACL when creating new tokens.
+ bool lockdown_default_dacl_;
+
+ DISALLOW_COPY_AND_ASSIGN(RestrictedToken);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_RESTRICTED_TOKEN_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_unittest.cc b/security/sandbox/chromium/sandbox/win/src/restricted_token_unittest.cc
new file mode 100644
index 0000000000..1855054a7c
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_unittest.cc
@@ -0,0 +1,829 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for the RestrictedToken.
+
+#include "sandbox/win/src/restricted_token.h"
+
+#include <vector>
+
+#include "base/win/atl.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/security_capabilities.h"
+#include "sandbox/win/src/sid.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+void TestDefaultDalc(bool restricted_required) {
+ RestrictedToken token;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ if (!restricted_required)
+ token.SetLockdownDefaultDacl();
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+
+ base::win::ScopedHandle handle;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(handle.Take());
+
+ ATL::CDacl dacl;
+ ASSERT_TRUE(restricted_token.GetDefaultDacl(&dacl));
+
+ ATL::CSid logon_sid;
+ ASSERT_TRUE(restricted_token.GetLogonSid(&logon_sid));
+
+ bool restricted_found = false;
+ bool logon_sid_found = false;
+
+ unsigned int ace_count = dacl.GetAceCount();
+ for (unsigned int i = 0; i < ace_count; ++i) {
+ ATL::CSid sid;
+ ACCESS_MASK mask = 0;
+ dacl.GetAclEntry(i, &sid, &mask);
+ if (sid == ATL::Sids::RestrictedCode() && mask == GENERIC_ALL) {
+ restricted_found = true;
+ } else if (sid == logon_sid) {
+ logon_sid_found = true;
+ }
+ }
+
+ ASSERT_EQ(restricted_required, restricted_found);
+ if (!restricted_required)
+ ASSERT_FALSE(logon_sid_found);
+}
+
+bool GetVariableTokenInformation(HANDLE token,
+ TOKEN_INFORMATION_CLASS information_class,
+ std::vector<char>* information) {
+ DWORD return_length;
+ if (!::GetTokenInformation(token, information_class, nullptr, 0,
+ &return_length)) {
+ if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ return false;
+ }
+ }
+
+ information->resize(return_length);
+ return !!::GetTokenInformation(token, information_class, information->data(),
+ return_length, &return_length);
+}
+
+bool GetVariableTokenInformation(const base::win::ScopedHandle& token,
+ TOKEN_INFORMATION_CLASS information_class,
+ std::vector<char>* information) {
+ return GetVariableTokenInformation(token.Get(), information_class,
+ information);
+}
+
+void CheckDaclForPackageSid(const base::win::ScopedHandle& token,
+ PSECURITY_CAPABILITIES security_capabilities,
+ bool package_sid_required) {
+ DWORD length_needed = 0;
+ ::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION, nullptr, 0,
+ &length_needed);
+ ASSERT_EQ(::GetLastError(), DWORD{ERROR_INSUFFICIENT_BUFFER});
+
+ std::vector<char> security_desc_buffer(length_needed);
+ SECURITY_DESCRIPTOR* security_desc =
+ reinterpret_cast<SECURITY_DESCRIPTOR*>(security_desc_buffer.data());
+
+ ASSERT_TRUE(::GetKernelObjectSecurity(token.Get(), DACL_SECURITY_INFORMATION,
+ security_desc, length_needed,
+ &length_needed));
+
+ ATL::CSecurityDesc token_sd(*security_desc);
+ ATL::CDacl dacl;
+ ASSERT_TRUE(token_sd.GetDacl(&dacl));
+
+ ATL::CSid package_sid(
+ static_cast<SID*>(security_capabilities->AppContainerSid));
+ ATL::CSid all_package_sid(
+ static_cast<SID*>(sandbox::Sid(::WinBuiltinAnyPackageSid).GetPSID()));
+
+ unsigned int ace_count = dacl.GetAceCount();
+ for (unsigned int i = 0; i < ace_count; ++i) {
+ ATL::CSid sid;
+ ACCESS_MASK mask = 0;
+ BYTE type = 0;
+ dacl.GetAclEntry(i, &sid, &mask, &type);
+ if (mask != TOKEN_ALL_ACCESS || type != ACCESS_ALLOWED_ACE_TYPE)
+ continue;
+ if (sid == package_sid)
+ EXPECT_TRUE(package_sid_required);
+ else if (sid == all_package_sid)
+ EXPECT_FALSE(package_sid_required);
+ }
+}
+
+void CheckLowBoxToken(const base::win::ScopedHandle& token,
+ TOKEN_TYPE token_type,
+ PSECURITY_CAPABILITIES security_capabilities) {
+ DWORD appcontainer;
+ DWORD return_length;
+ ASSERT_TRUE(::GetTokenInformation(token.Get(), ::TokenIsAppContainer,
+ &appcontainer, sizeof(appcontainer),
+ &return_length));
+ ASSERT_TRUE(appcontainer);
+ TOKEN_TYPE token_type_real;
+ ASSERT_TRUE(::GetTokenInformation(token.Get(), ::TokenType, &token_type_real,
+ sizeof(token_type_real), &return_length));
+ ASSERT_EQ(token_type_real, token_type);
+ if (token_type == ::TokenImpersonation) {
+ SECURITY_IMPERSONATION_LEVEL imp_level;
+ ASSERT_TRUE(::GetTokenInformation(token.Get(), ::TokenImpersonationLevel,
+ &imp_level, sizeof(imp_level),
+ &return_length));
+ ASSERT_EQ(imp_level, ::SecurityImpersonation);
+ }
+
+ std::vector<char> package_sid_buf;
+ ASSERT_TRUE(GetVariableTokenInformation(token, ::TokenAppContainerSid,
+ &package_sid_buf));
+ PTOKEN_APPCONTAINER_INFORMATION package_sid =
+ reinterpret_cast<PTOKEN_APPCONTAINER_INFORMATION>(package_sid_buf.data());
+ EXPECT_TRUE(::EqualSid(security_capabilities->AppContainerSid,
+ package_sid->TokenAppContainer));
+
+ std::vector<char> capabilities_buf;
+ ASSERT_TRUE(GetVariableTokenInformation(token, ::TokenCapabilities,
+ &capabilities_buf));
+ PTOKEN_GROUPS capabilities =
+ reinterpret_cast<PTOKEN_GROUPS>(capabilities_buf.data());
+ ASSERT_EQ(capabilities->GroupCount, security_capabilities->CapabilityCount);
+ for (DWORD index = 0; index < capabilities->GroupCount; ++index) {
+ EXPECT_EQ(capabilities->Groups[index].Attributes,
+ security_capabilities->Capabilities[index].Attributes);
+ EXPECT_TRUE(::EqualSid(capabilities->Groups[index].Sid,
+ security_capabilities->Capabilities[index].Sid));
+ }
+
+ CheckDaclForPackageSid(token, security_capabilities, true);
+}
+
+// Checks if a sid is in the restricting list of the restricted token.
+// Asserts if it's not the case. If count is a positive number, the number of
+// elements in the restricting sids list has to be equal.
+void CheckRestrictingSid(HANDLE restricted_token, ATL::CSid sid, int count) {
+ std::vector<char> memory;
+ ASSERT_TRUE(GetVariableTokenInformation(restricted_token,
+ ::TokenRestrictedSids, &memory));
+ PTOKEN_GROUPS groups = reinterpret_cast<PTOKEN_GROUPS>(memory.data());
+ ATL::CTokenGroups atl_groups(*groups);
+
+ if (count >= 0)
+ ASSERT_EQ(static_cast<unsigned>(count), atl_groups.GetCount());
+
+ ATL::CSid::CSidArray sids;
+ ATL::CAtlArray<DWORD> attributes;
+ atl_groups.GetSidsAndAttributes(&sids, &attributes);
+
+ bool present = false;
+ for (unsigned int i = 0; i < sids.GetCount(); ++i) {
+ if (sids[i] == sid) {
+ present = true;
+ break;
+ }
+ }
+
+ ASSERT_TRUE(present);
+}
+
+void CheckRestrictingSid(const ATL::CAccessToken& restricted_token,
+ ATL::CSid sid,
+ int count) {
+ CheckRestrictingSid(restricted_token.GetHandle(), sid, count);
+}
+
+} // namespace
+
+// Tests the initializatioin with an invalid token handle.
+TEST(RestrictedTokenTest, InvalidHandle) {
+ RestrictedToken token;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_INVALID_HANDLE),
+ token.Init(reinterpret_cast<HANDLE>(0x5555)));
+}
+
+// Tests the initialization with nullptr as parameter.
+TEST(RestrictedTokenTest, DefaultInit) {
+ // Get the current process token.
+ HANDLE token_handle = INVALID_HANDLE_VALUE;
+ ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+ &token_handle));
+
+ ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+
+ ATL::CAccessToken access_token;
+ access_token.Attach(token_handle);
+
+ // Create the token using the current token.
+ RestrictedToken token_default;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token_default.Init(nullptr));
+
+ // Get the handle to the restricted token.
+
+ base::win::ScopedHandle restricted_token_handle;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token_default.GetRestrictedToken(&restricted_token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(restricted_token_handle.Take());
+
+ ATL::CSid sid_user_restricted;
+ ATL::CSid sid_user_default;
+ ATL::CSid sid_owner_restricted;
+ ATL::CSid sid_owner_default;
+ ASSERT_TRUE(restricted_token.GetUser(&sid_user_restricted));
+ ASSERT_TRUE(access_token.GetUser(&sid_user_default));
+ ASSERT_TRUE(restricted_token.GetOwner(&sid_owner_restricted));
+ ASSERT_TRUE(access_token.GetOwner(&sid_owner_default));
+
+ // Check if both token have the same owner and user.
+ ASSERT_EQ(sid_user_restricted, sid_user_default);
+ ASSERT_EQ(sid_owner_restricted, sid_owner_default);
+}
+
+// Tests the initialization with a custom token as parameter.
+TEST(RestrictedTokenTest, CustomInit) {
+ // Get the current process token.
+ HANDLE token_handle = INVALID_HANDLE_VALUE;
+ ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+ &token_handle));
+
+ ASSERT_NE(INVALID_HANDLE_VALUE, token_handle);
+
+ ATL::CAccessToken access_token;
+ access_token.Attach(token_handle);
+
+ // Change the primary group.
+ access_token.SetPrimaryGroup(ATL::Sids::World());
+
+ // Create the token using the current token.
+ RestrictedToken token;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.Init(access_token.GetHandle()));
+
+ // Get the handle to the restricted token.
+
+ base::win::ScopedHandle restricted_token_handle;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&restricted_token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(restricted_token_handle.Take());
+
+ ATL::CSid sid_restricted;
+ ATL::CSid sid_default;
+ ASSERT_TRUE(restricted_token.GetPrimaryGroup(&sid_restricted));
+ ASSERT_TRUE(access_token.GetPrimaryGroup(&sid_default));
+
+ // Check if both token have the same owner.
+ ASSERT_EQ(sid_restricted, sid_default);
+}
+
+// Verifies that the token created by the object are valid.
+TEST(RestrictedTokenTest, ResultToken) {
+ RestrictedToken token;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+
+ base::win::ScopedHandle restricted_token;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&restricted_token));
+
+ ASSERT_TRUE(::IsTokenRestricted(restricted_token.Get()));
+
+ DWORD length = 0;
+ TOKEN_TYPE type;
+ ASSERT_TRUE(::GetTokenInformation(restricted_token.Get(), ::TokenType, &type,
+ sizeof(type), &length));
+
+ ASSERT_EQ(type, TokenPrimary);
+
+ base::win::ScopedHandle impersonation_token;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedTokenForImpersonation(&impersonation_token));
+
+ ASSERT_TRUE(::IsTokenRestricted(impersonation_token.Get()));
+
+ ASSERT_TRUE(::GetTokenInformation(impersonation_token.Get(), ::TokenType,
+ &type, sizeof(type), &length));
+
+ ASSERT_EQ(type, TokenImpersonation);
+}
+
+// Verifies that the token created has "Restricted" in its default dacl.
+TEST(RestrictedTokenTest, DefaultDacl) {
+ TestDefaultDalc(true);
+}
+
+// Verifies that the token created does not have "Restricted" in its default
+// dacl.
+TEST(RestrictedTokenTest, DefaultDaclLockdown) {
+ TestDefaultDalc(false);
+}
+
+// Tests the method "AddSidForDenyOnly".
+TEST(RestrictedTokenTest, DenySid) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddSidForDenyOnly(Sid(WinWorldSid)));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenGroups groups;
+ ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+ ATL::CSid::CSidArray sids;
+ ATL::CAtlArray<DWORD> attributes;
+ groups.GetSidsAndAttributes(&sids, &attributes);
+
+ for (unsigned int i = 0; i < sids.GetCount(); i++) {
+ if (ATL::Sids::World() == sids[i]) {
+ ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
+ attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+ }
+ }
+}
+
+// Tests the method "AddAllSidsForDenyOnly".
+TEST(RestrictedTokenTest, DenySids) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddAllSidsForDenyOnly(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenGroups groups;
+ ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+ ATL::CSid::CSidArray sids;
+ ATL::CAtlArray<DWORD> attributes;
+ groups.GetSidsAndAttributes(&sids, &attributes);
+
+ // Verify that all sids are really gone.
+ for (unsigned int i = 0; i < sids.GetCount(); i++) {
+ if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
+ (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
+ ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
+ attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+ }
+ }
+}
+
+// Tests the method "AddAllSidsForDenyOnly" using an exception list.
+TEST(RestrictedTokenTest, DenySidsException) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ std::vector<Sid> sids_exception;
+ sids_exception.push_back(Sid(WinWorldSid));
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddAllSidsForDenyOnly(&sids_exception));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenGroups groups;
+ ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+ ATL::CSid::CSidArray sids;
+ ATL::CAtlArray<DWORD> attributes;
+ groups.GetSidsAndAttributes(&sids, &attributes);
+
+ // Verify that all sids are really gone.
+ for (unsigned int i = 0; i < sids.GetCount(); i++) {
+ if ((attributes[i] & SE_GROUP_LOGON_ID) == 0 &&
+ (attributes[i] & SE_GROUP_INTEGRITY) == 0) {
+ if (ATL::Sids::World() == sids[i]) {
+ ASSERT_EQ(0u, attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+ } else {
+ ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
+ attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+ }
+ }
+ }
+}
+
+// Tests test method AddOwnerSidForDenyOnly.
+TEST(RestrictedTokenTest, DenyOwnerSid) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.AddUserSidForDenyOnly());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenGroups groups;
+ ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+ ATL::CSid::CSidArray sids;
+ ATL::CAtlArray<DWORD> attributes;
+ groups.GetSidsAndAttributes(&sids, &attributes);
+
+ ATL::CSid user_sid;
+ ASSERT_TRUE(restricted_token.GetUser(&user_sid));
+
+ for (unsigned int i = 0; i < sids.GetCount(); ++i) {
+ if (user_sid == sids[i]) {
+ ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
+ attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+ }
+ }
+}
+
+// Tests test method AddOwnerSidForDenyOnly with a custom effective token.
+TEST(RestrictedTokenTest, DenyOwnerSidCustom) {
+ // Get the current process token.
+ HANDLE access_handle = INVALID_HANDLE_VALUE;
+ ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+ &access_handle));
+
+ ASSERT_NE(INVALID_HANDLE_VALUE, access_handle);
+
+ ATL::CAccessToken access_token;
+ access_token.Attach(access_handle);
+
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.Init(access_token.GetHandle()));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.AddUserSidForDenyOnly());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenGroups groups;
+ ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+ ATL::CSid::CSidArray sids;
+ ATL::CAtlArray<DWORD> attributes;
+ groups.GetSidsAndAttributes(&sids, &attributes);
+
+ ATL::CSid user_sid;
+ ASSERT_TRUE(restricted_token.GetUser(&user_sid));
+
+ for (unsigned int i = 0; i < sids.GetCount(); ++i) {
+ if (user_sid == sids[i]) {
+ ASSERT_EQ(static_cast<DWORD>(SE_GROUP_USE_FOR_DENY_ONLY),
+ attributes[i] & SE_GROUP_USE_FOR_DENY_ONLY);
+ }
+ }
+}
+
+// Tests the method DeleteAllPrivileges.
+TEST(RestrictedTokenTest, DeleteAllPrivileges) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.DeleteAllPrivileges(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenPrivileges privileges;
+ ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
+
+ ASSERT_EQ(0u, privileges.GetCount());
+}
+
+// Tests the method DeleteAllPrivileges with an exception list.
+TEST(RestrictedTokenTest, DeleteAllPrivilegesException) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ std::vector<std::wstring> exceptions;
+ exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.DeleteAllPrivileges(&exceptions));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenPrivileges privileges;
+ ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
+
+ ATL::CTokenPrivileges::CNames privilege_names;
+ ATL::CTokenPrivileges::CAttributes privilege_name_attributes;
+ privileges.GetNamesAndAttributes(&privilege_names,
+ &privilege_name_attributes);
+
+ ASSERT_EQ(1u, privileges.GetCount());
+
+ for (unsigned int i = 0; i < privileges.GetCount(); ++i) {
+ ASSERT_EQ(privilege_names[i], SE_CHANGE_NOTIFY_NAME);
+ }
+}
+
+// Tests the method DeletePrivilege.
+TEST(RestrictedTokenTest, DeletePrivilege) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.DeletePrivilege(SE_CHANGE_NOTIFY_NAME));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenPrivileges privileges;
+ ASSERT_TRUE(restricted_token.GetPrivileges(&privileges));
+
+ ATL::CTokenPrivileges::CNames privilege_names;
+ ATL::CTokenPrivileges::CAttributes privilege_name_attributes;
+ privileges.GetNamesAndAttributes(&privilege_names,
+ &privilege_name_attributes);
+
+ for (unsigned int i = 0; i < privileges.GetCount(); ++i) {
+ ASSERT_NE(privilege_names[i], SE_CHANGE_NOTIFY_NAME);
+ }
+}
+
+// Tests the method AddRestrictingSid.
+TEST(RestrictedTokenTest, AddRestrictingSid) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ CheckRestrictingSid(restricted_token, ATL::Sids::World(), 1);
+}
+
+// Tests the method AddRestrictingSidCurrentUser.
+TEST(RestrictedTokenTest, AddRestrictingSidCurrentUser) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSidCurrentUser());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+ ATL::CSid user;
+ restricted_token.GetUser(&user);
+
+ CheckRestrictingSid(restricted_token, user, 1);
+}
+
+// Tests the method AddRestrictingSidCurrentUser with a custom effective token.
+TEST(RestrictedTokenTest, AddRestrictingSidCurrentUserCustom) {
+ // Get the current process token.
+ HANDLE access_handle = INVALID_HANDLE_VALUE;
+ ASSERT_TRUE(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+ &access_handle));
+
+ ASSERT_NE(INVALID_HANDLE_VALUE, access_handle);
+
+ ATL::CAccessToken access_token;
+ access_token.Attach(access_handle);
+
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.Init(access_token.GetHandle()));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSidCurrentUser());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+ ATL::CSid user;
+ restricted_token.GetUser(&user);
+
+ CheckRestrictingSid(restricted_token, user, 1);
+}
+
+// Tests the method AddRestrictingSidLogonSession.
+TEST(RestrictedTokenTest, AddRestrictingSidLogonSession) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSidLogonSession());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+ ATL::CSid session;
+ restricted_token.GetLogonSid(&session);
+
+ CheckRestrictingSid(restricted_token, session, 1);
+}
+
+// Tests adding a lot of restricting sids.
+TEST(RestrictedTokenTest, AddMultipleRestrictingSids) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSidCurrentUser());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSidLogonSession());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+ ATL::CSid session;
+ restricted_token.GetLogonSid(&session);
+
+ std::vector<char> memory;
+ ASSERT_TRUE(GetVariableTokenInformation(restricted_token.GetHandle(),
+ ::TokenRestrictedSids, &memory));
+ PTOKEN_GROUPS groups = reinterpret_cast<PTOKEN_GROUPS>(memory.data());
+ ATL::CTokenGroups atl_groups(*groups);
+ ASSERT_EQ(3u, atl_groups.GetCount());
+}
+
+// Tests the method "AddRestrictingSidAllSids".
+TEST(RestrictedTokenTest, AddAllSidToRestrictingSids) {
+ RestrictedToken token;
+ base::win::ScopedHandle token_handle;
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.AddRestrictingSidAllSids());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ token.GetRestrictedToken(&token_handle));
+
+ ATL::CAccessToken restricted_token;
+ restricted_token.Attach(token_handle.Take());
+
+ ATL::CTokenGroups groups;
+ ASSERT_TRUE(restricted_token.GetGroups(&groups));
+
+ ATL::CSid::CSidArray sids;
+ ATL::CAtlArray<DWORD> attributes;
+ groups.GetSidsAndAttributes(&sids, &attributes);
+
+ // Verify that all group sids are in the restricting sid list.
+ for (unsigned int i = 0; i < sids.GetCount(); i++) {
+ if ((attributes[i] & SE_GROUP_INTEGRITY) == 0) {
+ CheckRestrictingSid(restricted_token, sids[i], -1);
+ }
+ }
+
+ // Verify that the user is in the restricting sid list.
+ ATL::CSid user;
+ restricted_token.GetUser(&user);
+ CheckRestrictingSid(restricted_token, user, -1);
+}
+
+// Checks the error code when the object is initialized twice.
+TEST(RestrictedTokenTest, DoubleInit) {
+ RestrictedToken token;
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), token.Init(nullptr));
+
+ ASSERT_EQ(static_cast<DWORD>(ERROR_ALREADY_INITIALIZED), token.Init(nullptr));
+}
+
+TEST(RestrictedTokenTest, LockdownDefaultDaclNoLogonSid) {
+ ATL::CAccessToken anonymous_token;
+ ASSERT_TRUE(::ImpersonateAnonymousToken(::GetCurrentThread()));
+ ASSERT_TRUE(anonymous_token.GetThreadToken(TOKEN_ALL_ACCESS));
+ ::RevertToSelf();
+ ATL::CSid logon_sid;
+ // Verify that the anonymous token doesn't have the logon sid.
+ ASSERT_FALSE(anonymous_token.GetLogonSid(&logon_sid));
+
+ RestrictedToken token;
+ ASSERT_EQ(DWORD{ERROR_SUCCESS}, token.Init(anonymous_token.GetHandle()));
+ token.SetLockdownDefaultDacl();
+
+ base::win::ScopedHandle handle;
+ ASSERT_EQ(DWORD{ERROR_SUCCESS}, token.GetRestrictedToken(&handle));
+}
+
+TEST(RestrictedTokenTest, LowBoxToken) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return;
+ base::win::ScopedHandle token;
+
+ Sid package_sid = Sid::FromSddlString(L"S-1-15-2-1-2-3-4-5-6-7");
+ SecurityCapabilities caps_no_capabilities(package_sid);
+
+ ASSERT_EQ(DWORD{ERROR_INVALID_PARAMETER},
+ CreateLowBoxToken(nullptr, PRIMARY, &caps_no_capabilities, nullptr,
+ 0, nullptr));
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ CreateLowBoxToken(nullptr, PRIMARY, &caps_no_capabilities, nullptr,
+ 0, &token));
+ ASSERT_TRUE(token.IsValid());
+ CheckLowBoxToken(token, ::TokenPrimary, &caps_no_capabilities);
+
+ ASSERT_TRUE(ReplacePackageSidInDacl(token.Get(), SE_KERNEL_OBJECT,
+ Sid(caps_no_capabilities.AppContainerSid),
+ TOKEN_ALL_ACCESS));
+ CheckDaclForPackageSid(token, &caps_no_capabilities, false);
+
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ CreateLowBoxToken(nullptr, IMPERSONATION, &caps_no_capabilities,
+ nullptr, 0, &token));
+ ASSERT_TRUE(token.IsValid());
+ CheckLowBoxToken(token, ::TokenImpersonation, &caps_no_capabilities);
+
+ std::vector<Sid> capabilities;
+ capabilities.push_back(Sid::FromKnownCapability(kInternetClient));
+ capabilities.push_back(Sid::FromKnownCapability(kPrivateNetworkClientServer));
+ SecurityCapabilities caps_with_capabilities(package_sid, capabilities);
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ CreateLowBoxToken(nullptr, PRIMARY, &caps_with_capabilities,
+ nullptr, 0, &token));
+ ASSERT_TRUE(token.IsValid());
+ CheckLowBoxToken(token, ::TokenPrimary, &caps_with_capabilities);
+
+ RestrictedToken restricted_token;
+ base::win::ScopedHandle token_handle;
+ ASSERT_EQ(DWORD{ERROR_SUCCESS}, restricted_token.Init(nullptr));
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ restricted_token.AddRestrictingSid(ATL::Sids::World().GetPSID()));
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ restricted_token.GetRestrictedToken(&token_handle));
+
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ CreateLowBoxToken(token_handle.Get(), PRIMARY,
+ &caps_with_capabilities, nullptr, 0, &token));
+ ASSERT_TRUE(token.IsValid());
+ CheckLowBoxToken(token, ::TokenPrimary, &caps_with_capabilities);
+ CheckRestrictingSid(token.Get(), ATL::Sids::World(), 1);
+
+ SecurityCapabilities caps_for_handles(
+ Sid::FromSddlString(L"S-1-15-2-1-2-3-4-5-6-8"));
+ base::win::ScopedHandle object_handle;
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ CreateLowBoxObjectDirectory(caps_for_handles.AppContainerSid, true,
+ &object_handle));
+ HANDLE saved_handles[] = {object_handle.Get()};
+
+ ASSERT_EQ(DWORD{ERROR_SUCCESS},
+ CreateLowBoxToken(token_handle.Get(), PRIMARY, &caps_for_handles,
+ saved_handles, 1, &token));
+ ASSERT_TRUE(token.IsValid());
+ object_handle.Close();
+ ASSERT_FALSE(object_handle.IsValid());
+ ASSERT_EQ(DWORD{ERROR_ALREADY_EXISTS},
+ CreateLowBoxObjectDirectory(caps_for_handles.AppContainerSid, false,
+ &object_handle));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
new file mode 100644
index 0000000000..d93386d646
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
@@ -0,0 +1,482 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/restricted_token_utils.h"
+
+#include <aclapi.h>
+#include <sddl.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/job.h"
+#include "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/security_level.h"
+#include "sandbox/win/src/sid.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+DWORD GetObjectSecurityDescriptor(HANDLE handle,
+ SECURITY_INFORMATION security_info,
+ std::vector<char>* security_desc_buffer,
+ PSECURITY_DESCRIPTOR* security_desc) {
+ DWORD last_error = 0;
+ DWORD length_needed = 0;
+
+ ::GetKernelObjectSecurity(handle, security_info, nullptr, 0, &length_needed);
+ last_error = ::GetLastError();
+ if (last_error != ERROR_INSUFFICIENT_BUFFER)
+ return last_error;
+
+ security_desc_buffer->resize(length_needed);
+ *security_desc =
+ reinterpret_cast<PSECURITY_DESCRIPTOR>(security_desc_buffer->data());
+
+ if (!::GetKernelObjectSecurity(handle, security_info, *security_desc,
+ length_needed, &length_needed)) {
+ return ::GetLastError();
+ }
+
+ return ERROR_SUCCESS;
+}
+
+} // namespace
+
+DWORD CreateRestrictedToken(HANDLE effective_token,
+ TokenLevel security_level,
+ IntegrityLevel integrity_level,
+ TokenType token_type,
+ bool lockdown_default_dacl,
+ PSID unique_restricted_sid,
+ bool use_restricting_sids,
+ base::win::ScopedHandle* token) {
+ RestrictedToken restricted_token;
+ restricted_token.Init(effective_token);
+ if (lockdown_default_dacl)
+ restricted_token.SetLockdownDefaultDacl();
+ if (unique_restricted_sid) {
+ restricted_token.AddDefaultDaclSid(Sid(unique_restricted_sid), GRANT_ACCESS,
+ GENERIC_ALL);
+ restricted_token.AddDefaultDaclSid(Sid(WinCreatorOwnerRightsSid),
+ GRANT_ACCESS, READ_CONTROL);
+ }
+
+ std::vector<std::wstring> privilege_exceptions;
+ std::vector<Sid> sid_exceptions;
+
+ bool deny_sids = true;
+ bool remove_privileges = true;
+
+ switch (security_level) {
+ case USER_UNPROTECTED: {
+ deny_sids = false;
+ remove_privileges = false;
+ break;
+ }
+ case USER_RESTRICTED_SAME_ACCESS: {
+ deny_sids = false;
+ remove_privileges = false;
+
+ if (use_restricting_sids) {
+ unsigned err_code = restricted_token.AddRestrictingSidAllSids();
+ if (ERROR_SUCCESS != err_code) {
+ return err_code;
+ }
+ }
+
+ break;
+ }
+ case USER_NON_ADMIN: {
+ sid_exceptions.push_back(WinBuiltinUsersSid);
+ sid_exceptions.push_back(WinWorldSid);
+ sid_exceptions.push_back(WinInteractiveSid);
+ sid_exceptions.push_back(WinAuthenticatedUserSid);
+ privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+ break;
+ }
+ case USER_RESTRICTED_NON_ADMIN: {
+ sid_exceptions.push_back(WinBuiltinUsersSid);
+ sid_exceptions.push_back(WinWorldSid);
+ sid_exceptions.push_back(WinInteractiveSid);
+ sid_exceptions.push_back(WinAuthenticatedUserSid);
+ privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+ if (use_restricting_sids) {
+ restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
+ restricted_token.AddRestrictingSid(WinWorldSid);
+ restricted_token.AddRestrictingSid(WinInteractiveSid);
+ restricted_token.AddRestrictingSid(WinAuthenticatedUserSid);
+ restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+ restricted_token.AddRestrictingSidCurrentUser();
+ restricted_token.AddRestrictingSidLogonSession();
+ }
+ break;
+ }
+ case USER_INTERACTIVE: {
+ sid_exceptions.push_back(WinBuiltinUsersSid);
+ sid_exceptions.push_back(WinWorldSid);
+ sid_exceptions.push_back(WinInteractiveSid);
+ sid_exceptions.push_back(WinAuthenticatedUserSid);
+ privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+ if (use_restricting_sids) {
+ restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
+ restricted_token.AddRestrictingSid(WinWorldSid);
+ restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+ restricted_token.AddRestrictingSidCurrentUser();
+ restricted_token.AddRestrictingSidLogonSession();
+ if (unique_restricted_sid)
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
+ }
+ break;
+ }
+ case USER_LIMITED: {
+ sid_exceptions.push_back(WinBuiltinUsersSid);
+ sid_exceptions.push_back(WinWorldSid);
+ sid_exceptions.push_back(WinInteractiveSid);
+ privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+ if (use_restricting_sids) {
+ restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
+ restricted_token.AddRestrictingSid(WinWorldSid);
+ restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+ if (unique_restricted_sid)
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
+
+ // This token has to be able to create objects in BNO.
+ // Unfortunately, on Vista+, it needs the current logon sid
+ // in the token to achieve this. You should also set the process to be
+ // low integrity level so it can't access object created by other
+ // processes.
+ restricted_token.AddRestrictingSidLogonSession();
+ } else {
+ restricted_token.AddUserSidForDenyOnly();
+ }
+ break;
+ }
+ case USER_RESTRICTED: {
+ privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
+ restricted_token.AddUserSidForDenyOnly();
+ if (use_restricting_sids) {
+ restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
+ if (unique_restricted_sid)
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
+ }
+ break;
+ }
+ case USER_LOCKDOWN: {
+ restricted_token.AddUserSidForDenyOnly();
+ if (use_restricting_sids) {
+ restricted_token.AddRestrictingSid(WinNullSid);
+ if (unique_restricted_sid)
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
+ }
+ break;
+ }
+ default: { return ERROR_BAD_ARGUMENTS; }
+ }
+
+ DWORD err_code = ERROR_SUCCESS;
+ if (deny_sids) {
+ err_code = restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
+ if (ERROR_SUCCESS != err_code)
+ return err_code;
+ }
+
+ if (remove_privileges) {
+ err_code = restricted_token.DeleteAllPrivileges(&privilege_exceptions);
+ if (ERROR_SUCCESS != err_code)
+ return err_code;
+ }
+
+ restricted_token.SetIntegrityLevel(integrity_level);
+
+ switch (token_type) {
+ case PRIMARY: {
+ err_code = restricted_token.GetRestrictedToken(token);
+ break;
+ }
+ case IMPERSONATION: {
+ err_code = restricted_token.GetRestrictedTokenForImpersonation(token);
+ break;
+ }
+ default: {
+ err_code = ERROR_BAD_ARGUMENTS;
+ break;
+ }
+ }
+
+ return err_code;
+}
+
+DWORD SetObjectIntegrityLabel(HANDLE handle,
+ SE_OBJECT_TYPE type,
+ const wchar_t* ace_access,
+ const wchar_t* integrity_level_sid) {
+ // Build the SDDL string for the label.
+ std::wstring sddl = L"S:("; // SDDL for a SACL.
+ sddl += SDDL_MANDATORY_LABEL; // Ace Type is "Mandatory Label".
+ sddl += L";;"; // No Ace Flags.
+ sddl += ace_access; // Add the ACE access.
+ sddl += L";;;"; // No ObjectType and Inherited Object Type.
+ sddl += integrity_level_sid; // Trustee Sid.
+ sddl += L")";
+
+ DWORD error = ERROR_SUCCESS;
+ PSECURITY_DESCRIPTOR sec_desc = nullptr;
+
+ PACL sacl = nullptr;
+ BOOL sacl_present = false;
+ BOOL sacl_defaulted = false;
+
+ if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(
+ sddl.c_str(), SDDL_REVISION, &sec_desc, nullptr)) {
+ if (::GetSecurityDescriptorSacl(sec_desc, &sacl_present, &sacl,
+ &sacl_defaulted)) {
+ error = ::SetSecurityInfo(handle, type, LABEL_SECURITY_INFORMATION,
+ nullptr, nullptr, nullptr, sacl);
+ } else {
+ error = ::GetLastError();
+ }
+
+ ::LocalFree(sec_desc);
+ } else {
+ return ::GetLastError();
+ }
+
+ return error;
+}
+
+const wchar_t* GetIntegrityLevelString(IntegrityLevel integrity_level) {
+ switch (integrity_level) {
+ case INTEGRITY_LEVEL_SYSTEM:
+ return L"S-1-16-16384";
+ case INTEGRITY_LEVEL_HIGH:
+ return L"S-1-16-12288";
+ case INTEGRITY_LEVEL_MEDIUM:
+ return L"S-1-16-8192";
+ case INTEGRITY_LEVEL_MEDIUM_LOW:
+ return L"S-1-16-6144";
+ case INTEGRITY_LEVEL_LOW:
+ return L"S-1-16-4096";
+ case INTEGRITY_LEVEL_BELOW_LOW:
+ return L"S-1-16-2048";
+ case INTEGRITY_LEVEL_UNTRUSTED:
+ return L"S-1-16-0";
+ case INTEGRITY_LEVEL_LAST:
+ return nullptr;
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
+DWORD SetTokenIntegrityLevel(HANDLE token, IntegrityLevel integrity_level) {
+ const wchar_t* integrity_level_str = GetIntegrityLevelString(integrity_level);
+ if (!integrity_level_str) {
+ // No mandatory level specified, we don't change it.
+ return ERROR_SUCCESS;
+ }
+
+ PSID integrity_sid = nullptr;
+ if (!::ConvertStringSidToSid(integrity_level_str, &integrity_sid))
+ return ::GetLastError();
+
+ TOKEN_MANDATORY_LABEL label = {};
+ label.Label.Attributes = SE_GROUP_INTEGRITY;
+ label.Label.Sid = integrity_sid;
+
+ DWORD size = sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(integrity_sid);
+ bool result = ::SetTokenInformation(token, TokenIntegrityLevel, &label, size);
+ auto last_error = ::GetLastError();
+ ::LocalFree(integrity_sid);
+
+ return result ? ERROR_SUCCESS : last_error;
+}
+
+DWORD SetProcessIntegrityLevel(IntegrityLevel integrity_level) {
+ // We don't check for an invalid level here because we'll just let it
+ // fail on the SetTokenIntegrityLevel call later on.
+ if (integrity_level == INTEGRITY_LEVEL_LAST) {
+ // No mandatory level specified, we don't change it.
+ return ERROR_SUCCESS;
+ }
+
+ HANDLE token_handle;
+ if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT,
+ &token_handle))
+ return ::GetLastError();
+
+ base::win::ScopedHandle token(token_handle);
+
+ return SetTokenIntegrityLevel(token.Get(), integrity_level);
+}
+
+DWORD HardenTokenIntegrityLevelPolicy(HANDLE token) {
+ std::vector<char> security_desc_buffer;
+ PSECURITY_DESCRIPTOR security_desc = nullptr;
+ DWORD last_error = GetObjectSecurityDescriptor(
+ token, LABEL_SECURITY_INFORMATION, &security_desc_buffer, &security_desc);
+ if (last_error != ERROR_SUCCESS)
+ return last_error;
+
+ PACL sacl = nullptr;
+ BOOL sacl_present = false;
+ BOOL sacl_defaulted = false;
+
+ if (!::GetSecurityDescriptorSacl(security_desc, &sacl_present, &sacl,
+ &sacl_defaulted)) {
+ return ::GetLastError();
+ }
+
+ for (DWORD ace_index = 0; ace_index < sacl->AceCount; ++ace_index) {
+ PSYSTEM_MANDATORY_LABEL_ACE ace;
+
+ if (::GetAce(sacl, ace_index, reinterpret_cast<LPVOID*>(&ace)) &&
+ ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE) {
+ ace->Mask |= SYSTEM_MANDATORY_LABEL_NO_READ_UP |
+ SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP;
+ break;
+ }
+ }
+
+ if (!::SetKernelObjectSecurity(token, LABEL_SECURITY_INFORMATION,
+ security_desc))
+ return ::GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+DWORD HardenProcessIntegrityLevelPolicy() {
+ HANDLE token_handle;
+ if (!::OpenProcessToken(GetCurrentProcess(), READ_CONTROL | WRITE_OWNER,
+ &token_handle))
+ return ::GetLastError();
+
+ base::win::ScopedHandle token(token_handle);
+
+ return HardenTokenIntegrityLevelPolicy(token.Get());
+}
+
+DWORD CreateLowBoxToken(HANDLE base_token,
+ TokenType token_type,
+ PSECURITY_CAPABILITIES security_capabilities,
+ PHANDLE saved_handles,
+ DWORD saved_handles_count,
+ base::win::ScopedHandle* token) {
+ NtCreateLowBoxToken CreateLowBoxToken = nullptr;
+ ResolveNTFunctionPtr("NtCreateLowBoxToken", &CreateLowBoxToken);
+
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return ERROR_CALL_NOT_IMPLEMENTED;
+
+ if (token_type != PRIMARY && token_type != IMPERSONATION)
+ return ERROR_INVALID_PARAMETER;
+
+ if (!token)
+ return ERROR_INVALID_PARAMETER;
+
+ base::win::ScopedHandle base_token_handle;
+ if (!base_token) {
+ HANDLE process_token = nullptr;
+ if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS,
+ &process_token)) {
+ return ::GetLastError();
+ }
+ base_token_handle.Set(process_token);
+ base_token = process_token;
+ }
+ OBJECT_ATTRIBUTES obj_attr;
+ InitializeObjectAttributes(&obj_attr, nullptr, 0, nullptr, nullptr);
+ HANDLE token_lowbox = nullptr;
+
+ NTSTATUS status = CreateLowBoxToken(
+ &token_lowbox, base_token, TOKEN_ALL_ACCESS, &obj_attr,
+ security_capabilities->AppContainerSid,
+ security_capabilities->CapabilityCount,
+ security_capabilities->Capabilities, saved_handles_count,
+ saved_handles_count > 0 ? saved_handles : nullptr);
+ if (!NT_SUCCESS(status))
+ return GetLastErrorFromNtStatus(status);
+
+ base::win::ScopedHandle token_lowbox_handle(token_lowbox);
+ DCHECK(token_lowbox_handle.IsValid());
+
+ // Default from NtCreateLowBoxToken is a Primary token.
+ if (token_type == PRIMARY) {
+ *token = std::move(token_lowbox_handle);
+ return ERROR_SUCCESS;
+ }
+
+ HANDLE dup_handle = nullptr;
+ if (!::DuplicateTokenEx(token_lowbox_handle.Get(), TOKEN_ALL_ACCESS, nullptr,
+ ::SecurityImpersonation, ::TokenImpersonation,
+ &dup_handle)) {
+ return ::GetLastError();
+ }
+
+ // Copy security descriptor from primary token as the new object will have
+ // the DACL from the current token's default DACL.
+ base::win::ScopedHandle token_for_sd(dup_handle);
+ std::vector<char> security_desc_buffer;
+ PSECURITY_DESCRIPTOR security_desc = nullptr;
+ DWORD last_error = GetObjectSecurityDescriptor(
+ token_lowbox_handle.Get(), DACL_SECURITY_INFORMATION,
+ &security_desc_buffer, &security_desc);
+ if (last_error != ERROR_SUCCESS)
+ return last_error;
+
+ if (!::SetKernelObjectSecurity(token_for_sd.Get(), DACL_SECURITY_INFORMATION,
+ security_desc)) {
+ return ::GetLastError();
+ }
+
+ *token = std::move(token_for_sd);
+
+ return ERROR_SUCCESS;
+}
+
+DWORD CreateLowBoxObjectDirectory(PSID lowbox_sid,
+ bool open_directory,
+ base::win::ScopedHandle* directory) {
+ DWORD session_id = 0;
+ if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id))
+ return ::GetLastError();
+
+ LPWSTR sid_string = nullptr;
+ if (!::ConvertSidToStringSid(lowbox_sid, &sid_string))
+ return ::GetLastError();
+
+ std::unique_ptr<wchar_t, LocalFreeDeleter> sid_string_ptr(sid_string);
+ std::wstring directory_path = base::StringPrintf(
+ L"\\Sessions\\%d\\AppContainerNamedObjects\\%ls", session_id, sid_string);
+
+ NtCreateDirectoryObjectFunction CreateObjectDirectory = nullptr;
+ ResolveNTFunctionPtr("NtCreateDirectoryObject", &CreateObjectDirectory);
+
+ OBJECT_ATTRIBUTES obj_attr;
+ UNICODE_STRING obj_name;
+ DWORD attributes = OBJ_CASE_INSENSITIVE;
+ if (open_directory)
+ attributes |= OBJ_OPENIF;
+
+ sandbox::InitObjectAttribs(directory_path, attributes, nullptr, &obj_attr,
+ &obj_name, nullptr);
+
+ HANDLE handle = nullptr;
+ NTSTATUS status =
+ CreateObjectDirectory(&handle, DIRECTORY_ALL_ACCESS, &obj_attr);
+
+ if (!NT_SUCCESS(status))
+ return GetLastErrorFromNtStatus(status);
+ directory->Set(handle);
+
+ return ERROR_SUCCESS;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
new file mode 100644
index 0000000000..e1f75a89c9
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_RESTRICTED_TOKEN_UTILS_H__
+#define SANDBOX_SRC_RESTRICTED_TOKEN_UTILS_H__
+
+#include <accctrl.h>
+#include <windows.h>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/restricted_token.h"
+#include "sandbox/win/src/security_level.h"
+
+// Contains the utility functions to be able to create restricted tokens based
+// on a security profiles.
+
+namespace sandbox {
+
+// The type of the token returned by the CreateNakedToken.
+enum TokenType { IMPERSONATION = 0, PRIMARY };
+
+// Creates a restricted token from effective token. If it's nullptr then
+// effective token of process is used instead. The parameter security_level
+// determines how much the token isrestricted. The token_type determines if
+// the token will be used as a primarytoken or impersonation token. The
+// integrity level of the token is set to |integrity level| on Vista only.
+// |token| is the output value containing the handle of the newly created
+// restricted token.
+// |lockdown_default_dacl| indicates the token's default DACL should be locked
+// down to restrict what other process can open kernel resources created while
+// running under the token.
+// If the function succeeds, the return value is ERROR_SUCCESS. If the
+// function fails, the return value is the win32 error code corresponding to
+// the error.
+DWORD CreateRestrictedToken(HANDLE effective_token,
+ TokenLevel security_level,
+ IntegrityLevel integrity_level,
+ TokenType token_type,
+ bool lockdown_default_dacl,
+ PSID unique_restricted_sid,
+ bool use_restricting_sids,
+ base::win::ScopedHandle* token);
+
+// Sets the integrity label on a object handle.
+DWORD SetObjectIntegrityLabel(HANDLE handle,
+ SE_OBJECT_TYPE type,
+ const wchar_t* ace_access,
+ const wchar_t* integrity_level_sid);
+
+// Sets the integrity level on a token. This is only valid on Vista. It returns
+// without failing on XP. If the integrity level that you specify is greater
+// than the current integrity level, the function will fail.
+DWORD SetTokenIntegrityLevel(HANDLE token, IntegrityLevel integrity_level);
+
+// Returns the integrity level SDDL string associated with a given
+// IntegrityLevel value.
+const wchar_t* GetIntegrityLevelString(IntegrityLevel integrity_level);
+
+// Sets the integrity level on the current process on Vista. It returns without
+// failing on XP. If the integrity level that you specify is greater than the
+// current integrity level, the function will fail.
+DWORD SetProcessIntegrityLevel(IntegrityLevel integrity_level);
+
+// Hardens the integrity level policy on a token. This is only valid on Win 7
+// and above. Specifically it sets the policy to block read and execute so
+// that a lower privileged process cannot open the token for impersonate or
+// duplicate permissions. This should limit potential security holes.
+DWORD HardenTokenIntegrityLevelPolicy(HANDLE token);
+
+// Hardens the integrity level policy on the current process. This is only
+// valid on Win 7 and above. Specifically it sets the policy to block read
+// and execute so that a lower privileged process cannot open the token for
+// impersonate or duplicate permissions. This should limit potential security
+// holes.
+DWORD HardenProcessIntegrityLevelPolicy();
+
+// Create a lowbox token. This is not valid prior to Windows 8.
+// |base_token| a base token to derive the lowbox token from. Can be nullptr.
+// |security_capabilities| list of LowBox capabilities to use when creating the
+// token.
+// |token| is the output value containing the handle of the newly created
+// restricted token.
+// |lockdown_default_dacl| indicates the token's default DACL should be locked
+// down to restrict what other process can open kernel resources created while
+// running under the token.
+DWORD CreateLowBoxToken(HANDLE base_token,
+ TokenType token_type,
+ PSECURITY_CAPABILITIES security_capabilities,
+ PHANDLE saved_handles,
+ DWORD saved_handles_count,
+ base::win::ScopedHandle* token);
+
+// Create a lowbox object directory token. This is not valid prior to Windows 8.
+// This returns the Win32 error code from the operation.
+// |lowbox_sid| the SID for the LowBox.
+// |open_directory| open the directory if it already exists.
+// |directory| is the output value for the directory object.
+DWORD CreateLowBoxObjectDirectory(PSID lowbox_sid,
+ bool open_directory,
+ base::win::ScopedHandle* directory);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_RESTRICTED_TOKEN_UTILS_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.cc b/security/sandbox/chromium/sandbox/win/src/sandbox.cc
new file mode 100644
index 0000000000..f65e379683
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox.h"
+
+#include <windows.h>
+
+#include "sandbox/win/src/broker_services.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+// The section for IPC and policy.
+SANDBOX_INTERCEPT HANDLE g_shared_section;
+static bool s_is_broker = false;
+
+// GetBrokerServices: the current implementation relies on a shared section
+// that is created by the broker and opened by the target.
+BrokerServices* SandboxFactory::GetBrokerServices() {
+ // Can't be the broker if the shared section is open.
+ if (g_shared_section)
+ return nullptr;
+ // If the shared section does not exist we are the broker, then create
+ // the broker object.
+ s_is_broker = true;
+ return BrokerServicesBase::GetInstance();
+}
+
+// GetTargetServices implementation must follow the same technique as the
+// GetBrokerServices, but in this case the logic is the opposite.
+TargetServices* SandboxFactory::GetTargetServices() {
+ // Can't be the target if the section handle is not valid.
+ if (!g_shared_section)
+ return nullptr;
+ // We are the target
+ s_is_broker = false;
+ // Creates and returns the target services implementation.
+ return TargetServicesBase::GetInstance();
+}
+
+} // namespace sandbox
+
+// Allows querying for whether the current process has been sandboxed.
+extern "C" bool __declspec(dllexport) IsSandboxedProcess() {
+ return !!sandbox::g_shared_section;
+}
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sandbox/chromium/sandbox/win/src/sandbox.h
new file mode 100644
index 0000000000..858c350558
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox.h
@@ -0,0 +1,228 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Sandbox is a sandbox library for windows processes. Use when you want a
+// 'privileged' process and a 'locked down process' to interact with.
+// The privileged process is called the broker and it is started by external
+// means (such as the user starting it). The 'sandboxed' process is called the
+// target and it is started by the broker. There can be many target processes
+// started by a single broker process. This library provides facilities
+// for both the broker and the target.
+//
+// The design rationale and relevant documents can be found at http://go/sbox.
+//
+// Note: this header does not include the SandboxFactory definitions because
+// there are cases where the Sandbox library is linked against the main .exe
+// while its API needs to be used in a DLL.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_H_
+#define SANDBOX_WIN_SRC_SANDBOX_H_
+
+#if !defined(SANDBOX_FUZZ_TARGET)
+#include <windows.h>
+#else
+#include "sandbox/win/fuzzer/fuzzer_types.h"
+#endif
+
+#include <stddef.h>
+#include <memory>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+// sandbox: Google User-Land Application Sandbox
+namespace sandbox {
+
+class BrokerServices;
+class PolicyDiagnosticsReceiver;
+class ProcessState;
+class TargetPolicy;
+class TargetServices;
+
+// BrokerServices exposes all the broker API.
+// The basic use is to start the target(s) and wait for them to end.
+//
+// This API is intended to be called in the following order
+// (error checking omitted):
+// BrokerServices* broker = SandboxFactory::GetBrokerServices();
+// broker->Init();
+// PROCESS_INFORMATION target;
+// broker->SpawnTarget(target_exe_path, target_args, &target);
+// ::ResumeThread(target->hThread);
+// // -- later you can call:
+// broker->WaitForAllTargets(option);
+//
+class BrokerServices {
+ public:
+ // Initializes the broker. Must be called before any other on this class.
+ // returns ALL_OK if successful. All other return values imply failure.
+ // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+ // more information.
+ virtual ResultCode Init() = 0;
+
+ // Returns the interface pointer to a new, empty policy object. Use this
+ // interface to specify the sandbox policy for new processes created by
+ // SpawnTarget()
+ virtual scoped_refptr<TargetPolicy> CreatePolicy() = 0;
+
+ // Creates a new target (child process) in a suspended state.
+ // Parameters:
+ // exe_path: This is the full path to the target binary. This parameter
+ // can be null and in this case the exe path must be the first argument
+ // of the command_line.
+ // command_line: The arguments to be passed as command line to the new
+ // process. This can be null if the exe_path parameter is not null.
+ // policy: This is the pointer to the policy object for the sandbox to
+ // be created.
+ // last_warning: The argument will contain an indication on whether
+ // the process security was initialized completely, Only set if the
+ // process can be used without a serious compromise in security.
+ // last_error: If an error or warning is returned from this method this
+ // parameter will hold the last Win32 error value.
+ // target: returns the resulting target process information such as process
+ // handle and PID just as if CreateProcess() had been called. The caller is
+ // responsible for closing the handles returned in this structure.
+ // Returns:
+ // ALL_OK if successful. All other return values imply failure.
+ virtual ResultCode SpawnTarget(const wchar_t* exe_path,
+ const wchar_t* command_line,
+ base::EnvironmentMap& env_map,
+ scoped_refptr<TargetPolicy> policy,
+ ResultCode* last_warning,
+ DWORD* last_error,
+ PROCESS_INFORMATION* target) = 0;
+
+ // This call blocks (waits) for all the targets to terminate.
+ // Returns:
+ // ALL_OK if successful. All other return values imply failure.
+ // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+ // more information.
+ virtual ResultCode WaitForAllTargets() = 0;
+
+ // Adds an unsandboxed process as a peer for policy decisions (e.g.
+ // HANDLES_DUP_ANY policy).
+ // Returns:
+ // ALL_OK if successful. All other return values imply failure.
+ // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+ // more information.
+ virtual ResultCode AddTargetPeer(HANDLE peer_process) = 0;
+
+ // This call creates a snapshot of policies managed by the sandbox and
+ // returns them via a helper class.
+ // Parameters:
+ // receiver: The |PolicyDiagnosticsReceiver| implementation will be
+ // called to accept the results of the call.
+ // Returns:
+ // ALL_OK if the request was dispatched. All other return values
+ // imply failure, and the responder will not receive its completion
+ // callback.
+ virtual ResultCode GetPolicyDiagnostics(
+ std::unique_ptr<PolicyDiagnosticsReceiver> receiver) = 0;
+
+ // Derive a capability PSID from the given string.
+ virtual bool DeriveCapabilitySidFromName(const wchar_t* name,
+ PSID derived_sid,
+ DWORD sid_buffer_length) = 0;
+
+ protected:
+ ~BrokerServices() {}
+};
+
+// TargetServices models the current process from the perspective
+// of a target process. To obtain a pointer to it use
+// Sandbox::GetTargetServices(). Note that this call returns a non-null
+// pointer only if this process is in fact a target. A process is a target
+// only if the process was spawned by a call to BrokerServices::SpawnTarget().
+//
+// This API allows the target to gain access to resources with a high
+// privilege token and then when it is ready to perform dangerous activities
+// (such as download content from the web) it can lower its token and
+// enter into locked-down (sandbox) mode.
+// The typical usage is as follows:
+//
+// TargetServices* target_services = Sandbox::GetTargetServices();
+// if (target_services) {
+// // We are the target.
+// target_services->Init();
+// // Do work that requires high privileges here.
+// // ....
+// // When ready to enter lock-down mode call LowerToken:
+// target_services->LowerToken();
+// }
+//
+// For more information see the BrokerServices API documentation.
+class TargetServices {
+ public:
+ // Initializes the target. Must call this function before any other.
+ // returns ALL_OK if successful. All other return values imply failure.
+ // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+ // more information.
+ virtual ResultCode Init() = 0;
+
+ // Discards the impersonation token and uses the lower token, call before
+ // processing any untrusted data or running third-party code. If this call
+ // fails the current process could be terminated immediately.
+ virtual void LowerToken() = 0;
+
+ // Returns the ProcessState object. Through that object it's possible to have
+ // information about the current state of the process, such as whether
+ // LowerToken has been called or not.
+ virtual ProcessState* GetState() = 0;
+
+ // Requests the broker to duplicate the supplied handle into the target
+ // process. The target process must be an active sandbox child process
+ // and the source process must have a corresponding policy allowing
+ // handle duplication for this object type.
+ // Returns:
+ // ALL_OK if successful. All other return values imply failure.
+ // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
+ // more information.
+ virtual ResultCode DuplicateHandle(HANDLE source_handle,
+ DWORD target_process_id,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ DWORD options) = 0;
+
+ virtual ResultCode GetComplexLineBreaks(const WCHAR* text, uint32_t length,
+ uint8_t* break_before) = 0;
+
+ protected:
+ ~TargetServices() {}
+};
+
+class PolicyInfo {
+ public:
+ // Returns a JSON representation of the policy snapshot.
+ // This pointer has the same lifetime as this PolicyInfo object.
+ virtual const char* JsonString() = 0;
+ virtual ~PolicyInfo() {}
+};
+
+// This is returned by BrokerServices::GetPolicyDiagnostics().
+// PolicyInfo entries need not be ordered.
+class PolicyList {
+ public:
+ virtual std::vector<std::unique_ptr<PolicyInfo>>::iterator begin() = 0;
+ virtual std::vector<std::unique_ptr<PolicyInfo>>::iterator end() = 0;
+ virtual size_t size() const = 0;
+ virtual ~PolicyList() {}
+};
+
+// This class mediates calls to BrokerServices::GetPolicyDiagnostics().
+class PolicyDiagnosticsReceiver {
+ public:
+ // ReceiveDiagnostics() should return quickly and should not block the
+ // thread on which it is called.
+ virtual void ReceiveDiagnostics(std::unique_ptr<PolicyList> policies) = 0;
+ // OnError() is passed any errors encountered and |ReceiveDiagnostics|
+ // will not be called.
+ virtual void OnError(ResultCode code) = 0;
+ virtual ~PolicyDiagnosticsReceiver() {}
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SANDBOX_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.vcproj b/security/sandbox/chromium/sandbox/win/src/sandbox.vcproj
new file mode 100644
index 0000000000..229441cbd5
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox.vcproj
@@ -0,0 +1,648 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="sandbox"
+ ProjectGUID="{881F6A97-D539-4C48-B401-DF04385B2343}"
+ RootNamespace="sandbox"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\debug.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="2"
+ ForcedIncludeFiles="stdafx.h"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(SolutionDir)..\build\release.vsprops;$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\testing\using_gtest.vsprops"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="security"
+ >
+ <File
+ RelativePath=".\acl.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\acl.h"
+ >
+ </File>
+ <File
+ RelativePath=".\dep.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\dep.h"
+ >
+ </File>
+ <File
+ RelativePath=".\job.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\job.h"
+ >
+ </File>
+ <File
+ RelativePath=".\restricted_token.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\restricted_token.h"
+ >
+ </File>
+ <File
+ RelativePath=".\restricted_token_utils.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\restricted_token_utils.h"
+ >
+ </File>
+ <File
+ RelativePath=".\security_level.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sid.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sid.h"
+ >
+ </File>
+ <File
+ RelativePath=".\window.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\window.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Interception"
+ >
+ <File
+ RelativePath=".\eat_resolver.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\eat_resolver.h"
+ >
+ </File>
+ <File
+ RelativePath=".\interception.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\interception.h"
+ >
+ </File>
+ <File
+ RelativePath=".\interception_agent.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\interception_agent.h"
+ >
+ </File>
+ <File
+ RelativePath=".\interception_internal.h"
+ >
+ </File>
+ <File
+ RelativePath=".\pe_image.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\pe_image.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resolver.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\resolver.h"
+ >
+ </File>
+ <File
+ RelativePath=".\service_resolver.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\service_resolver.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep_resolver.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep_resolver.h"
+ >
+ </File>
+ <File
+ RelativePath=".\target_interceptions.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\target_interceptions.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Wow64.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\Wow64.h"
+ >
+ </File>
+ <Filter
+ Name="sidestep"
+ >
+ <File
+ RelativePath=".\sidestep\ia32_modrm_map.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep\ia32_opcode_map.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep\mini_disassembler.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep\mini_disassembler.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep\mini_disassembler_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep\preamble_patcher.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sidestep\preamble_patcher_with_stub.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="nt_level"
+ >
+ <File
+ RelativePath=".\nt_internals.h"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_target.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_target.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_nt_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_nt_util.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_nt_util.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Policy_handlers"
+ >
+ <File
+ RelativePath=".\filesystem_dispatcher.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\filesystem_dispatcher.h"
+ >
+ </File>
+ <File
+ RelativePath=".\filesystem_interception.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\filesystem_interception.h"
+ >
+ </File>
+ <File
+ RelativePath=".\filesystem_policy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\filesystem_policy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\named_pipe_dispatcher.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\named_pipe_dispatcher.h"
+ >
+ </File>
+ <File
+ RelativePath=".\named_pipe_interception.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\named_pipe_interception.h"
+ >
+ </File>
+ <File
+ RelativePath=".\named_pipe_policy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\named_pipe_policy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_params.h"
+ >
+ </File>
+ <File
+ RelativePath=".\process_thread_dispatcher.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\process_thread_dispatcher.h"
+ >
+ </File>
+ <File
+ RelativePath=".\process_thread_interception.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\process_thread_interception.h"
+ >
+ </File>
+ <File
+ RelativePath=".\process_thread_policy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\process_thread_policy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\registry_dispatcher.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\registry_dispatcher.h"
+ >
+ </File>
+ <File
+ RelativePath=".\registry_interception.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\registry_interception.h"
+ >
+ </File>
+ <File
+ RelativePath=".\registry_policy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\registry_policy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sync_dispatcher.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sync_dispatcher.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sync_interception.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sync_interception.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sync_policy.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sync_policy.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="IPC"
+ >
+ <File
+ RelativePath=".\crosscall_client.h"
+ >
+ </File>
+ <File
+ RelativePath=".\crosscall_params.h"
+ >
+ </File>
+ <File
+ RelativePath=".\crosscall_server.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\crosscall_server.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ipc_tags.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sharedmem_ipc_client.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sharedmem_ipc_client.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sharedmem_ipc_server.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sharedmem_ipc_server.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Policy_base"
+ >
+ <File
+ RelativePath=".\policy_engine_opcodes.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_engine_opcodes.h"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_engine_params.h"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_engine_processor.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_engine_processor.h"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_low_level.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_low_level.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_policy_base.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_policy_base.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\broker_services.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\broker_services.h"
+ >
+ </File>
+ <File
+ RelativePath=".\internal_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_broker.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\policy_broker.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_factory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_policy.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_types.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_utils.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\sandbox_utils.h"
+ >
+ </File>
+ <File
+ RelativePath=".\shared_handles.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\shared_handles.h"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\target_process.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\target_process.h"
+ >
+ </File>
+ <File
+ RelativePath=".\target_services.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\target_services.h"
+ >
+ </File>
+ <File
+ RelativePath=".\win2k_threadpool.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\win2k_threadpool.h"
+ >
+ </File>
+ <File
+ RelativePath=".\win_utils.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\win_utils.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_factory.h b/security/sandbox/chromium/sandbox/win/src/sandbox_factory.h
new file mode 100644
index 0000000000..07402521dc
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_factory.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_FACTORY_H__
+#define SANDBOX_SRC_SANDBOX_FACTORY_H__
+
+#include "base/macros.h"
+#include "sandbox/win/src/sandbox.h"
+
+// SandboxFactory is a set of static methods to get access to the broker
+// or target services object. Only one of the two methods (GetBrokerServices,
+// GetTargetServices) will return a non-null pointer and that should be used
+// as the indication that the process is the broker or the target:
+//
+// BrokerServices* broker_services = SandboxFactory::GetBrokerServices();
+// if (broker_services) {
+// //we are the broker, call broker api here
+// broker_services->Init();
+// } else {
+// TargetServices* target_services = SandboxFactory::GetTargetServices();
+// if (target_services) {
+// //we are the target, call target api here
+// target_services->Init();
+// }
+//
+// The methods in this class are expected to be called from a single thread
+//
+// The Sandbox library needs to be linked against the main executable, but
+// sometimes the API calls are issued from a DLL that loads into the exe
+// process. These factory methods then need to be called from the main
+// exe and the interface pointers then can be safely passed to the DLL where
+// the Sandbox API calls are made.
+namespace sandbox {
+
+class SandboxFactory {
+ public:
+ // Returns the Broker API interface, returns nullptr if this process is the
+ // target.
+ static BrokerServices* GetBrokerServices();
+
+ // Returns the Target API interface, returns nullptr if this process is the
+ // broker.
+ static TargetServices* GetTargetServices();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SandboxFactory);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SANDBOX_FACTORY_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_globals.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_globals.cc
new file mode 100644
index 0000000000..3387e3f604
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_globals.cc
@@ -0,0 +1,18 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+// The section for IPC and policy.
+SANDBOX_INTERCEPT HANDLE g_shared_section = nullptr;
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt = {};
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_nt_types.h b/security/sandbox/chromium/sandbox/win/src/sandbox_nt_types.h
new file mode 100644
index 0000000000..eff0f019d3
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_nt_types.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_NT_TYPES_H__
+#define SANDBOX_SRC_SANDBOX_NT_TYPES_H__
+
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+struct NtExports {
+ NtAllocateVirtualMemoryFunction AllocateVirtualMemory;
+ NtCloseFunction Close;
+ NtDuplicateObjectFunction DuplicateObject;
+ NtFreeVirtualMemoryFunction FreeVirtualMemory;
+ NtMapViewOfSectionFunction MapViewOfSection;
+ NtProtectVirtualMemoryFunction ProtectVirtualMemory;
+ NtQueryInformationProcessFunction QueryInformationProcess;
+ NtQueryObjectFunction QueryObject;
+ NtQuerySectionFunction QuerySection;
+ NtQueryVirtualMemoryFunction QueryVirtualMemory;
+ NtUnmapViewOfSectionFunction UnmapViewOfSection;
+ NtSignalAndWaitForSingleObjectFunction SignalAndWaitForSingleObject;
+ NtWaitForSingleObjectFunction WaitForSingleObject;
+ RtlAllocateHeapFunction RtlAllocateHeap;
+ RtlAnsiStringToUnicodeStringFunction RtlAnsiStringToUnicodeString;
+ RtlCompareUnicodeStringFunction RtlCompareUnicodeString;
+ RtlCreateHeapFunction RtlCreateHeap;
+ RtlCreateUserThreadFunction RtlCreateUserThread;
+ RtlDestroyHeapFunction RtlDestroyHeap;
+ RtlFreeHeapFunction RtlFreeHeap;
+ _strnicmpFunction _strnicmp;
+ strlenFunction strlen;
+ wcslenFunction wcslen;
+ memcpyFunction memcpy;
+};
+
+// This is the value used for the ntdll level allocator.
+enum AllocationType {
+ NT_ALLOC,
+ NT_PAGE
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SANDBOX_NT_TYPES_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.cc
new file mode 100644
index 0000000000..2641a13d04
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.cc
@@ -0,0 +1,755 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+
+namespace sandbox {
+
+// This is the list of all imported symbols from ntdll.dll.
+SANDBOX_INTERCEPT NtExports g_nt;
+
+} // namespace sandbox
+
+namespace {
+
+#if defined(_WIN64)
+// Align a pointer to the next allocation granularity boundary.
+inline char* AlignToBoundary(void* ptr, size_t increment) {
+ const size_t kAllocationGranularity = (64 * 1024) - 1;
+ uintptr_t ptr_int = reinterpret_cast<uintptr_t>(ptr);
+ uintptr_t ret_ptr =
+ (ptr_int + increment + kAllocationGranularity) & ~kAllocationGranularity;
+ // Check for overflow.
+ if (ret_ptr < ptr_int)
+ return nullptr;
+ return reinterpret_cast<char*>(ret_ptr);
+}
+
+// Allocate a memory block somewhere within 2GiB of a specified base address.
+// This is used for the DLL hooking code to get a valid trampoline location
+// which must be within +/- 2GiB of the base. We only consider +2GiB for now.
+void* AllocateNearTo(void* source, size_t size) {
+ using sandbox::g_nt;
+ // 2GiB, maximum upper bound the allocation address must be within.
+ const size_t kMaxSize = 0x80000000ULL;
+ // We don't support null as a base as this would just pick an arbitrary
+ // address when passed to NtAllocateVirtualMemory.
+ if (!source)
+ return nullptr;
+ // Ignore an allocation which is larger than the maximum.
+ if (size > kMaxSize)
+ return nullptr;
+
+ // Ensure base address is aligned to the allocation granularity boundary.
+ char* base = AlignToBoundary(source, 0);
+ if (!base)
+ return nullptr;
+ // Set top address to be base + 2GiB.
+ const char* top_address = base + kMaxSize;
+
+ while (base < top_address) {
+ // Avoid memset inserted by -ftrivial-auto-var-init=pattern.
+ STACK_UNINITIALIZED MEMORY_BASIC_INFORMATION mem_info;
+ NTSTATUS status =
+ g_nt.QueryVirtualMemory(NtCurrentProcess, base, MemoryBasicInformation,
+ &mem_info, sizeof(mem_info), nullptr);
+ if (!NT_SUCCESS(status))
+ break;
+
+ if ((mem_info.State == MEM_FREE) && (mem_info.RegionSize >= size)) {
+ // We've found a valid free block, try and allocate it for use.
+ // Note that we need to both commit and reserve the block for the
+ // allocation to succeed as per Windows virtual memory requirements.
+ void* ret_base = mem_info.BaseAddress;
+ status =
+ g_nt.AllocateVirtualMemory(NtCurrentProcess, &ret_base, 0, &size,
+ MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ // Shouldn't fail, but if it does we'll just continue and try next block.
+ if (NT_SUCCESS(status))
+ return ret_base;
+ }
+
+ // Update base past current allocation region.
+ base = AlignToBoundary(mem_info.BaseAddress, mem_info.RegionSize);
+ if (!base)
+ break;
+ }
+ return nullptr;
+}
+#else // defined(_WIN64).
+void* AllocateNearTo(void* source, size_t size) {
+ using sandbox::g_nt;
+
+ // In 32-bit processes allocations below 512k are predictable, so mark
+ // anything in that range as reserved and retry until we get a good address.
+ const void* const kMinAddress = reinterpret_cast<void*>(512 * 1024);
+ NTSTATUS ret;
+ SIZE_T actual_size;
+ void* base;
+ do {
+ base = nullptr;
+ actual_size = 64 * 1024;
+ ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size,
+ MEM_RESERVE, PAGE_NOACCESS);
+ if (!NT_SUCCESS(ret))
+ return nullptr;
+ } while (base < kMinAddress);
+
+ actual_size = size;
+ ret = g_nt.AllocateVirtualMemory(NtCurrentProcess, &base, 0, &actual_size,
+ MEM_COMMIT, PAGE_READWRITE);
+ if (!NT_SUCCESS(ret))
+ return nullptr;
+ return base;
+}
+#endif // defined(_WIN64).
+
+} // namespace.
+
+namespace sandbox {
+
+// Handle for our private heap.
+void* g_heap = nullptr;
+
+SANDBOX_INTERCEPT HANDLE g_shared_section;
+SANDBOX_INTERCEPT size_t g_shared_IPC_size = 0;
+SANDBOX_INTERCEPT size_t g_shared_policy_size = 0;
+
+void* volatile g_shared_policy_memory = nullptr;
+void* volatile g_shared_IPC_memory = nullptr;
+
+// Both the IPC and the policy share a single region of memory in which the IPC
+// memory is first and the policy memory is last.
+bool MapGlobalMemory() {
+ if (!g_shared_IPC_memory) {
+ void* memory = nullptr;
+ SIZE_T size = 0;
+ // Map the entire shared section from the start.
+ NTSTATUS ret =
+ g_nt.MapViewOfSection(g_shared_section, NtCurrentProcess, &memory, 0, 0,
+ nullptr, &size, ViewUnmap, 0, PAGE_READWRITE);
+
+ if (!NT_SUCCESS(ret) || !memory) {
+ NOTREACHED_NT();
+ return false;
+ }
+
+ if (_InterlockedCompareExchangePointer(&g_shared_IPC_memory, memory,
+ nullptr)) {
+ // Somebody beat us to the memory setup.
+ VERIFY_SUCCESS(g_nt.UnmapViewOfSection(NtCurrentProcess, memory));
+ }
+ DCHECK_NT(g_shared_IPC_size > 0);
+ g_shared_policy_memory =
+ reinterpret_cast<char*>(g_shared_IPC_memory) + g_shared_IPC_size;
+ }
+ DCHECK_NT(g_shared_policy_memory);
+ DCHECK_NT(g_shared_policy_size > 0);
+ return true;
+}
+
+void* GetGlobalIPCMemory() {
+ if (!MapGlobalMemory())
+ return nullptr;
+ return g_shared_IPC_memory;
+}
+
+void* GetGlobalPolicyMemory() {
+ if (!MapGlobalMemory())
+ return nullptr;
+ return g_shared_policy_memory;
+}
+
+bool InitHeap() {
+ if (!g_heap) {
+ // Create a new heap using default values for everything.
+ void* heap =
+ g_nt.RtlCreateHeap(HEAP_GROWABLE, nullptr, 0, 0, nullptr, nullptr);
+ if (!heap)
+ return false;
+
+ if (_InterlockedCompareExchangePointer(&g_heap, heap, nullptr)) {
+ // Somebody beat us to the memory setup.
+ g_nt.RtlDestroyHeap(heap);
+ }
+ }
+ return !!g_heap;
+}
+
+// Physically reads or writes from memory to verify that (at this time), it is
+// valid. Returns a dummy value.
+int TouchMemory(void* buffer, size_t size_bytes, RequiredAccess intent) {
+ const int kPageSize = 4096;
+ int dummy = 0;
+ volatile char* start = reinterpret_cast<char*>(buffer);
+ volatile char* end = start + size_bytes - 1;
+
+ if (WRITE == intent) {
+ for (; start < end; start += kPageSize) {
+ *start = *start;
+ }
+ *end = *end;
+ } else {
+ for (; start < end; start += kPageSize) {
+ dummy += *start;
+ }
+ dummy += *end;
+ }
+
+ return dummy;
+}
+
+bool ValidParameter(void* buffer, size_t size, RequiredAccess intent) {
+ DCHECK_NT(size);
+ __try {
+ TouchMemory(buffer, size, intent);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ return false;
+ }
+ return true;
+}
+
+NTSTATUS CopyData(void* destination, const void* source, size_t bytes) {
+ NTSTATUS ret = STATUS_SUCCESS;
+ __try {
+ g_nt.memcpy(destination, source, bytes);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ ret = GetExceptionCode();
+ }
+ return ret;
+}
+
+NTSTATUS AllocAndGetFullPath(
+ HANDLE root,
+ const wchar_t* path,
+ std::unique_ptr<wchar_t, NtAllocDeleter>* full_path) {
+ if (!InitHeap())
+ return STATUS_NO_MEMORY;
+
+ DCHECK_NT(full_path);
+ DCHECK_NT(path);
+ NTSTATUS ret = STATUS_UNSUCCESSFUL;
+ __try {
+ do {
+ static NtQueryObjectFunction NtQueryObject = nullptr;
+ if (!NtQueryObject)
+ ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
+
+ ULONG size = 0;
+ // Query the name information a first time to get the size of the name.
+ ret = NtQueryObject(root, ObjectNameInformation, nullptr, 0, &size);
+
+ std::unique_ptr<OBJECT_NAME_INFORMATION, NtAllocDeleter> handle_name;
+ if (size) {
+ handle_name.reset(reinterpret_cast<OBJECT_NAME_INFORMATION*>(
+ new (NT_ALLOC) BYTE[size]));
+
+ // Query the name information a second time to get the name of the
+ // object referenced by the handle.
+ ret = NtQueryObject(root, ObjectNameInformation, handle_name.get(),
+ size, &size);
+ }
+
+ if (STATUS_SUCCESS != ret)
+ break;
+
+ // Space for path + '\' + name + '\0'.
+ size_t name_length =
+ handle_name->ObjectName.Length + (wcslen(path) + 2) * sizeof(wchar_t);
+ full_path->reset(new (NT_ALLOC) wchar_t[name_length / sizeof(wchar_t)]);
+ if (!*full_path)
+ break;
+ wchar_t* off = full_path->get();
+ ret = CopyData(off, handle_name->ObjectName.Buffer,
+ handle_name->ObjectName.Length);
+ if (!NT_SUCCESS(ret))
+ break;
+ off += handle_name->ObjectName.Length / sizeof(wchar_t);
+ *off = L'\\';
+ off += 1;
+ ret = CopyData(off, path, wcslen(path) * sizeof(wchar_t));
+ if (!NT_SUCCESS(ret))
+ break;
+ off += wcslen(path);
+ *off = L'\0';
+ } while (false);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ ret = GetExceptionCode();
+ }
+
+ if (!NT_SUCCESS(ret) && *full_path)
+ full_path->reset(nullptr);
+
+ return ret;
+}
+
+// Hacky code... replace with AllocAndCopyObjectAttributes.
+NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
+ std::unique_ptr<wchar_t, NtAllocDeleter>* out_name,
+ uint32_t* attributes,
+ HANDLE* root) {
+ if (!InitHeap())
+ return STATUS_NO_MEMORY;
+
+ DCHECK_NT(out_name);
+ NTSTATUS ret = STATUS_UNSUCCESSFUL;
+ __try {
+ do {
+ if (in_object->RootDirectory != static_cast<HANDLE>(0) && !root)
+ break;
+ if (!in_object->ObjectName)
+ break;
+ if (!in_object->ObjectName->Buffer)
+ break;
+
+ size_t size = in_object->ObjectName->Length + sizeof(wchar_t);
+ out_name->reset(new (NT_ALLOC) wchar_t[size / sizeof(wchar_t)]);
+ if (!*out_name)
+ break;
+
+ ret = CopyData(out_name->get(), in_object->ObjectName->Buffer,
+ size - sizeof(wchar_t));
+ if (!NT_SUCCESS(ret))
+ break;
+
+ out_name->get()[size / sizeof(wchar_t) - 1] = L'\0';
+
+ if (attributes)
+ *attributes = in_object->Attributes;
+
+ if (root)
+ *root = in_object->RootDirectory;
+ ret = STATUS_SUCCESS;
+ } while (false);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ ret = GetExceptionCode();
+ }
+
+ if (!NT_SUCCESS(ret) && *out_name)
+ out_name->reset(nullptr);
+
+ return ret;
+}
+
+NTSTATUS GetProcessId(HANDLE process, DWORD* process_id) {
+ PROCESS_BASIC_INFORMATION proc_info;
+ ULONG bytes_returned;
+
+ NTSTATUS ret =
+ g_nt.QueryInformationProcess(process, ProcessBasicInformation, &proc_info,
+ sizeof(proc_info), &bytes_returned);
+ if (!NT_SUCCESS(ret) || sizeof(proc_info) != bytes_returned)
+ return ret;
+
+ *process_id = proc_info.UniqueProcessId;
+ return STATUS_SUCCESS;
+}
+
+bool IsSameProcess(HANDLE process) {
+ if (NtCurrentProcess == process)
+ return true;
+
+ static DWORD s_process_id = 0;
+
+ if (!s_process_id) {
+ NTSTATUS ret = GetProcessId(NtCurrentProcess, &s_process_id);
+ if (!NT_SUCCESS(ret))
+ return false;
+ }
+
+ DWORD process_id;
+ NTSTATUS ret = GetProcessId(process, &process_id);
+ if (!NT_SUCCESS(ret))
+ return false;
+
+ return (process_id == s_process_id);
+}
+
+bool IsValidImageSection(HANDLE section,
+ PVOID* base,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size) {
+ if (!section || !base || !view_size || offset)
+ return false;
+
+ HANDLE query_section;
+
+ NTSTATUS ret =
+ g_nt.DuplicateObject(NtCurrentProcess, section, NtCurrentProcess,
+ &query_section, SECTION_QUERY, 0, 0);
+ if (!NT_SUCCESS(ret))
+ return false;
+
+ SECTION_BASIC_INFORMATION basic_info;
+ SIZE_T bytes_returned;
+ ret = g_nt.QuerySection(query_section, SectionBasicInformation, &basic_info,
+ sizeof(basic_info), &bytes_returned);
+
+ VERIFY_SUCCESS(g_nt.Close(query_section));
+
+ if (!NT_SUCCESS(ret) || sizeof(basic_info) != bytes_returned)
+ return false;
+
+ if (!(basic_info.Attributes & SEC_IMAGE))
+ return false;
+
+ // Windows 10 2009+ may open PEs as SEC_IMAGE_NO_EXECUTE in non-dll-loading
+ // paths which looks identical to dll-loading unless we check if the section
+ // handle has execute rights.
+ // Avoid memset inserted by -ftrivial-auto-var-init=pattern.
+ STACK_UNINITIALIZED OBJECT_BASIC_INFORMATION obj_info;
+ ULONG obj_size_returned;
+ ret = g_nt.QueryObject(section, ObjectBasicInformation, &obj_info,
+ sizeof(obj_info), &obj_size_returned);
+
+ if (!NT_SUCCESS(ret) || sizeof(obj_info) != obj_size_returned)
+ return false;
+
+ if (!(obj_info.GrantedAccess & SECTION_MAP_EXECUTE))
+ return false;
+
+ return true;
+}
+
+UNICODE_STRING* AnsiToUnicode(const char* string) {
+ ANSI_STRING ansi_string;
+ ansi_string.Length = static_cast<USHORT>(g_nt.strlen(string));
+ ansi_string.MaximumLength = ansi_string.Length + 1;
+ ansi_string.Buffer = const_cast<char*>(string);
+
+ if (ansi_string.Length > ansi_string.MaximumLength)
+ return nullptr;
+
+ size_t name_bytes =
+ ansi_string.MaximumLength * sizeof(wchar_t) + sizeof(UNICODE_STRING);
+
+ UNICODE_STRING* out_string =
+ reinterpret_cast<UNICODE_STRING*>(new (NT_ALLOC) char[name_bytes]);
+ if (!out_string)
+ return nullptr;
+
+ out_string->MaximumLength = ansi_string.MaximumLength * sizeof(wchar_t);
+ out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
+
+ BOOLEAN alloc_destination = false;
+ NTSTATUS ret = g_nt.RtlAnsiStringToUnicodeString(out_string, &ansi_string,
+ alloc_destination);
+ DCHECK_NT(STATUS_BUFFER_OVERFLOW != ret);
+ if (!NT_SUCCESS(ret)) {
+ operator delete(out_string, NT_ALLOC);
+ return nullptr;
+ }
+
+ return out_string;
+}
+
+UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32_t* flags) {
+// PEImage's dtor won't be run during SEH unwinding, but that's OK.
+#pragma warning(push)
+#pragma warning(disable : 4509)
+ UNICODE_STRING* out_name = nullptr;
+ __try {
+ do {
+ *flags = 0;
+ base::win::PEImage pe(module);
+
+ if (!pe.VerifyMagic())
+ break;
+ *flags |= MODULE_IS_PE_IMAGE;
+
+ PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory();
+ if (exports) {
+ char* name = reinterpret_cast<char*>(pe.RVAToAddr(exports->Name));
+ out_name = AnsiToUnicode(name);
+ }
+
+ PIMAGE_NT_HEADERS headers = pe.GetNTHeaders();
+ if (headers) {
+ if (headers->OptionalHeader.AddressOfEntryPoint)
+ *flags |= MODULE_HAS_ENTRY_POINT;
+ if (headers->OptionalHeader.SizeOfCode)
+ *flags |= MODULE_HAS_CODE;
+ }
+ } while (false);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ }
+
+ return out_name;
+#pragma warning(pop)
+}
+
+const char* GetAnsiImageInfoFromModule(HMODULE module) {
+// PEImage's dtor won't be run during SEH unwinding, but that's OK.
+#pragma warning(push)
+#pragma warning(disable : 4509)
+ const char* out_name = nullptr;
+ __try {
+ do {
+ base::win::PEImage pe(module);
+
+ if (!pe.VerifyMagic())
+ break;
+
+ PIMAGE_EXPORT_DIRECTORY exports = pe.GetExportDirectory();
+ if (exports)
+ out_name = static_cast<const char*>(pe.RVAToAddr(exports->Name));
+ } while (false);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ }
+
+ return out_name;
+#pragma warning(pop)
+}
+
+UNICODE_STRING* GetBackingFilePath(PVOID address) {
+ // We'll start with something close to max_path charactes for the name.
+ SIZE_T buffer_bytes = MAX_PATH * 2;
+
+ for (;;) {
+ MEMORY_SECTION_NAME* section_name = reinterpret_cast<MEMORY_SECTION_NAME*>(
+ new (NT_ALLOC) char[buffer_bytes]);
+
+ if (!section_name)
+ return nullptr;
+
+ SIZE_T returned_bytes;
+ NTSTATUS ret =
+ g_nt.QueryVirtualMemory(NtCurrentProcess, address, MemorySectionName,
+ section_name, buffer_bytes, &returned_bytes);
+
+ if (STATUS_BUFFER_OVERFLOW == ret) {
+ // Retry the call with the given buffer size.
+ operator delete(section_name, NT_ALLOC);
+ section_name = nullptr;
+ buffer_bytes = returned_bytes;
+ continue;
+ }
+ if (!NT_SUCCESS(ret)) {
+ operator delete(section_name, NT_ALLOC);
+ return nullptr;
+ }
+
+ return reinterpret_cast<UNICODE_STRING*>(section_name);
+ }
+}
+
+UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path) {
+ if ((!module_path) || (!module_path->Buffer))
+ return nullptr;
+
+ wchar_t* sep = nullptr;
+ int start_pos = module_path->Length / sizeof(wchar_t) - 1;
+ int ix = start_pos;
+
+ for (; ix >= 0; --ix) {
+ if (module_path->Buffer[ix] == L'\\') {
+ sep = &module_path->Buffer[ix];
+ break;
+ }
+ }
+
+ // Ends with path separator. Not a valid module name.
+ if ((ix == start_pos) && sep)
+ return nullptr;
+
+ // No path separator found. Use the entire name.
+ if (!sep) {
+ sep = &module_path->Buffer[-1];
+ }
+
+ // Add one to the size so we can null terminate the string.
+ size_t size_bytes = (start_pos - ix + 1) * sizeof(wchar_t);
+
+ // Based on the code above, size_bytes should always be small enough
+ // to make the static_cast below safe.
+ DCHECK_NT(UINT16_MAX > size_bytes);
+ char* str_buffer = new (NT_ALLOC) char[size_bytes + sizeof(UNICODE_STRING)];
+ if (!str_buffer)
+ return nullptr;
+
+ UNICODE_STRING* out_string = reinterpret_cast<UNICODE_STRING*>(str_buffer);
+ out_string->Buffer = reinterpret_cast<wchar_t*>(&out_string[1]);
+ out_string->Length = static_cast<USHORT>(size_bytes - sizeof(wchar_t));
+ out_string->MaximumLength = static_cast<USHORT>(size_bytes);
+
+ NTSTATUS ret = CopyData(out_string->Buffer, &sep[1], out_string->Length);
+ if (!NT_SUCCESS(ret)) {
+ operator delete(out_string, NT_ALLOC);
+ return nullptr;
+ }
+
+ out_string->Buffer[out_string->Length / sizeof(wchar_t)] = L'\0';
+ return out_string;
+}
+
+NTSTATUS AutoProtectMemory::ChangeProtection(void* address,
+ size_t bytes,
+ ULONG protect) {
+ DCHECK_NT(!changed_);
+ SIZE_T new_bytes = bytes;
+ NTSTATUS ret = g_nt.ProtectVirtualMemory(NtCurrentProcess, &address,
+ &new_bytes, protect, &old_protect_);
+ if (NT_SUCCESS(ret)) {
+ changed_ = true;
+ address_ = address;
+ bytes_ = new_bytes;
+ }
+
+ return ret;
+}
+
+NTSTATUS AutoProtectMemory::RevertProtection() {
+ if (!changed_)
+ return STATUS_SUCCESS;
+
+ DCHECK_NT(address_);
+ DCHECK_NT(bytes_);
+
+ SIZE_T new_bytes = bytes_;
+ NTSTATUS ret = g_nt.ProtectVirtualMemory(
+ NtCurrentProcess, &address_, &new_bytes, old_protect_, &old_protect_);
+ DCHECK_NT(NT_SUCCESS(ret));
+
+ changed_ = false;
+ address_ = nullptr;
+ bytes_ = 0;
+ old_protect_ = 0;
+
+ return ret;
+}
+
+bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info,
+ DWORD length,
+ uint32_t file_info_class) {
+ if (FileRenameInformation != file_info_class)
+ return false;
+
+ if (length < sizeof(FILE_RENAME_INFORMATION))
+ return false;
+
+ // Make sure file name length doesn't exceed the message length
+ if (length - offsetof(FILE_RENAME_INFORMATION, FileName) <
+ file_info->FileNameLength)
+ return false;
+
+ // We don't support a root directory.
+ if (file_info->RootDirectory)
+ return false;
+
+ static const wchar_t kPathPrefix[] = {L'\\', L'?', L'?', L'\\'};
+
+ // Check if it starts with \\??\\. We don't support relative paths.
+ if (file_info->FileNameLength < sizeof(kPathPrefix) ||
+ file_info->FileNameLength > UINT16_MAX)
+ return false;
+
+ if (file_info->FileName[0] != kPathPrefix[0] ||
+ file_info->FileName[1] != kPathPrefix[1] ||
+ file_info->FileName[2] != kPathPrefix[2] ||
+ file_info->FileName[3] != kPathPrefix[3])
+ return false;
+
+ return true;
+}
+
+bool NtGetPathFromHandle(HANDLE handle,
+ std::unique_ptr<wchar_t, NtAllocDeleter>* path) {
+ OBJECT_NAME_INFORMATION initial_buffer;
+ OBJECT_NAME_INFORMATION* name;
+ ULONG size = 0;
+ // Query the name information a first time to get the size of the name.
+ NTSTATUS status = g_nt.QueryObject(handle, ObjectNameInformation,
+ &initial_buffer, size, &size);
+
+ if (!NT_SUCCESS(status) && status != STATUS_INFO_LENGTH_MISMATCH)
+ return false;
+
+ std::unique_ptr<BYTE[], NtAllocDeleter> name_ptr;
+ if (!size)
+ return false;
+ name_ptr.reset(new (NT_ALLOC) BYTE[size]);
+ name = reinterpret_cast<OBJECT_NAME_INFORMATION*>(name_ptr.get());
+
+ // Query the name information a second time to get the name of the
+ // object referenced by the handle.
+ status = g_nt.QueryObject(handle, ObjectNameInformation, name, size, &size);
+
+ if (STATUS_SUCCESS != status)
+ return false;
+ size_t num_path_wchars = (name->ObjectName.Length / sizeof(wchar_t)) + 1;
+ path->reset(new (NT_ALLOC) wchar_t[num_path_wchars]);
+ status =
+ CopyData(path->get(), name->ObjectName.Buffer, name->ObjectName.Length);
+ path->get()[num_path_wchars - 1] = L'\0';
+ if (STATUS_SUCCESS != status)
+ return false;
+ return true;
+}
+
+} // namespace sandbox
+
+void* operator new(size_t size, sandbox::AllocationType type, void* near_to) {
+ void* result = nullptr;
+ if (type == sandbox::NT_ALLOC) {
+ if (sandbox::InitHeap()) {
+ // Use default flags for the allocation.
+ result = sandbox::g_nt.RtlAllocateHeap(sandbox::g_heap, 0, size);
+ }
+ } else if (type == sandbox::NT_PAGE) {
+ result = AllocateNearTo(near_to, size);
+ } else {
+ NOTREACHED_NT();
+ }
+
+ // TODO: Returning nullptr from operator new has undefined behavior, but
+ // the Allocate() functions called above can return nullptr. Consider checking
+ // for nullptr here and crashing or throwing.
+
+ return result;
+}
+
+void* operator new [](size_t size, sandbox::AllocationType type,
+ void* near_to) {
+ return operator new(size, type, near_to);
+}
+
+void operator delete(void* memory, sandbox::AllocationType type) {
+ if (type == sandbox::NT_ALLOC) {
+ // Use default flags.
+ VERIFY(sandbox::g_nt.RtlFreeHeap(sandbox::g_heap, 0, memory));
+ } else if (type == sandbox::NT_PAGE) {
+ void* base = memory;
+ SIZE_T size = 0;
+ VERIFY_SUCCESS(sandbox::g_nt.FreeVirtualMemory(NtCurrentProcess, &base,
+ &size, MEM_RELEASE));
+ } else {
+ NOTREACHED_NT();
+ }
+}
+
+void operator delete(void* memory,
+ sandbox::AllocationType type,
+ void* near_to) {
+ operator delete(memory, type);
+}
+
+void* __cdecl operator new(size_t size,
+ void* buffer,
+ sandbox::AllocationType type) {
+ return buffer;
+}
+
+void __cdecl operator delete(void* memory,
+ void* buffer,
+ sandbox::AllocationType type) {}
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.h b/security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.h
new file mode 100644
index 0000000000..70d011dfb4
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_nt_util.h
@@ -0,0 +1,220 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_NT_UTIL_H_
+#define SANDBOX_SRC_SANDBOX_NT_UTIL_H_
+
+#include <intrin.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+
+// Placement new and delete to be used from ntdll interception code.
+void* __cdecl operator new(size_t size,
+ sandbox::AllocationType type,
+ void* near_to = nullptr);
+void* __cdecl operator new[](size_t size,
+ sandbox::AllocationType type,
+ void* near_to = nullptr);
+void __cdecl operator delete(void* memory, sandbox::AllocationType type);
+// Add operator delete that matches the placement form of the operator new
+// above. This is required by compiler to generate code to call operator delete
+// in case the object's constructor throws an exception.
+// See http://msdn.microsoft.com/en-us/library/cxdxz3x6.aspx
+void __cdecl operator delete(void* memory,
+ sandbox::AllocationType type,
+ void* near_to);
+
+// Regular placement new and delete
+void* __cdecl operator new(size_t size,
+ void* buffer,
+ sandbox::AllocationType type);
+void __cdecl operator delete(void* memory,
+ void* buffer,
+ sandbox::AllocationType type);
+
+// DCHECK_NT is defined to be pretty much an assert at this time because we
+// don't have logging from the ntdll layer on the child.
+//
+// VERIFY_NT and VERIFY_SUCCESS are the standard asserts on debug, but
+// execute the actual argument on release builds. VERIFY_NT expects an action
+// returning a bool, while VERIFY_SUCCESS expects an action returning
+// NTSTATUS.
+#ifndef NDEBUG
+#define DCHECK_NT(condition) \
+ { (condition) ? (void)0 : __debugbreak(); }
+#define VERIFY(action) DCHECK_NT(action)
+#define VERIFY_SUCCESS(action) DCHECK_NT(NT_SUCCESS(action))
+#else
+#define DCHECK_NT(condition)
+#define VERIFY(action) (action)
+#define VERIFY_SUCCESS(action) (action)
+#endif
+
+#define CHECK_NT(condition) \
+ { (condition) ? (void)0 : __debugbreak(); }
+
+#define NOTREACHED_NT() DCHECK_NT(false)
+
+namespace sandbox {
+
+#if defined(_M_X64) || defined(_M_ARM64)
+#pragma intrinsic(_InterlockedCompareExchange)
+#pragma intrinsic(_InterlockedCompareExchangePointer)
+
+#elif defined(_M_IX86)
+extern "C" long _InterlockedCompareExchange(long volatile* destination,
+ long exchange,
+ long comperand);
+
+#pragma intrinsic(_InterlockedCompareExchange)
+
+// We want to make sure that we use an intrinsic version of the function, not
+// the one provided by kernel32.
+__forceinline void* _InterlockedCompareExchangePointer(
+ void* volatile* destination,
+ void* exchange,
+ void* comperand) {
+ long ret = _InterlockedCompareExchange(
+ reinterpret_cast<long volatile*>(destination),
+ static_cast<long>(reinterpret_cast<size_t>(exchange)),
+ static_cast<long>(reinterpret_cast<size_t>(comperand)));
+
+ return reinterpret_cast<void*>(static_cast<size_t>(ret));
+}
+
+#else
+#error Architecture not supported.
+
+#endif
+
+struct NtAllocDeleter {
+ inline void operator()(void* ptr) const {
+ operator delete(ptr, AllocationType::NT_ALLOC);
+ }
+};
+
+// Returns a pointer to the IPC shared memory.
+void* GetGlobalIPCMemory();
+
+// Returns a pointer to the Policy shared memory.
+void* GetGlobalPolicyMemory();
+
+enum RequiredAccess { READ, WRITE };
+
+// Performs basic user mode buffer validation. In any case, buffers access must
+// be protected by SEH. intent specifies if the buffer should be tested for read
+// or write.
+bool ValidParameter(void* buffer, size_t size, RequiredAccess intent);
+
+// Copies data from a user buffer to our buffer. Returns the operation status.
+NTSTATUS CopyData(void* destination, const void* source, size_t bytes);
+
+// Copies the name from an object attributes.
+NTSTATUS AllocAndCopyName(const OBJECT_ATTRIBUTES* in_object,
+ std::unique_ptr<wchar_t, NtAllocDeleter>* out_name,
+ uint32_t* attributes,
+ HANDLE* root);
+
+// Determine full path name from object root and path.
+NTSTATUS AllocAndGetFullPath(
+ HANDLE root,
+ const wchar_t* path,
+ std::unique_ptr<wchar_t, NtAllocDeleter>* full_path);
+
+// Initializes our ntdll level heap
+bool InitHeap();
+
+// Returns true if the provided handle refers to the current process.
+bool IsSameProcess(HANDLE process);
+
+enum MappedModuleFlags {
+ MODULE_IS_PE_IMAGE = 1, // Module is an executable.
+ MODULE_HAS_ENTRY_POINT = 2, // Execution entry point found.
+ MODULE_HAS_CODE = 4 // Non zero size of executable sections.
+};
+
+// Returns the name and characteristics for a given PE module. The return
+// value is the name as defined by the export table and the flags is any
+// combination of the MappedModuleFlags enumeration.
+//
+// The returned buffer must be freed with a placement delete from the ntdll
+// level allocator:
+//
+// UNICODE_STRING* name = GetPEImageInfoFromModule(HMODULE module, &flags);
+// if (!name) {
+// // probably not a valid dll
+// return;
+// }
+// InsertYourLogicHere(name);
+// operator delete(name, NT_ALLOC);
+UNICODE_STRING* GetImageInfoFromModule(HMODULE module, uint32_t* flags);
+
+// Returns the name and characteristics for a given PE module. The return
+// value is the name as defined by the export table.
+//
+// The returned buffer is within the PE module and must not be freed.
+const char* GetAnsiImageInfoFromModule(HMODULE module);
+
+// Returns the full path and filename for a given dll.
+// May return nullptr if the provided address is not backed by a named section,
+// or if the current OS version doesn't support the call. The returned buffer
+// must be freed with a placement delete (see GetImageNameFromModule example).
+UNICODE_STRING* GetBackingFilePath(PVOID address);
+
+// Returns the last component of a path that contains the module name.
+// It will return nullptr if the path ends with the path separator. The returned
+// buffer must be freed with a placement delete (see GetImageNameFromModule
+// example).
+UNICODE_STRING* ExtractModuleName(const UNICODE_STRING* module_path);
+
+// Returns true if the parameters correspond to a dll mapped as code.
+bool IsValidImageSection(HANDLE section,
+ PVOID* base,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size);
+
+// Converts an ansi string to an UNICODE_STRING.
+UNICODE_STRING* AnsiToUnicode(const char* string);
+
+// Resolves a handle to an nt path. Returns true if the handle can be resolved.
+bool NtGetPathFromHandle(HANDLE handle,
+ std::unique_ptr<wchar_t, NtAllocDeleter>* path);
+
+// Provides a simple way to temporarily change the protection of a memory page.
+class AutoProtectMemory {
+ public:
+ AutoProtectMemory()
+ : changed_(false), address_(nullptr), bytes_(0), old_protect_(0) {}
+
+ ~AutoProtectMemory() { RevertProtection(); }
+
+ // Sets the desired protection of a given memory range.
+ NTSTATUS ChangeProtection(void* address, size_t bytes, ULONG protect);
+
+ // Restores the original page protection.
+ NTSTATUS RevertProtection();
+
+ private:
+ bool changed_;
+ void* address_;
+ size_t bytes_;
+ ULONG old_protect_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutoProtectMemory);
+};
+
+// Returns true if the file_rename_information structure is supported by our
+// rename handler.
+bool IsSupportedRenameCall(FILE_RENAME_INFORMATION* file_info,
+ DWORD length,
+ uint32_t file_info_class);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SANDBOX_NT_UTIL_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
new file mode 100644
index 0000000000..75514ef595
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
@@ -0,0 +1,296 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/security_level.h"
+
+namespace sandbox {
+
+class AppContainerProfile;
+
+class TargetPolicy {
+ public:
+ // Windows subsystems that can have specific rules.
+ // Note: The process subsystem(SUBSYS_PROCESS) does not evaluate the request
+ // exactly like the CreateProcess API does. See the comment at the top of
+ // process_thread_dispatcher.cc for more details.
+ enum SubSystem {
+ SUBSYS_FILES, // Creation and opening of files and pipes.
+ SUBSYS_NAMED_PIPES, // Creation of named pipes.
+ SUBSYS_PROCESS, // Creation of child processes.
+ SUBSYS_REGISTRY, // Creation and opening of registry keys.
+ SUBSYS_SYNC, // Creation of named sync objects.
+ SUBSYS_HANDLES, // Duplication of handles to other processes.
+ SUBSYS_WIN32K_LOCKDOWN, // Win32K Lockdown related policy.
+ SUBSYS_SIGNED_BINARY, // Signed binary policy.
+ SUBSYS_LINE_BREAK // Complex line break policy.
+ };
+
+ // Allowable semantics when a rule is matched.
+ enum Semantics {
+ FILES_ALLOW_ANY, // Allows open or create for any kind of access that
+ // the file system supports.
+ FILES_ALLOW_READONLY, // Allows open or create with read access only.
+ FILES_ALLOW_QUERY, // Allows access to query the attributes of a file.
+ FILES_ALLOW_DIR_ANY, // Allows open or create with directory semantics
+ // only.
+ HANDLES_DUP_ANY, // Allows duplicating handles opened with any
+ // access permissions.
+ HANDLES_DUP_BROKER, // Allows duplicating handles to the broker process.
+ NAMEDPIPES_ALLOW_ANY, // Allows creation of a named pipe.
+ PROCESS_MIN_EXEC, // Allows to create a process with minimal rights
+ // over the resulting process and thread handles.
+ // No other parameters besides the command line are
+ // passed to the child process.
+ PROCESS_ALL_EXEC, // Allows the creation of a process and return full
+ // access on the returned handles.
+ // This flag can be used only when the main token of
+ // the sandboxed application is at least INTERACTIVE.
+ EVENTS_ALLOW_ANY, // Allows the creation of an event with full access.
+ EVENTS_ALLOW_READONLY, // Allows opening an even with synchronize access.
+ REG_ALLOW_READONLY, // Allows readonly access to a registry key.
+ REG_ALLOW_ANY, // Allows read and write access to a registry key.
+ FAKE_USER_GDI_INIT, // Fakes user32 and gdi32 initialization. This can
+ // be used to allow the DLLs to load and initialize
+ // even if the process cannot access that subsystem.
+ IMPLEMENT_OPM_APIS, // Implements FAKE_USER_GDI_INIT and also exposes
+ // IPC calls to handle Output Protection Manager
+ // APIs.
+ SIGNED_ALLOW_LOAD, // Allows loading the module when CIG is enabled.
+ LINE_BREAK_ALLOW // Allow complex line break brokering.
+ };
+
+ // Increments the reference count of this object. The reference count must
+ // be incremented if this interface is given to another component.
+ virtual void AddRef() = 0;
+
+ // Decrements the reference count of this object. When the reference count
+ // is zero the object is automatically destroyed.
+ // Indicates that the caller is done with this interface. After calling
+ // release no other method should be called.
+ virtual void Release() = 0;
+
+ // Sets the security level for the target process' two tokens.
+ // This setting is permanent and cannot be changed once the target process is
+ // spawned.
+ // initial: the security level for the initial token. This is the token that
+ // is used by the process from the creation of the process until the moment
+ // the process calls TargetServices::LowerToken() or the process calls
+ // win32's RevertToSelf(). Once this happens the initial token is no longer
+ // available and the lockdown token is in effect. Using an initial token is
+ // not compatible with AppContainer, see SetAppContainer.
+ // lockdown: the security level for the token that comes into force after the
+ // process calls TargetServices::LowerToken() or the process calls
+ // RevertToSelf(). See the explanation of each level in the TokenLevel
+ // definition.
+ // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
+ // Returns false if the lockdown value is more permissive than the initial
+ // value.
+ //
+ // Important: most of the sandbox-provided security relies on this single
+ // setting. The caller should strive to set the lockdown level as restricted
+ // as possible.
+ virtual ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) = 0;
+
+ // Returns the initial token level.
+ virtual TokenLevel GetInitialTokenLevel() const = 0;
+
+ // Returns the lockdown token level.
+ virtual TokenLevel GetLockdownTokenLevel() const = 0;
+
+ // Sets that we should not use restricting SIDs in the access tokens. We need
+ // to do this in some circumstances even though it weakens the sandbox.
+ // The default is to use them.
+ virtual void SetDoNotUseRestrictingSIDs() = 0;
+
+ // Sets the security level of the Job Object to which the target process will
+ // belong. This setting is permanent and cannot be changed once the target
+ // process is spawned. The job controls the global security settings which
+ // can not be specified in the token security profile.
+ // job_level: the security level for the job. See the explanation of each
+ // level in the JobLevel definition.
+ // ui_exceptions: specify what specific rights that are disabled in the
+ // chosen job_level that need to be granted. Use this parameter to avoid
+ // selecting the next permissive job level unless you need all the rights
+ // that are granted in such level.
+ // The exceptions can be specified as a combination of the following
+ // constants:
+ // JOB_OBJECT_UILIMIT_HANDLES : grant access to all user-mode handles. These
+ // include windows, icons, menus and various GDI objects. In addition the
+ // target process can set hooks, and broadcast messages to other processes
+ // that belong to the same desktop.
+ // JOB_OBJECT_UILIMIT_READCLIPBOARD : grant read-only access to the clipboard.
+ // JOB_OBJECT_UILIMIT_WRITECLIPBOARD : grant write access to the clipboard.
+ // JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS : allow changes to the system-wide
+ // parameters as defined by the Win32 call SystemParametersInfo().
+ // JOB_OBJECT_UILIMIT_DISPLAYSETTINGS : allow programmatic changes to the
+ // display settings.
+ // JOB_OBJECT_UILIMIT_GLOBALATOMS : allow access to the global atoms table.
+ // JOB_OBJECT_UILIMIT_DESKTOP : allow the creation of new desktops.
+ // JOB_OBJECT_UILIMIT_EXITWINDOWS : allow the call to ExitWindows().
+ //
+ // Return value: SBOX_ALL_OK if the setting succeeds and false otherwise.
+ //
+ // Note: JOB_OBJECT_XXXX constants are defined in winnt.h and documented at
+ // length in:
+ // http://msdn2.microsoft.com/en-us/library/ms684152.aspx
+ //
+ // Note: the recommended level is JOB_RESTRICTED or JOB_LOCKDOWN.
+ virtual ResultCode SetJobLevel(JobLevel job_level,
+ uint32_t ui_exceptions) = 0;
+
+ // Returns the job level.
+ virtual JobLevel GetJobLevel() const = 0;
+
+ // Sets a hard limit on the size of the commit set for the sandboxed process.
+ // If the limit is reached, the process will be terminated with
+ // SBOX_FATAL_MEMORY_EXCEEDED (7012).
+ virtual ResultCode SetJobMemoryLimit(size_t memory_limit) = 0;
+
+ // Specifies the desktop on which the application is going to run. If the
+ // desktop does not exist, it will be created. If alternate_winstation is
+ // set to true, the desktop will be created on an alternate window station.
+ virtual ResultCode SetAlternateDesktop(bool alternate_winstation) = 0;
+
+ // Returns the name of the alternate desktop used. If an alternate window
+ // station is specified, the name is prepended by the window station name,
+ // followed by a backslash.
+ virtual std::wstring GetAlternateDesktop() const = 0;
+
+ // Precreates the desktop and window station, if any.
+ virtual ResultCode CreateAlternateDesktop(bool alternate_winstation) = 0;
+
+ // Destroys the desktop and windows station.
+ virtual void DestroyAlternateDesktop() = 0;
+
+ // Sets the integrity level of the process in the sandbox. Both the initial
+ // token and the main token will be affected by this. If the integrity level
+ // is set to a level higher than the current level, the sandbox will fail
+ // to start.
+ virtual ResultCode SetIntegrityLevel(IntegrityLevel level) = 0;
+
+ // Returns the initial integrity level used.
+ virtual IntegrityLevel GetIntegrityLevel() const = 0;
+
+ // Sets the integrity level of the process in the sandbox. The integrity level
+ // will not take effect before you call LowerToken. User Interface Privilege
+ // Isolation is not affected by this setting and will remain off for the
+ // process in the sandbox. If the integrity level is set to a level higher
+ // than the current level, the sandbox will fail to start.
+ virtual ResultCode SetDelayedIntegrityLevel(IntegrityLevel level) = 0;
+
+ // Sets the LowBox token for sandboxed process. This is mutually exclusive
+ // with SetAppContainer method.
+ virtual ResultCode SetLowBox(const wchar_t* sid) = 0;
+
+ // Sets the mitigations enabled when the process is created. Most of these
+ // are implemented as attributes passed via STARTUPINFOEX. So they take
+ // effect before any thread in the target executes. The declaration of
+ // MitigationFlags is followed by a detailed description of each flag.
+ virtual ResultCode SetProcessMitigations(MitigationFlags flags) = 0;
+
+ // Returns the currently set mitigation flags.
+ virtual MitigationFlags GetProcessMitigations() = 0;
+
+ // Sets process mitigation flags that don't take effect before the call to
+ // LowerToken().
+ virtual ResultCode SetDelayedProcessMitigations(MitigationFlags flags) = 0;
+
+ // Returns the currently set delayed mitigation flags.
+ virtual MitigationFlags GetDelayedProcessMitigations() const = 0;
+
+ // Disconnect the target from CSRSS when TargetServices::LowerToken() is
+ // called inside the target.
+ virtual ResultCode SetDisconnectCsrss() = 0;
+
+ // Sets the interceptions to operate in strict mode. By default, interceptions
+ // are performed in "relaxed" mode, where if something inside NTDLL.DLL is
+ // already patched we attempt to intercept it anyway. Setting interceptions
+ // to strict mode means that when we detect that the function is patched we'll
+ // refuse to perform the interception.
+ virtual void SetStrictInterceptions() = 0;
+
+ // Set the handles the target process should inherit for stdout and
+ // stderr. The handles the caller passes must remain valid for the
+ // lifetime of the policy object. This only has an effect on
+ // Windows Vista and later versions. These methods accept pipe and
+ // file handles, but not console handles.
+ virtual ResultCode SetStdoutHandle(HANDLE handle) = 0;
+ virtual ResultCode SetStderrHandle(HANDLE handle) = 0;
+
+ // Adds a policy rule effective for processes spawned using this policy.
+ // subsystem: One of the above enumerated windows subsystems.
+ // semantics: One of the above enumerated FileSemantics.
+ // pattern: A specific full path or a full path with wildcard patterns.
+ // The valid wildcards are:
+ // '*' : Matches zero or more character. Only one in series allowed.
+ // '?' : Matches a single character. One or more in series are allowed.
+ // Examples:
+ // "c:\\documents and settings\\vince\\*.dmp"
+ // "c:\\documents and settings\\*\\crashdumps\\*.dmp"
+ // "c:\\temp\\app_log_?????_chrome.txt"
+ virtual ResultCode AddRule(SubSystem subsystem,
+ Semantics semantics,
+ const wchar_t* pattern) = 0;
+
+ // Adds a dll that will be unloaded in the target process before it gets
+ // a chance to initialize itself. Typically, dlls that cause the target
+ // to crash go here.
+ virtual ResultCode AddDllToUnload(const wchar_t* dll_name) = 0;
+
+ // Adds a handle that will be closed in the target process after lockdown.
+ // A nullptr value for handle_name indicates all handles of the specified
+ // type. An empty string for handle_name indicates the handle is unnamed.
+ virtual ResultCode AddKernelObjectToClose(const wchar_t* handle_type,
+ const wchar_t* handle_name) = 0;
+
+ // Adds a handle that will be shared with the target process. Does not take
+ // ownership of the handle.
+ virtual void AddHandleToShare(HANDLE handle) = 0;
+
+ // Locks down the default DACL of the created lockdown and initial tokens
+ // to restrict what other processes are allowed to access a process' kernel
+ // resources.
+ virtual void SetLockdownDefaultDacl() = 0;
+
+ // Adds a restricting random SID to the restricted SIDs list as well as
+ // the default DACL.
+ virtual void AddRestrictingRandomSid() = 0;
+
+ // Enable OPM API redirection when in Win32k lockdown.
+ virtual void SetEnableOPMRedirection() = 0;
+ // Enable OPM API emulation when in Win32k lockdown.
+ virtual bool GetEnableOPMRedirection() = 0;
+
+ // Configure policy to use an AppContainer profile. |package_name| is the
+ // name of the profile to use. Specifying True for |create_profile| ensures
+ // the profile exists, if set to False process creation will fail if the
+ // profile has not already been created.
+ virtual ResultCode AddAppContainerProfile(const wchar_t* package_name,
+ bool create_profile) = 0;
+
+ // Get the configured AppContainerProfile.
+ virtual scoped_refptr<AppContainerProfile> GetAppContainerProfile() = 0;
+
+ // Set effective token that will be used for creating the initial and
+ // lockdown tokens. The token the caller passes must remain valid for the
+ // lifetime of the policy object.
+ virtual void SetEffectiveToken(HANDLE token) = 0;
+
+ protected:
+ ~TargetPolicy() {}
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SANDBOX_POLICY_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
new file mode 100644
index 0000000000..f228dbbc31
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
@@ -0,0 +1,832 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+#include <sddl.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/filesystem_policy.h"
+#include "sandbox/win/src/handle_policy.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/job.h"
+#include "sandbox/win/src/line_break_policy.h"
+#include "sandbox/win/src/named_pipe_policy.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_engine_processor.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/process_mitigations_win32k_policy.h"
+#include "sandbox/win/src/process_thread_policy.h"
+#include "sandbox/win/src/registry_policy.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/security_capabilities.h"
+#include "sandbox/win/src/signed_policy.h"
+#include "sandbox/win/src/sync_policy.h"
+#include "sandbox/win/src/target_process.h"
+#include "sandbox/win/src/top_level_dispatcher.h"
+#include "sandbox/win/src/window.h"
+
+namespace {
+
+// The standard windows size for one memory page.
+constexpr size_t kOneMemPage = 4096;
+// The IPC and Policy shared memory sizes.
+constexpr size_t kIPCMemSize = kOneMemPage * 2;
+constexpr size_t kPolMemSize = kOneMemPage * 14;
+
+// Helper function to allocate space (on the heap) for policy.
+sandbox::PolicyGlobal* MakeBrokerPolicyMemory() {
+ const size_t kTotalPolicySz = kPolMemSize;
+ sandbox::PolicyGlobal* policy =
+ static_cast<sandbox::PolicyGlobal*>(::operator new(kTotalPolicySz));
+ DCHECK(policy);
+ memset(policy, 0, kTotalPolicySz);
+ policy->data_size = kTotalPolicySz - sizeof(sandbox::PolicyGlobal);
+ return policy;
+}
+
+bool IsInheritableHandle(HANDLE handle) {
+ if (!handle)
+ return false;
+ if (handle == INVALID_HANDLE_VALUE)
+ return false;
+ // File handles (FILE_TYPE_DISK) and pipe handles are known to be
+ // inheritable. Console handles (FILE_TYPE_CHAR) are not
+ // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+ DWORD handle_type = GetFileType(handle);
+ return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
+}
+
+} // namespace
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level;
+SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations;
+
+// Initializes static members. alternate_desktop_handle_ is a desktop on
+// alternate_winstation_handle_, alternate_desktop_local_winstation_handle_ is a
+// desktop on the same winstation as the parent process.
+HWINSTA PolicyBase::alternate_winstation_handle_ = nullptr;
+HDESK PolicyBase::alternate_desktop_handle_ = nullptr;
+HDESK PolicyBase::alternate_desktop_local_winstation_handle_ = nullptr;
+IntegrityLevel PolicyBase::alternate_desktop_integrity_level_label_ =
+ INTEGRITY_LEVEL_SYSTEM;
+IntegrityLevel
+ PolicyBase::alternate_desktop_local_winstation_integrity_level_label_ =
+ INTEGRITY_LEVEL_SYSTEM;
+
+PolicyBase::PolicyBase()
+ : ref_count(1),
+ lockdown_level_(USER_LOCKDOWN),
+ initial_level_(USER_LOCKDOWN),
+ job_level_(JOB_LOCKDOWN),
+ ui_exceptions_(0),
+ memory_limit_(0),
+ use_alternate_desktop_(false),
+ use_alternate_winstation_(false),
+ file_system_init_(false),
+ relaxed_interceptions_(true),
+ stdout_handle_(INVALID_HANDLE_VALUE),
+ stderr_handle_(INVALID_HANDLE_VALUE),
+ integrity_level_(INTEGRITY_LEVEL_LAST),
+ delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
+ mitigations_(0),
+ delayed_mitigations_(0),
+ is_csrss_connected_(true),
+ policy_maker_(nullptr),
+ policy_(nullptr),
+ lowbox_sid_(nullptr),
+ lockdown_default_dacl_(false),
+ add_restricting_random_sid_(false),
+ enable_opm_redirection_(false),
+ effective_token_(nullptr) {
+ ::InitializeCriticalSection(&lock_);
+ dispatcher_.reset(new TopLevelDispatcher(this));
+}
+
+PolicyBase::~PolicyBase() {
+ TargetSet::iterator it;
+ for (it = targets_.begin(); it != targets_.end(); ++it) {
+ TargetProcess* target = (*it);
+ delete target;
+ }
+ delete policy_maker_;
+ delete policy_;
+
+ if (lowbox_sid_)
+ ::LocalFree(lowbox_sid_);
+
+ ::DeleteCriticalSection(&lock_);
+}
+
+void PolicyBase::AddRef() {
+ ::InterlockedIncrement(&ref_count);
+}
+
+void PolicyBase::Release() {
+ if (0 == ::InterlockedDecrement(&ref_count))
+ delete this;
+}
+
+ResultCode PolicyBase::SetTokenLevel(TokenLevel initial, TokenLevel lockdown) {
+ if (initial < lockdown) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ initial_level_ = initial;
+ lockdown_level_ = lockdown;
+ return SBOX_ALL_OK;
+}
+
+TokenLevel PolicyBase::GetInitialTokenLevel() const {
+ return initial_level_;
+}
+
+TokenLevel PolicyBase::GetLockdownTokenLevel() const {
+ return lockdown_level_;
+}
+
+void PolicyBase::SetDoNotUseRestrictingSIDs() {
+ use_restricting_sids_ = false;
+}
+
+ResultCode PolicyBase::SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) {
+ if (memory_limit_ && job_level == JOB_NONE) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ job_level_ = job_level;
+ ui_exceptions_ = ui_exceptions;
+ return SBOX_ALL_OK;
+}
+
+JobLevel PolicyBase::GetJobLevel() const {
+ return job_level_;
+}
+
+ResultCode PolicyBase::SetJobMemoryLimit(size_t memory_limit) {
+ memory_limit_ = memory_limit;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetAlternateDesktop(bool alternate_winstation) {
+ use_alternate_desktop_ = true;
+ use_alternate_winstation_ = alternate_winstation;
+ return CreateAlternateDesktop(alternate_winstation);
+}
+
+std::wstring PolicyBase::GetAlternateDesktop() const {
+ // No alternate desktop or winstation. Return an empty string.
+ if (!use_alternate_desktop_ && !use_alternate_winstation_) {
+ return std::wstring();
+ }
+
+ if (use_alternate_winstation_) {
+ // The desktop and winstation should have been created by now.
+ // If we hit this scenario, it means that the user ignored the failure
+ // during SetAlternateDesktop, so we ignore it here too.
+ if (!alternate_desktop_handle_ || !alternate_winstation_handle_)
+ return std::wstring();
+
+ return GetFullDesktopName(alternate_winstation_handle_,
+ alternate_desktop_handle_);
+ }
+
+ if (!alternate_desktop_local_winstation_handle_)
+ return std::wstring();
+
+ return GetFullDesktopName(nullptr,
+ alternate_desktop_local_winstation_handle_);
+}
+
+ResultCode PolicyBase::CreateAlternateDesktop(bool alternate_winstation) {
+ if (alternate_winstation) {
+ // Check if it's already created.
+ if (alternate_winstation_handle_ && alternate_desktop_handle_)
+ return SBOX_ALL_OK;
+
+ DCHECK(!alternate_winstation_handle_);
+ // Create the window station.
+ ResultCode result = CreateAltWindowStation(&alternate_winstation_handle_);
+ if (SBOX_ALL_OK != result)
+ return result;
+
+ // Verify that everything is fine.
+ if (!alternate_winstation_handle_ ||
+ base::win::GetWindowObjectName(alternate_winstation_handle_).empty())
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+
+ // Create the destkop.
+ result = CreateAltDesktop(alternate_winstation_handle_,
+ &alternate_desktop_handle_);
+ if (SBOX_ALL_OK != result)
+ return result;
+
+ // Verify that everything is fine.
+ if (!alternate_desktop_handle_ ||
+ base::win::GetWindowObjectName(alternate_desktop_handle_).empty()) {
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+ }
+ } else {
+ // Check if it already exists.
+ if (alternate_desktop_local_winstation_handle_)
+ return SBOX_ALL_OK;
+
+ // Create the destkop.
+ ResultCode result =
+ CreateAltDesktop(nullptr, &alternate_desktop_local_winstation_handle_);
+ if (SBOX_ALL_OK != result)
+ return result;
+
+ // Verify that everything is fine.
+ if (!alternate_desktop_local_winstation_handle_ ||
+ base::win::GetWindowObjectName(
+ alternate_desktop_local_winstation_handle_)
+ .empty()) {
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+ }
+ }
+
+ return SBOX_ALL_OK;
+}
+
+void PolicyBase::DestroyAlternateDesktop() {
+ if (use_alternate_winstation_) {
+ if (alternate_desktop_handle_) {
+ ::CloseDesktop(alternate_desktop_handle_);
+ alternate_desktop_handle_ = nullptr;
+ }
+
+ if (alternate_winstation_handle_) {
+ ::CloseWindowStation(alternate_winstation_handle_);
+ alternate_winstation_handle_ = nullptr;
+ }
+ } else {
+ if (alternate_desktop_local_winstation_handle_) {
+ ::CloseDesktop(alternate_desktop_local_winstation_handle_);
+ alternate_desktop_local_winstation_handle_ = nullptr;
+ }
+ }
+}
+
+ResultCode PolicyBase::SetIntegrityLevel(IntegrityLevel integrity_level) {
+ if (app_container_profile_)
+ return SBOX_ERROR_BAD_PARAMS;
+ integrity_level_ = integrity_level;
+ return SBOX_ALL_OK;
+}
+
+IntegrityLevel PolicyBase::GetIntegrityLevel() const {
+ return integrity_level_;
+}
+
+ResultCode PolicyBase::SetDelayedIntegrityLevel(
+ IntegrityLevel integrity_level) {
+ delayed_integrity_level_ = integrity_level;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetLowBox(const wchar_t* sid) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return SBOX_ERROR_UNSUPPORTED;
+
+ DCHECK(sid);
+ if (lowbox_sid_ || app_container_profile_)
+ return SBOX_ERROR_BAD_PARAMS;
+
+ if (!ConvertStringSidToSid(sid, &lowbox_sid_))
+ return SBOX_ERROR_INVALID_LOWBOX_SID;
+
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetProcessMitigations(MitigationFlags flags) {
+ // Prior to Win10 RS5 CreateProcess fails when AppContainer and mitigation
+ // flags are enabled. Return an error on downlevel platforms if trying to
+ // set new mitigations.
+ if (app_container_profile_ &&
+ base::win::GetVersion() < base::win::Version::WIN10_RS5) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ if (!CanSetProcessMitigationsPreStartup(flags))
+ return SBOX_ERROR_BAD_PARAMS;
+ mitigations_ = flags;
+ return SBOX_ALL_OK;
+}
+
+MitigationFlags PolicyBase::GetProcessMitigations() {
+ return mitigations_;
+}
+
+ResultCode PolicyBase::SetDelayedProcessMitigations(MitigationFlags flags) {
+ if (!CanSetProcessMitigationsPostStartup(flags))
+ return SBOX_ERROR_BAD_PARAMS;
+ delayed_mitigations_ = flags;
+ return SBOX_ALL_OK;
+}
+
+MitigationFlags PolicyBase::GetDelayedProcessMitigations() const {
+ return delayed_mitigations_;
+}
+
+void PolicyBase::SetStrictInterceptions() {
+ relaxed_interceptions_ = false;
+}
+
+ResultCode PolicyBase::SetStdoutHandle(HANDLE handle) {
+ if (!IsInheritableHandle(handle))
+ return SBOX_ERROR_BAD_PARAMS;
+ stdout_handle_ = handle;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::SetStderrHandle(HANDLE handle) {
+ if (!IsInheritableHandle(handle))
+ return SBOX_ERROR_BAD_PARAMS;
+ stderr_handle_ = handle;
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::AddRule(SubSystem subsystem,
+ Semantics semantics,
+ const wchar_t* pattern) {
+ ResultCode result = AddRuleInternal(subsystem, semantics, pattern);
+ LOG_IF(ERROR, result != SBOX_ALL_OK)
+ << "Failed to add sandbox rule."
+ << " error = " << result << ", subsystem = " << subsystem
+ << ", semantics = " << semantics << ", pattern = '" << pattern << "'";
+ return result;
+}
+
+ResultCode PolicyBase::AddDllToUnload(const wchar_t* dll_name) {
+ blocklisted_dlls_.push_back(dll_name);
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::AddKernelObjectToClose(const wchar_t* handle_type,
+ const wchar_t* handle_name) {
+ return handle_closer_.AddHandle(handle_type, handle_name);
+}
+
+void PolicyBase::AddHandleToShare(HANDLE handle) {
+ CHECK(handle);
+ CHECK_NE(handle, INVALID_HANDLE_VALUE);
+
+ // Ensure the handle can be inherited.
+ bool result =
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
+ PCHECK(result);
+
+ handles_to_share_.push_back(handle);
+}
+
+void PolicyBase::SetLockdownDefaultDacl() {
+ lockdown_default_dacl_ = true;
+}
+
+void PolicyBase::AddRestrictingRandomSid() {
+ add_restricting_random_sid_ = true;
+}
+
+const base::HandlesToInheritVector& PolicyBase::GetHandlesBeingShared() {
+ return handles_to_share_;
+}
+
+ResultCode PolicyBase::MakeJobObject(base::win::ScopedHandle* job) {
+ if (job_level_ == JOB_NONE) {
+ job->Close();
+ return SBOX_ALL_OK;
+ }
+
+ // Create the windows job object.
+ Job job_obj;
+ DWORD result =
+ job_obj.Init(job_level_, nullptr, ui_exceptions_, memory_limit_);
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_INIT_JOB;
+
+ *job = job_obj.Take();
+ return SBOX_ALL_OK;
+}
+
+ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
+ base::win::ScopedHandle* lockdown,
+ base::win::ScopedHandle* lowbox) {
+ Sid random_sid = Sid::GenerateRandomSid();
+ PSID random_sid_ptr = nullptr;
+ if (add_restricting_random_sid_)
+ random_sid_ptr = random_sid.GetPSID();
+
+ // Create the 'naked' token. This will be the permanent token associated
+ // with the process and therefore with any thread that is not impersonating.
+ DWORD result = CreateRestrictedToken(
+ effective_token_, lockdown_level_, integrity_level_, PRIMARY,
+ lockdown_default_dacl_, random_sid_ptr, use_restricting_sids_, lockdown);
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN;
+
+ // If we're launching on the alternate desktop we need to make sure the
+ // integrity label on the object is no higher than the sandboxed process's
+ // integrity level. So, we lower the label on the desktop process if it's
+ // not already low enough for our process.
+ if (use_alternate_desktop_ && integrity_level_ != INTEGRITY_LEVEL_LAST) {
+ // Integrity label enum is reversed (higher level is a lower value).
+ static_assert(INTEGRITY_LEVEL_SYSTEM < INTEGRITY_LEVEL_UNTRUSTED,
+ "Integrity level ordering reversed.");
+ HDESK desktop_handle = nullptr;
+ IntegrityLevel desktop_integrity_level_label;
+ if (use_alternate_winstation_) {
+ desktop_handle = alternate_desktop_handle_;
+ desktop_integrity_level_label = alternate_desktop_integrity_level_label_;
+ } else {
+ desktop_handle = alternate_desktop_local_winstation_handle_;
+ desktop_integrity_level_label =
+ alternate_desktop_local_winstation_integrity_level_label_;
+ }
+ // If the desktop_handle hasn't been created for any reason, skip this.
+ if (desktop_handle && desktop_integrity_level_label < integrity_level_) {
+ result =
+ SetObjectIntegrityLabel(desktop_handle, SE_WINDOW_OBJECT, L"",
+ GetIntegrityLevelString(integrity_level_));
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_SET_DESKTOP_INTEGRITY;
+
+ if (use_alternate_winstation_) {
+ alternate_desktop_integrity_level_label_ = integrity_level_;
+ } else {
+ alternate_desktop_local_winstation_integrity_level_label_ =
+ integrity_level_;
+ }
+ }
+ }
+
+ if (lowbox_sid_) {
+ if (!lowbox_directory_.IsValid()) {
+ result =
+ CreateLowBoxObjectDirectory(lowbox_sid_, true, &lowbox_directory_);
+ DCHECK(result == ERROR_SUCCESS);
+ }
+
+ // The order of handles isn't important in the CreateLowBoxToken call.
+ // The kernel will maintain a reference to the object directory handle.
+ HANDLE saved_handles[1] = {lowbox_directory_.Get()};
+ DWORD saved_handles_count = lowbox_directory_.IsValid() ? 1 : 0;
+
+ Sid package_sid(lowbox_sid_);
+ SecurityCapabilities caps(package_sid);
+ if (CreateLowBoxToken(lockdown->Get(), PRIMARY, &caps, saved_handles,
+ saved_handles_count, lowbox) != ERROR_SUCCESS) {
+ return SBOX_ERROR_CANNOT_CREATE_LOWBOX_TOKEN;
+ }
+
+ if (!ReplacePackageSidInDacl(lowbox->Get(), SE_KERNEL_OBJECT, package_sid,
+ TOKEN_ALL_ACCESS)) {
+ return SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL;
+ }
+ }
+
+ // Create the 'better' token. We use this token as the one that the main
+ // thread uses when booting up the process. It should contain most of
+ // what we need (before reaching main( ))
+ result = CreateRestrictedToken(
+ effective_token_, initial_level_, integrity_level_, IMPERSONATION,
+ lockdown_default_dacl_, random_sid_ptr, use_restricting_sids_, initial);
+ if (ERROR_SUCCESS != result)
+ return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN;
+
+ return SBOX_ALL_OK;
+}
+
+PSID PolicyBase::GetLowBoxSid() const {
+ return lowbox_sid_;
+}
+
+ResultCode PolicyBase::AddTarget(TargetProcess* target) {
+ if (policy_)
+ policy_maker_->Done();
+
+ if (!ApplyProcessMitigationsToSuspendedProcess(target->Process(),
+ mitigations_)) {
+ return SBOX_ERROR_APPLY_ASLR_MITIGATIONS;
+ }
+
+ ResultCode ret = SetupAllInterceptions(target);
+
+ if (ret != SBOX_ALL_OK)
+ return ret;
+
+ if (!SetupHandleCloser(target))
+ return SBOX_ERROR_SETUP_HANDLE_CLOSER;
+
+ DWORD win_error = ERROR_SUCCESS;
+ // Initialize the sandbox infrastructure for the target.
+ // TODO(wfh) do something with win_error code here.
+ ret = target->Init(dispatcher_.get(), policy_, kIPCMemSize, kPolMemSize,
+ &win_error);
+
+ if (ret != SBOX_ALL_OK)
+ return ret;
+
+ g_shared_delayed_integrity_level = delayed_integrity_level_;
+ ret = target->TransferVariable("g_shared_delayed_integrity_level",
+ &g_shared_delayed_integrity_level,
+ sizeof(g_shared_delayed_integrity_level));
+ g_shared_delayed_integrity_level = INTEGRITY_LEVEL_LAST;
+ if (SBOX_ALL_OK != ret)
+ return ret;
+
+ // Add in delayed mitigations and pseudo-mitigations enforced at startup.
+ g_shared_delayed_mitigations =
+ delayed_mitigations_ | FilterPostStartupProcessMitigations(mitigations_);
+ if (!CanSetProcessMitigationsPostStartup(g_shared_delayed_mitigations))
+ return SBOX_ERROR_BAD_PARAMS;
+
+ ret = target->TransferVariable("g_shared_delayed_mitigations",
+ &g_shared_delayed_mitigations,
+ sizeof(g_shared_delayed_mitigations));
+ g_shared_delayed_mitigations = 0;
+ if (SBOX_ALL_OK != ret)
+ return ret;
+
+ AutoLock lock(&lock_);
+ targets_.push_back(target);
+ return SBOX_ALL_OK;
+}
+
+bool PolicyBase::OnJobEmpty(HANDLE job) {
+ AutoLock lock(&lock_);
+ TargetSet::iterator it;
+ for (it = targets_.begin(); it != targets_.end(); ++it) {
+ if ((*it)->Job() == job)
+ break;
+ }
+ if (it == targets_.end()) {
+ return false;
+ }
+ TargetProcess* target = *it;
+ targets_.erase(it);
+ delete target;
+ return true;
+}
+
+ResultCode PolicyBase::SetDisconnectCsrss() {
+// Does not work on 32-bit, and the ASAN runtime falls over with the
+// CreateThread EAT patch used when this is enabled.
+// See https://crbug.com/783296#c27.
+#if defined(_WIN64) && !defined(ADDRESS_SANITIZER)
+ if (base::win::GetVersion() >= base::win::Version::WIN10) {
+ is_csrss_connected_ = false;
+ return AddKernelObjectToClose(L"ALPC Port", nullptr);
+ }
+#endif // !defined(_WIN64)
+ return SBOX_ALL_OK;
+}
+
+EvalResult PolicyBase::EvalPolicy(IpcTag service,
+ CountedParameterSetBase* params) {
+ if (policy_) {
+ if (!policy_->entry[static_cast<size_t>(service)]) {
+ // There is no policy for this particular service. This is not a big
+ // deal.
+ return DENY_ACCESS;
+ }
+ for (size_t i = 0; i < params->count; i++) {
+ if (!params->parameters[i].IsValid()) {
+ NOTREACHED();
+ return SIGNAL_ALARM;
+ }
+ }
+ PolicyProcessor pol_evaluator(policy_->entry[static_cast<size_t>(service)]);
+ PolicyResult result =
+ pol_evaluator.Evaluate(kShortEval, params->parameters, params->count);
+ if (POLICY_MATCH == result)
+ return pol_evaluator.GetAction();
+
+ DCHECK(POLICY_ERROR != result);
+ }
+
+ return DENY_ACCESS;
+}
+
+HANDLE PolicyBase::GetStdoutHandle() {
+ return stdout_handle_;
+}
+
+HANDLE PolicyBase::GetStderrHandle() {
+ return stderr_handle_;
+}
+
+void PolicyBase::SetEnableOPMRedirection() {
+ enable_opm_redirection_ = true;
+}
+
+bool PolicyBase::GetEnableOPMRedirection() {
+ return enable_opm_redirection_;
+}
+
+ResultCode PolicyBase::AddAppContainerProfile(const wchar_t* package_name,
+ bool create_profile) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return SBOX_ERROR_UNSUPPORTED;
+
+ DCHECK(package_name);
+ if (lowbox_sid_ || app_container_profile_ ||
+ integrity_level_ != INTEGRITY_LEVEL_LAST) {
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+
+ if (create_profile) {
+ app_container_profile_ = AppContainerProfileBase::Create(
+ package_name, L"Chrome Sandbox", L"Profile for Chrome Sandbox");
+ } else {
+ app_container_profile_ = AppContainerProfileBase::Open(package_name);
+ }
+ if (!app_container_profile_)
+ return SBOX_ERROR_CREATE_APPCONTAINER_PROFILE;
+
+ // A bug exists in CreateProcess where enabling an AppContainer profile and
+ // passing a set of mitigation flags will generate ERROR_INVALID_PARAMETER.
+ // Apply best efforts here and convert set mitigations to delayed mitigations.
+ // This bug looks to have been fixed in Win10 RS5, so exit early if possible.
+ if (base::win::GetVersion() >= base::win::Version::WIN10_RS5)
+ return SBOX_ALL_OK;
+
+ delayed_mitigations_ =
+ mitigations_ & GetAllowedPostStartupProcessMitigations();
+ DCHECK(delayed_mitigations_ ==
+ (mitigations_ & ~(MITIGATION_SEHOP |
+ MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION)));
+ mitigations_ = 0;
+ return SBOX_ALL_OK;
+}
+
+scoped_refptr<AppContainerProfile> PolicyBase::GetAppContainerProfile() {
+ return GetAppContainerProfileBase();
+}
+
+void PolicyBase::SetEffectiveToken(HANDLE token) {
+ CHECK(token);
+ effective_token_ = token;
+}
+
+scoped_refptr<AppContainerProfileBase>
+PolicyBase::GetAppContainerProfileBase() {
+ return app_container_profile_;
+}
+
+ResultCode PolicyBase::SetupAllInterceptions(TargetProcess* target) {
+ InterceptionManager manager(target, relaxed_interceptions_);
+
+ if (policy_) {
+ for (size_t i = 0; i < kMaxIpcTag; i++) {
+ if (policy_->entry[i] &&
+ !dispatcher_->SetupService(&manager, static_cast<IpcTag>(i)))
+ return SBOX_ERROR_SETUP_INTERCEPTION_SERVICE;
+ }
+ }
+
+ for (const std::wstring& dll : blocklisted_dlls_)
+ manager.AddToUnloadModules(dll.c_str());
+
+ if (!SetupBasicInterceptions(&manager, is_csrss_connected_))
+ return SBOX_ERROR_SETUP_BASIC_INTERCEPTIONS;
+
+ ResultCode rc = manager.InitializeInterceptions();
+ if (rc != SBOX_ALL_OK)
+ return rc;
+
+ // Finally, setup imports on the target so the interceptions can work.
+ if (!SetupNtdllImports(target))
+ return SBOX_ERROR_SETUP_NTDLL_IMPORTS;
+
+ return SBOX_ALL_OK;
+}
+
+bool PolicyBase::SetupHandleCloser(TargetProcess* target) {
+ return handle_closer_.InitializeTargetHandles(target);
+}
+
+ResultCode PolicyBase::AddRuleInternal(SubSystem subsystem,
+ Semantics semantics,
+ const wchar_t* pattern) {
+ if (!policy_) {
+ policy_ = MakeBrokerPolicyMemory();
+ DCHECK(policy_);
+ policy_maker_ = new LowLevelPolicy(policy_);
+ DCHECK(policy_maker_);
+ }
+
+ switch (subsystem) {
+ case SUBSYS_FILES: {
+ if (!file_system_init_) {
+ if (!FileSystemPolicy::SetInitialRules(policy_maker_))
+ return SBOX_ERROR_BAD_PARAMS;
+ file_system_init_ = true;
+ }
+ if (!FileSystemPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_SYNC: {
+ if (!SyncPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_PROCESS: {
+ if (lockdown_level_ < USER_INTERACTIVE &&
+ TargetPolicy::PROCESS_ALL_EXEC == semantics) {
+ // This is unsupported. This is a huge security risk to give full access
+ // to a process handle.
+ return SBOX_ERROR_UNSUPPORTED;
+ }
+ if (!ProcessPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_NAMED_PIPES: {
+ if (!NamedPipePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_REGISTRY: {
+ if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+ case SUBSYS_HANDLES: {
+ if (!HandlePolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+
+ case SUBSYS_WIN32K_LOCKDOWN: {
+ // Win32k intercept rules only supported on Windows 8 and above. This must
+ // match the version checks in process_mitigations.cc for consistency.
+ if (base::win::GetVersion() >= base::win::Version::WIN8) {
+ DCHECK_EQ(MITIGATION_WIN32K_DISABLE,
+ mitigations_ & MITIGATION_WIN32K_DISABLE)
+ << "Enable MITIGATION_WIN32K_DISABLE before adding win32k policy "
+ "rules.";
+ if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
+ pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ }
+ break;
+ }
+ case SUBSYS_SIGNED_BINARY: {
+ // Signed intercept rules only supported on Windows 10 TH2 and above. This
+ // must match the version checks in process_mitigations.cc for
+ // consistency.
+ if (base::win::GetVersion() >= base::win::Version::WIN10_TH2) {
+ DCHECK_EQ(MITIGATION_FORCE_MS_SIGNED_BINS,
+ (mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS) | (delayed_mitigations_ & MITIGATION_FORCE_MS_SIGNED_BINS))
+ << "Enable MITIGATION_FORCE_MS_SIGNED_BINS before adding signed "
+ "policy rules.";
+ if (!SignedPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ }
+ break;
+ }
+ case SUBSYS_LINE_BREAK: {
+ if (!LineBreakPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
+ NOTREACHED();
+ return SBOX_ERROR_BAD_PARAMS;
+ }
+ break;
+ }
+
+ default: { return SBOX_ERROR_UNSUPPORTED; }
+ }
+
+ return SBOX_ALL_OK;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
new file mode 100644
index 0000000000..18268e230d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
@@ -0,0 +1,198 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
+#define SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
+
+#include <windows.h>
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <list>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/process/launch.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/app_container_profile_base.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/handle_closer.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_engine_params.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+class LowLevelPolicy;
+class PolicyDiagnostic;
+class TargetProcess;
+struct PolicyGlobal;
+
+class PolicyBase final : public TargetPolicy {
+ public:
+ PolicyBase();
+
+ // TargetPolicy:
+ void AddRef() override;
+ void Release() override;
+ ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) override;
+ TokenLevel GetInitialTokenLevel() const override;
+ TokenLevel GetLockdownTokenLevel() const override;
+ void SetDoNotUseRestrictingSIDs() final;
+ ResultCode SetJobLevel(JobLevel job_level, uint32_t ui_exceptions) override;
+ JobLevel GetJobLevel() const override;
+ ResultCode SetJobMemoryLimit(size_t memory_limit) override;
+ ResultCode SetAlternateDesktop(bool alternate_winstation) override;
+ std::wstring GetAlternateDesktop() const override;
+ ResultCode CreateAlternateDesktop(bool alternate_winstation) override;
+ void DestroyAlternateDesktop() override;
+ ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) override;
+ IntegrityLevel GetIntegrityLevel() const override;
+ ResultCode SetDelayedIntegrityLevel(IntegrityLevel integrity_level) override;
+ ResultCode SetLowBox(const wchar_t* sid) override;
+ ResultCode SetProcessMitigations(MitigationFlags flags) override;
+ MitigationFlags GetProcessMitigations() override;
+ ResultCode SetDelayedProcessMitigations(MitigationFlags flags) override;
+ MitigationFlags GetDelayedProcessMitigations() const override;
+ ResultCode SetDisconnectCsrss() override;
+ void SetStrictInterceptions() override;
+ ResultCode SetStdoutHandle(HANDLE handle) override;
+ ResultCode SetStderrHandle(HANDLE handle) override;
+ ResultCode AddRule(SubSystem subsystem,
+ Semantics semantics,
+ const wchar_t* pattern) override;
+ ResultCode AddDllToUnload(const wchar_t* dll_name) override;
+ ResultCode AddKernelObjectToClose(const wchar_t* handle_type,
+ const wchar_t* handle_name) override;
+ void AddHandleToShare(HANDLE handle) override;
+ void SetLockdownDefaultDacl() override;
+ void AddRestrictingRandomSid() override;
+ void SetEnableOPMRedirection() override;
+ bool GetEnableOPMRedirection() override;
+ ResultCode AddAppContainerProfile(const wchar_t* package_name,
+ bool create_profile) override;
+ scoped_refptr<AppContainerProfile> GetAppContainerProfile() override;
+ void SetEffectiveToken(HANDLE token) override;
+
+ // Get the AppContainer profile as its internal type.
+ scoped_refptr<AppContainerProfileBase> GetAppContainerProfileBase();
+
+ // Creates a Job object with the level specified in a previous call to
+ // SetJobLevel().
+ ResultCode MakeJobObject(base::win::ScopedHandle* job);
+
+ // Creates the two tokens with the levels specified in a previous call to
+ // SetTokenLevel(). Also creates a lowbox token if specified based on the
+ // lowbox SID.
+ ResultCode MakeTokens(base::win::ScopedHandle* initial,
+ base::win::ScopedHandle* lockdown,
+ base::win::ScopedHandle* lowbox);
+
+ PSID GetLowBoxSid() const;
+
+ // Adds a target process to the internal list of targets. Internally a
+ // call to TargetProcess::Init() is issued.
+ ResultCode AddTarget(TargetProcess* target);
+
+ // Called when there are no more active processes in a Job.
+ // Removes a Job object associated with this policy and the target associated
+ // with the job.
+ bool OnJobEmpty(HANDLE job);
+
+ EvalResult EvalPolicy(IpcTag service, CountedParameterSetBase* params);
+
+ HANDLE GetStdoutHandle();
+ HANDLE GetStderrHandle();
+
+ // Returns the list of handles being shared with the target process.
+ const base::HandlesToInheritVector& GetHandlesBeingShared();
+
+ private:
+ // Allow PolicyInfo to snapshot PolicyBase for diagnostics.
+ friend class PolicyDiagnostic;
+ ~PolicyBase();
+
+ // Sets up interceptions for a new target.
+ ResultCode SetupAllInterceptions(TargetProcess* target);
+
+ // Sets up the handle closer for a new target.
+ bool SetupHandleCloser(TargetProcess* target);
+
+ ResultCode AddRuleInternal(SubSystem subsystem,
+ Semantics semantics,
+ const wchar_t* pattern);
+
+ // This lock synchronizes operations on the targets_ collection.
+ CRITICAL_SECTION lock_;
+ // Maintains the list of target process associated with this policy.
+ // The policy takes ownership of them.
+ typedef std::list<TargetProcess*> TargetSet;
+ TargetSet targets_;
+ // Standard object-lifetime reference counter.
+ volatile LONG ref_count;
+ // The user-defined global policy settings.
+ TokenLevel lockdown_level_;
+ TokenLevel initial_level_;
+ bool use_restricting_sids_ = true;
+ JobLevel job_level_;
+ uint32_t ui_exceptions_;
+ size_t memory_limit_;
+ bool use_alternate_desktop_;
+ bool use_alternate_winstation_;
+ // Helps the file system policy initialization.
+ bool file_system_init_;
+ bool relaxed_interceptions_;
+ HANDLE stdout_handle_;
+ HANDLE stderr_handle_;
+ IntegrityLevel integrity_level_;
+ IntegrityLevel delayed_integrity_level_;
+ MitigationFlags mitigations_;
+ MitigationFlags delayed_mitigations_;
+ bool is_csrss_connected_;
+ // Object in charge of generating the low level policy.
+ LowLevelPolicy* policy_maker_;
+ // Memory structure that stores the low level policy.
+ PolicyGlobal* policy_;
+ // The list of dlls to unload in the target process.
+ std::vector<std::wstring> blocklisted_dlls_;
+ // This is a map of handle-types to names that we need to close in the
+ // target process. A null set means we need to close all handles of the
+ // given type.
+ HandleCloser handle_closer_;
+ PSID lowbox_sid_;
+ base::win::ScopedHandle lowbox_directory_;
+ std::unique_ptr<Dispatcher> dispatcher_;
+ bool lockdown_default_dacl_;
+ bool add_restricting_random_sid_;
+
+ static HDESK alternate_desktop_handle_;
+ static HWINSTA alternate_winstation_handle_;
+ static HDESK alternate_desktop_local_winstation_handle_;
+ static IntegrityLevel alternate_desktop_integrity_level_label_;
+ static IntegrityLevel
+ alternate_desktop_local_winstation_integrity_level_label_;
+
+ // Contains the list of handles being shared with the target process.
+ // This list contains handles other than the stderr/stdout handles which are
+ // shared with the target at times.
+ base::HandlesToInheritVector handles_to_share_;
+ bool enable_opm_redirection_;
+
+ scoped_refptr<AppContainerProfileBase> app_container_profile_;
+
+ HANDLE effective_token_;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyBase);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SANDBOX_POLICY_BASE_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_rand.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_rand.cc
new file mode 100644
index 0000000000..9bc8634ec6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_rand.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox_rand.h"
+
+#include <windows.h>
+
+// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the
+// "Community Additions" comment on MSDN here:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
+#define SystemFunction036 NTAPI SystemFunction036
+#include <ntsecapi.h>
+#undef SystemFunction036
+
+namespace sandbox {
+
+bool GetRandom(unsigned int* random_value) {
+ return RtlGenRandom(random_value, sizeof(unsigned int)) != false;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_rand.h b/security/sandbox/chromium/sandbox/win/src/sandbox_rand.h
new file mode 100644
index 0000000000..f4662f9a84
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_rand.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_RAND_H_
+#define SANDBOX_SRC_SANDBOX_RAND_H_
+
+namespace sandbox {
+
+// Generate a random value in |random_value|. Returns true on success.
+bool GetRandom(unsigned int* random_value);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SANDBOX_RAND_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_types.h b/security/sandbox/chromium/sandbox/win/src/sandbox_types.h
new file mode 100644
index 0000000000..782541863d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_types.h
@@ -0,0 +1,199 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
+#define SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
+
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+
+namespace sandbox {
+
+#ifdef __MINGW32__
+// Map Microsoft's proprietary more-safe version of copy() back to
+// the std::basic_string method
+#define _Copy_s copy
+#endif
+
+// Operation result codes returned by the sandbox API.
+//
+// Note: These codes are listed in a histogram and any new codes should be added
+// at the end. If the underlying type is changed then the forward declaration in
+// sandbox_init.h must be updated.
+//
+enum ResultCode : int {
+ SBOX_ALL_OK = 0,
+ // Error is originating on the win32 layer. Call GetlastError() for more
+ // information.
+ SBOX_ERROR_GENERIC = 1,
+ // An invalid combination of parameters was given to the API.
+ SBOX_ERROR_BAD_PARAMS = 2,
+ // The desired operation is not supported at this time.
+ SBOX_ERROR_UNSUPPORTED = 3,
+ // The request requires more memory that allocated or available.
+ SBOX_ERROR_NO_SPACE = 4,
+ // The ipc service requested does not exist.
+ SBOX_ERROR_INVALID_IPC = 5,
+ // The ipc service did not complete.
+ SBOX_ERROR_FAILED_IPC = 6,
+ // The requested handle was not found.
+ SBOX_ERROR_NO_HANDLE = 7,
+ // This function was not expected to be called at this time.
+ SBOX_ERROR_UNEXPECTED_CALL = 8,
+ // WaitForAllTargets is already called.
+ SBOX_ERROR_WAIT_ALREADY_CALLED = 9,
+ // A channel error prevented DoCall from executing.
+ SBOX_ERROR_CHANNEL_ERROR = 10,
+ // Failed to create the alternate desktop.
+ SBOX_ERROR_CANNOT_CREATE_DESKTOP = 11,
+ // Failed to create the alternate window station.
+ SBOX_ERROR_CANNOT_CREATE_WINSTATION = 12,
+ // Failed to switch back to the interactive window station.
+ SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION = 13,
+ // The supplied AppContainer is not valid.
+ SBOX_ERROR_INVALID_APP_CONTAINER = 14,
+ // The supplied capability is not valid.
+ SBOX_ERROR_INVALID_CAPABILITY = 15,
+ // There is a failure initializing the AppContainer.
+ SBOX_ERROR_CANNOT_INIT_APPCONTAINER = 16,
+ // Initializing or updating ProcThreadAttributes failed.
+ SBOX_ERROR_PROC_THREAD_ATTRIBUTES = 17,
+ // Error in creating process.
+ SBOX_ERROR_CREATE_PROCESS = 18,
+ // Failure calling delegate PreSpawnTarget.
+ SBOX_ERROR_DELEGATE_PRE_SPAWN = 19,
+ // Could not assign process to job object.
+ SBOX_ERROR_ASSIGN_PROCESS_TO_JOB_OBJECT = 20,
+ // Could not assign process to job object.
+ SBOX_ERROR_SET_THREAD_TOKEN = 21,
+ // Could not get thread context of new process.
+ SBOX_ERROR_GET_THREAD_CONTEXT = 22,
+ // Could not duplicate target info of new process.
+ SBOX_ERROR_DUPLICATE_TARGET_INFO = 23,
+ // Could not set low box token.
+ SBOX_ERROR_SET_LOW_BOX_TOKEN = 24,
+ // Could not create file mapping for IPC dispatcher.
+ SBOX_ERROR_CREATE_FILE_MAPPING = 25,
+ // Could not duplicate shared section into target process for IPC dispatcher.
+ SBOX_ERROR_DUPLICATE_SHARED_SECTION = 26,
+ // Could not map view of shared memory in broker.
+ SBOX_ERROR_MAP_VIEW_OF_SHARED_SECTION = 27,
+ // Could not apply ASLR mitigations to target process.
+ SBOX_ERROR_APPLY_ASLR_MITIGATIONS = 28,
+ // Could not setup one of the required interception services.
+ SBOX_ERROR_SETUP_BASIC_INTERCEPTIONS = 29,
+ // Could not setup basic interceptions.
+ SBOX_ERROR_SETUP_INTERCEPTION_SERVICE = 30,
+ // Could not initialize interceptions. This usually means 3rd party software
+ // is stomping on our hooks, or can sometimes mean the syscall format has
+ // changed.
+ SBOX_ERROR_INITIALIZE_INTERCEPTIONS = 31,
+ // Could not setup the imports for ntdll in target process.
+ SBOX_ERROR_SETUP_NTDLL_IMPORTS = 32,
+ // Could not setup the handle closer in target process.
+ SBOX_ERROR_SETUP_HANDLE_CLOSER = 33,
+ // Cannot get the current Window Station.
+ SBOX_ERROR_CANNOT_GET_WINSTATION = 34,
+ // Cannot query the security attributes of the current Window Station.
+ SBOX_ERROR_CANNOT_QUERY_WINSTATION_SECURITY = 35,
+ // Cannot get the current Desktop.
+ SBOX_ERROR_CANNOT_GET_DESKTOP = 36,
+ // Cannot query the security attributes of the current Desktop.
+ SBOX_ERROR_CANNOT_QUERY_DESKTOP_SECURITY = 37,
+ // Cannot setup the interception manager config buffer.
+ SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_CONFIG_BUFFER = 38,
+ // Cannot copy data to the child process.
+ SBOX_ERROR_CANNOT_COPY_DATA_TO_CHILD = 39,
+ // Cannot setup the interception thunk.
+ SBOX_ERROR_CANNOT_SETUP_INTERCEPTION_THUNK = 40,
+ // Cannot resolve the interception thunk.
+ SBOX_ERROR_CANNOT_RESOLVE_INTERCEPTION_THUNK = 41,
+ // Cannot write interception thunk to child process.
+ SBOX_ERROR_CANNOT_WRITE_INTERCEPTION_THUNK = 42,
+ // Cannot find the base address of the new process.
+ SBOX_ERROR_CANNOT_FIND_BASE_ADDRESS = 43,
+ // Cannot create the AppContainer profile.
+ SBOX_ERROR_CREATE_APPCONTAINER_PROFILE = 44,
+ // Cannot create the AppContainer as the main executable can't be accessed.
+ SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_ACCESS_CHECK = 45,
+ // Cannot create the AppContainer as adding a capability failed.
+ SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY = 46,
+ // Cannot initialize a job object.
+ SBOX_ERROR_CANNOT_INIT_JOB = 47,
+ // Invalid LowBox SID string.
+ SBOX_ERROR_INVALID_LOWBOX_SID = 48,
+ // Cannot create restricted token.
+ SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN = 49,
+ // Cannot set the integrity level on a desktop object.
+ SBOX_ERROR_CANNOT_SET_DESKTOP_INTEGRITY = 50,
+ // Cannot create a LowBox token.
+ SBOX_ERROR_CANNOT_CREATE_LOWBOX_TOKEN = 51,
+ // Cannot modify LowBox token's DACL.
+ SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL = 52,
+ // Cannot create restricted impersonation token.
+ SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN = 53,
+ // Cannot duplicate target process handle.
+ SBOX_ERROR_CANNOT_DUPLICATE_PROCESS_HANDLE = 54,
+ // Cannot load executable for variable transfer.
+ SBOX_ERROR_CANNOT_LOADLIBRARY_EXECUTABLE = 55,
+ // Cannot find variable address for transfer.
+ SBOX_ERROR_CANNOT_FIND_VARIABLE_ADDRESS = 56,
+ // Cannot write variable value.
+ SBOX_ERROR_CANNOT_WRITE_VARIABLE_VALUE = 57,
+ // Short write to variable.
+ SBOX_ERROR_INVALID_WRITE_VARIABLE_SIZE = 58,
+ // Cannot initialize BrokerServices.
+ SBOX_ERROR_CANNOT_INIT_BROKERSERVICES = 59,
+ // Placeholder for last item of the enum.
+ SBOX_ERROR_LAST
+};
+
+// If the sandbox cannot create a secure environment for the target, the
+// target will be forcibly terminated. These are the process exit codes.
+enum TerminationCodes {
+ SBOX_FATAL_INTEGRITY = 7006, // Could not set the integrity level.
+ SBOX_FATAL_DROPTOKEN = 7007, // Could not lower the token.
+ SBOX_FATAL_FLUSHANDLES = 7008, // Failed to flush registry handles.
+ SBOX_FATAL_CACHEDISABLE = 7009, // Failed to forbid HCKU caching.
+ SBOX_FATAL_CLOSEHANDLES = 7010, // Failed to close pending handles.
+ SBOX_FATAL_MITIGATION = 7011, // Could not set the mitigation policy.
+ SBOX_FATAL_MEMORY_EXCEEDED = 7012, // Exceeded the job memory limit.
+ SBOX_FATAL_WARMUP = 7013, // Failed to warmup.
+ SBOX_FATAL_LAST
+};
+
+#if !defined(SANDBOX_FUZZ_TARGET)
+static_assert(SBOX_FATAL_MEMORY_EXCEEDED ==
+ base::win::kSandboxFatalMemoryExceeded,
+ "Value for SBOX_FATAL_MEMORY_EXCEEDED must match base.");
+#endif // !defined(SANDBOX_FUZZ_TARGET)
+
+class BrokerServices;
+class TargetServices;
+
+// Contains the pointer to a target or broker service.
+struct SandboxInterfaceInfo {
+ BrokerServices* broker_services;
+ TargetServices* target_services;
+};
+
+#if SANDBOX_EXPORTS
+#define SANDBOX_INTERCEPT extern "C" __declspec(dllexport)
+#else
+#define SANDBOX_INTERCEPT extern "C"
+#endif
+
+enum InterceptionType {
+ INTERCEPTION_INVALID = 0,
+ INTERCEPTION_SERVICE_CALL, // Trampoline of an NT native call
+ INTERCEPTION_EAT,
+ INTERCEPTION_SIDESTEP, // Preamble patch
+ INTERCEPTION_SMART_SIDESTEP, // Preamble patch but bypass internal calls
+ INTERCEPTION_UNLOAD_MODULE, // Unload the module (don't patch)
+ INTERCEPTION_LAST // Placeholder for last item in the enumeration
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SANDBOX_TYPES_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_utils.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_utils.cc
new file mode 100644
index 0000000000..f34daa7d3e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_utils.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sandbox_utils.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "sandbox/win/src/internal_types.h"
+
+namespace sandbox {
+
+void InitObjectAttribs(const std::wstring& name,
+ ULONG attributes,
+ HANDLE root,
+ OBJECT_ATTRIBUTES* obj_attr,
+ UNICODE_STRING* uni_name,
+ SECURITY_QUALITY_OF_SERVICE* security_qos) {
+ static RtlInitUnicodeStringFunction RtlInitUnicodeString;
+ if (!RtlInitUnicodeString) {
+ HMODULE ntdll = ::GetModuleHandle(kNtdllName);
+ RtlInitUnicodeString = reinterpret_cast<RtlInitUnicodeStringFunction>(
+ GetProcAddress(ntdll, "RtlInitUnicodeString"));
+ DCHECK(RtlInitUnicodeString);
+ }
+ RtlInitUnicodeString(uni_name, name.c_str());
+ InitializeObjectAttributes(obj_attr, uni_name, attributes, root, nullptr);
+ obj_attr->SecurityQualityOfService = security_qos;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_utils.h b/security/sandbox/chromium/sandbox/win/src/sandbox_utils.h
new file mode 100644
index 0000000000..580d1298f6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_utils.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SANDBOX_UTILS_H_
+#define SANDBOX_SRC_SANDBOX_UTILS_H_
+
+#include <windows.h>
+#include <string>
+
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+void InitObjectAttribs(const std::wstring& name,
+ ULONG attributes,
+ HANDLE root,
+ OBJECT_ATTRIBUTES* obj_attr,
+ UNICODE_STRING* uni_name,
+ SECURITY_QUALITY_OF_SERVICE* security_qos);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SANDBOX_UTILS_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/security_capabilities.cc b/security/sandbox/chromium/sandbox/win/src/security_capabilities.cc
new file mode 100644
index 0000000000..0df446b5be
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/security_capabilities.cc
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/security_capabilities.h"
+#include "base/numerics/safe_conversions.h"
+
+namespace sandbox {
+
+SecurityCapabilities::SecurityCapabilities(const Sid& package_sid,
+ const std::vector<Sid>& capabilities)
+ : SECURITY_CAPABILITIES(),
+ capabilities_(capabilities),
+ package_sid_(package_sid) {
+ AppContainerSid = package_sid_.GetPSID();
+ if (capabilities_.empty())
+ return;
+
+ capability_sids_.resize(capabilities_.size());
+ for (size_t index = 0; index < capabilities_.size(); ++index) {
+ capability_sids_[index].Sid = capabilities_[index].GetPSID();
+ capability_sids_[index].Attributes = SE_GROUP_ENABLED;
+ }
+ CapabilityCount = base::checked_cast<DWORD>(capability_sids_.size());
+ Capabilities = capability_sids_.data();
+}
+
+SecurityCapabilities::SecurityCapabilities(const Sid& package_sid)
+ : SecurityCapabilities(package_sid, std::vector<Sid>()) {}
+
+SecurityCapabilities::~SecurityCapabilities() {}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/security_capabilities.h b/security/sandbox/chromium/sandbox/win/src/security_capabilities.h
new file mode 100644
index 0000000000..7a66e59743
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/security_capabilities.h
@@ -0,0 +1,34 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SECURITY_CAPABILITIES_H_
+#define SANDBOX_SRC_SECURITY_CAPABILITIES_H_
+
+#include <windows.h>
+
+#include <vector>
+
+#include "base/macros.h"
+#include "sandbox/win/src/sid.h"
+
+namespace sandbox {
+
+class SecurityCapabilities final : public SECURITY_CAPABILITIES {
+ public:
+ explicit SecurityCapabilities(const Sid& package_sid);
+ SecurityCapabilities(const Sid& package_sid,
+ const std::vector<Sid>& capabilities);
+ ~SecurityCapabilities();
+
+ private:
+ std::vector<Sid> capabilities_;
+ std::vector<SID_AND_ATTRIBUTES> capability_sids_;
+ Sid package_sid_;
+
+ DISALLOW_COPY_AND_ASSIGN(SecurityCapabilities);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SECURITY_CAPABILITIES_H_ \ No newline at end of file
diff --git a/security/sandbox/chromium/sandbox/win/src/security_level.h b/security/sandbox/chromium/sandbox/win/src/security_level.h
new file mode 100644
index 0000000000..8e81cf21c9
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/security_level.h
@@ -0,0 +1,300 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SECURITY_LEVEL_H_
+#define SANDBOX_SRC_SECURITY_LEVEL_H_
+
+#include <stdint.h>
+
+namespace sandbox {
+
+// List of all the integrity levels supported in the sandbox.
+// The integrity level of the sandboxed process can't be set to a level higher
+// than the broker process.
+//
+// Note: These levels map to SIDs under the hood.
+// INTEGRITY_LEVEL_SYSTEM: "S-1-16-16384" System Mandatory Level
+// INTEGRITY_LEVEL_HIGH: "S-1-16-12288" High Mandatory Level
+// INTEGRITY_LEVEL_MEDIUM: "S-1-16-8192" Medium Mandatory Level
+// INTEGRITY_LEVEL_MEDIUM_LOW: "S-1-16-6144"
+// INTEGRITY_LEVEL_LOW: "S-1-16-4096" Low Mandatory Level
+// INTEGRITY_LEVEL_BELOW_LOW: "S-1-16-2048"
+// INTEGRITY_LEVEL_UNTRUSTED: "S-1-16-0" Untrusted Mandatory Level
+//
+// Not defined: "S-1-16-20480" Protected Process Mandatory Level
+// Not defined: "S-1-16-28672" Secure Process Mandatory Level
+enum IntegrityLevel {
+ INTEGRITY_LEVEL_SYSTEM,
+ INTEGRITY_LEVEL_HIGH,
+ INTEGRITY_LEVEL_MEDIUM,
+ INTEGRITY_LEVEL_MEDIUM_LOW,
+ INTEGRITY_LEVEL_LOW,
+ INTEGRITY_LEVEL_BELOW_LOW,
+ INTEGRITY_LEVEL_UNTRUSTED,
+ INTEGRITY_LEVEL_LAST
+};
+
+// The Token level specifies a set of security profiles designed to
+// provide the bulk of the security of sandbox.
+//
+// TokenLevel |Restricting |Deny Only |Privileges|
+// |Sids |Sids | |
+// ----------------------------|--------------|----------------|----------|
+// USER_LOCKDOWN | Null Sid | All | None |
+// ----------------------------|--------------|----------------|----------|
+// USER_RESTRICTED | RESTRICTED | All | Traverse |
+// ----------------------------|--------------|----------------|----------|
+// USER_LIMITED | Users | All except: | Traverse |
+// | Everyone | Users | |
+// | RESTRICTED | Everyone | |
+// | | Interactive | |
+// ----------------------------|--------------|----------------|----------|
+// USER_INTERACTIVE | Users | All except: | Traverse |
+// | Everyone | Users | |
+// | RESTRICTED | Everyone | |
+// | Owner | Interactive | |
+// | | Local | |
+// | | Authent-users | |
+// | | User | |
+// ----------------------------|--------------|----------------|----------|
+// USER_RESTRICTED_NON_ADMIN | Users | All except: | Traverse |
+// | Everyone | Users | |
+// | Interactive | Everyone | |
+// | Local | Interactive | |
+// | Authent-users| Local | |
+// | User | Authent-users | |
+// | | User | |
+// ----------------------------|--------------|----------------|----------|
+// USER_NON_ADMIN | None | All except: | Traverse |
+// | | Users | |
+// | | Everyone | |
+// | | Interactive | |
+// | | Local | |
+// | | Authent-users | |
+// | | User | |
+// ----------------------------|--------------|----------------|----------|
+// USER_RESTRICTED_SAME_ACCESS | All | None | All |
+// ----------------------------|--------------|----------------|----------|
+// USER_UNPROTECTED | None | None | All |
+// ----------------------------|--------------|----------------|----------|
+//
+// The above restrictions are actually a transformation that is applied to
+// the existing broker process token. The resulting token that will be
+// applied to the target process depends both on the token level selected
+// and on the broker token itself.
+//
+// The LOCKDOWN and RESTRICTED are designed to allow access to almost
+// nothing that has security associated with and they are the recommended
+// levels to run sandboxed code specially if there is a chance that the
+// broker is process might be started by a user that belongs to the Admins
+// or power users groups.
+enum TokenLevel {
+ USER_LOCKDOWN = 0,
+ USER_RESTRICTED,
+ USER_LIMITED,
+ USER_INTERACTIVE,
+ USER_RESTRICTED_NON_ADMIN,
+ USER_NON_ADMIN,
+ USER_RESTRICTED_SAME_ACCESS,
+ USER_UNPROTECTED,
+ USER_LAST
+};
+
+// The Job level specifies a set of decreasing security profiles for the
+// Job object that the target process will be placed into.
+// This table summarizes the security associated with each level:
+//
+// JobLevel |General |Quota |
+// |restrictions |restrictions |
+// -----------------|---------------------------------- |--------------------|
+// JOB_NONE | No job is assigned to the | None |
+// | sandboxed process. | |
+// -----------------|---------------------------------- |--------------------|
+// JOB_UNPROTECTED | None | *Kill on Job close.|
+// -----------------|---------------------------------- |--------------------|
+// JOB_INTERACTIVE | *Forbid system-wide changes using | |
+// | SystemParametersInfo(). | *Kill on Job close.|
+// | *Forbid the creation/switch of | |
+// | Desktops. | |
+// | *Forbids calls to ExitWindows(). | |
+// -----------------|---------------------------------- |--------------------|
+// JOB_LIMITED_USER | Same as INTERACTIVE_USER plus: | *One active process|
+// | *Forbid changes to the display | limit. |
+// | settings. | *Kill on Job close.|
+// -----------------|---------------------------------- |--------------------|
+// JOB_RESTRICTED | Same as LIMITED_USER plus: | *One active process|
+// | * No read/write to the clipboard. | limit. |
+// | * No access to User Handles that | *Kill on Job close.|
+// | belong to other processes. | |
+// | * Forbid message broadcasts. | |
+// | * Forbid setting global hooks. | |
+// | * No access to the global atoms | |
+// | table. | |
+// -----------------|-----------------------------------|--------------------|
+// JOB_LOCKDOWN | Same as RESTRICTED | *One active process|
+// | | limit. |
+// | | *Kill on Job close.|
+// | | *Kill on unhandled |
+// | | exception. |
+// | | |
+// In the context of the above table, 'user handles' refers to the handles of
+// windows, bitmaps, menus, etc. Files, treads and registry handles are kernel
+// handles and are not affected by the job level settings.
+enum JobLevel {
+ JOB_LOCKDOWN = 0,
+ JOB_RESTRICTED,
+ JOB_LIMITED_USER,
+ JOB_INTERACTIVE,
+ JOB_UNPROTECTED,
+ JOB_NONE
+};
+
+// These flags correspond to various process-level mitigations (eg. ASLR and
+// DEP). Most are implemented via UpdateProcThreadAttribute() plus flags for
+// the PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY attribute argument; documented
+// here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686880
+// Some mitigations are implemented directly by the sandbox or emulated to
+// the greatest extent possible when not directly supported by the OS.
+// Flags that are unsupported for the target OS will be silently ignored.
+// Flags that are invalid for their application (pre or post startup) will
+// return SBOX_ERROR_BAD_PARAMS.
+typedef uint64_t MitigationFlags;
+
+// Permanently enables DEP for the target process. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_DEP_ENABLE.
+const MitigationFlags MITIGATION_DEP = 0x00000001;
+
+// Permanently Disables ATL thunk emulation when DEP is enabled. Valid
+// only when MITIGATION_DEP is passed. Corresponds to not passing
+// PROCESS_CREATION_MITIGATION_POLICY_DEP_ATL_THUNK_ENABLE.
+const MitigationFlags MITIGATION_DEP_NO_ATL_THUNK = 0x00000002;
+
+// Enables Structured exception handling override prevention. Must be
+// enabled prior to process start. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE.
+const MitigationFlags MITIGATION_SEHOP = 0x00000004;
+
+// Forces ASLR on all images in the child process. In debug builds, must be
+// enabled after startup. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON .
+const MitigationFlags MITIGATION_RELOCATE_IMAGE = 0x00000008;
+
+// Refuses to load DLLs that cannot support ASLR. In debug builds, must be
+// enabled after startup. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS.
+const MitigationFlags MITIGATION_RELOCATE_IMAGE_REQUIRED = 0x00000010;
+
+// Terminates the process on Windows heap corruption. Coresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON.
+const MitigationFlags MITIGATION_HEAP_TERMINATE = 0x00000020;
+
+// Sets a random lower bound as the minimum user address. Must be
+// enabled prior to process start. On 32-bit processes this is
+// emulated to a much smaller degree. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON.
+const MitigationFlags MITIGATION_BOTTOM_UP_ASLR = 0x00000040;
+
+// Increases the randomness range of bottom-up ASLR to up to 1TB. Must be
+// enabled prior to process start and with MITIGATION_BOTTOM_UP_ASLR.
+// Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON
+const MitigationFlags MITIGATION_HIGH_ENTROPY_ASLR = 0x00000080;
+
+// Immediately raises an exception on a bad handle reference. Must be
+// enabled after startup. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON.
+const MitigationFlags MITIGATION_STRICT_HANDLE_CHECKS = 0x00000100;
+
+// Sets the DLL search order to LOAD_LIBRARY_SEARCH_DEFAULT_DIRS. Additional
+// directories can be added via the Windows AddDllDirectory() function.
+// http://msdn.microsoft.com/en-us/library/windows/desktop/hh310515
+// Must be enabled after startup.
+const MitigationFlags MITIGATION_DLL_SEARCH_ORDER = 0x00000200;
+
+// Changes the mandatory integrity level policy on the current process' token
+// to enable no-read and no-execute up. This prevents a lower IL process from
+// opening the process token for impersonate/duplicate/assignment.
+const MitigationFlags MITIGATION_HARDEN_TOKEN_IL_POLICY = 0x00000400;
+
+// Prevents the process from making Win32k calls. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON.
+//
+// Applications linked to user32.dll or gdi32.dll make Win32k calls during
+// setup, even if Win32k is not otherwise used. So they also need to add a rule
+// with SUBSYS_WIN32K_LOCKDOWN and semantics FAKE_USER_GDI_INIT to allow the
+// initialization to succeed.
+const MitigationFlags MITIGATION_WIN32K_DISABLE = 0x00000800;
+
+// Prevents certain built-in third party extension points from being used.
+// - App_Init DLLs
+// - Winsock Layered Service Providers (LSPs)
+// - Global Windows Hooks (NOT thread-targeted hooks)
+// - Legacy Input Method Editors (IMEs)
+// I.e.: Disable legacy hooking mechanisms. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON.
+const MitigationFlags MITIGATION_EXTENSION_POINT_DISABLE = 0x00001000;
+
+// Prevents the process from generating dynamic code or modifying executable
+// code. Second option to allow thread-specific opt-out.
+// - VirtualAlloc with PAGE_EXECUTE_*
+// - VirtualProtect with PAGE_EXECUTE_*
+// - MapViewOfFile with FILE_MAP_EXECUTE | FILE_MAP_WRITE
+// - SetProcessValidCallTargets for CFG
+// Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON and
+// PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON_ALLOW_OPT_OUT.
+const MitigationFlags MITIGATION_DYNAMIC_CODE_DISABLE = 0x00002000;
+const MitigationFlags MITIGATION_DYNAMIC_CODE_DISABLE_WITH_OPT_OUT = 0x00004000;
+// The following per-thread flag can be used with the
+// ApplyMitigationsToCurrentThread API. Requires the above process mitigation
+// to be set on the current process.
+const MitigationFlags MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD = 0x00008000;
+
+// Prevents the process from loading non-system fonts into GDI.
+// Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON
+const MitigationFlags MITIGATION_NONSYSTEM_FONT_DISABLE = 0x00010000;
+
+// Prevents the process from loading binaries NOT signed by MS.
+// Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON
+const MitigationFlags MITIGATION_FORCE_MS_SIGNED_BINS = 0x00020000;
+
+// Blocks mapping of images from remote devices. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON.
+const MitigationFlags MITIGATION_IMAGE_LOAD_NO_REMOTE = 0x00040000;
+
+// Blocks mapping of images that have the low manditory label. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON.
+const MitigationFlags MITIGATION_IMAGE_LOAD_NO_LOW_LABEL = 0x00080000;
+
+// Forces image load preference to prioritize the Windows install System32
+// folder before dll load dir, application dir and any user dirs set.
+// - Affects IAT resolution standard search path only, NOT direct LoadLibrary or
+// executable search path.
+// PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON.
+const MitigationFlags MITIGATION_IMAGE_LOAD_PREFER_SYS32 = 0x00100000;
+
+// Prevents hyperthreads from interfering with indirect branch predictions.
+// (SPECTRE Variant 2 mitigation.) Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY2_RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_ON.
+const MitigationFlags MITIGATION_RESTRICT_INDIRECT_BRANCH_PREDICTION =
+ 0x00200000;
+
+// Begin Mozilla-added flags.
+// Working down from the high bit to avoid conflict with new upstream flags.
+
+// Disable Control Flow Guard. This may seem more like an anti-mitigation, but
+// this flag allows code to make targeted changes to CFG to avoid bugs, while
+// leaving it enabled in the common case. Corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_ON.
+const MitigationFlags MITIGATION_CONTROL_FLOW_GUARD_DISABLE = 0x80000000;
+
+// This enables CET User Shadow Stack for compatible modules and corresponds to
+// PROCESS_CREATION_MITIGATION_POLICY2_CET_USER_SHADOW_STACKS_ALWAYS_ON.
+const MitigationFlags MITIGATION_CET_COMPAT_MODE = 0x40000000;
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SECURITY_LEVEL_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/service_resolver.cc b/security/sandbox/chromium/sandbox/win/src/service_resolver.cc
new file mode 100644
index 0000000000..f26322dd63
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/service_resolver.cc
@@ -0,0 +1,47 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/service_resolver.h"
+
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+NTSTATUS ServiceResolverThunk::ResolveInterceptor(
+ const void* interceptor_module,
+ const char* interceptor_name,
+ const void** address) {
+ // After all, we are using a locally mapped version of the exe, so the
+ // action is the same as for a target function.
+ return ResolveTarget(interceptor_module, interceptor_name,
+ const_cast<void**>(address));
+}
+
+// In this case all the work is done from the parent, so resolve is
+// just a simple GetProcAddress.
+NTSTATUS ServiceResolverThunk::ResolveTarget(const void* module,
+ const char* function_name,
+ void** address) {
+ if (!module)
+ return STATUS_UNSUCCESSFUL;
+
+ base::win::PEImage module_image(module);
+ *address =
+ reinterpret_cast<void*>(module_image.GetProcAddress(function_name));
+
+ if (!*address) {
+ NOTREACHED_NT();
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+void ServiceResolverThunk::AllowLocalPatches() {
+ ntdll_base_ = ::GetModuleHandle(kNtdllName);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/service_resolver.h b/security/sandbox/chromium/sandbox/win/src/service_resolver.h
new file mode 100644
index 0000000000..ee292f6a37
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/service_resolver.h
@@ -0,0 +1,158 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SERVICE_RESOLVER_H__
+#define SANDBOX_SRC_SERVICE_RESOLVER_H__
+
+#include <stddef.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/resolver.h"
+
+namespace sandbox {
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll.
+class ServiceResolverThunk : public ResolverThunk {
+ public:
+ // The service resolver needs a child process to write to.
+ ServiceResolverThunk(HANDLE process, bool relaxed)
+ : ntdll_base_(nullptr),
+ process_(process),
+ relaxed_(relaxed),
+ relative_jump_(0) {}
+ ~ServiceResolverThunk() override {}
+
+ // Implementation of Resolver::Setup.
+ NTSTATUS Setup(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) override;
+
+ // Implementation of Resolver::ResolveInterceptor.
+ NTSTATUS ResolveInterceptor(const void* module,
+ const char* function_name,
+ const void** address) override;
+
+ // Implementation of Resolver::ResolveTarget.
+ NTSTATUS ResolveTarget(const void* module,
+ const char* function_name,
+ void** address) override;
+
+ // Implementation of Resolver::GetThunkSize.
+ size_t GetThunkSize() const override;
+
+ // Call this to set up ntdll_base_ which will allow for local patches.
+ virtual void AllowLocalPatches();
+
+ // Verifies that the function specified by |target_name| in |target_module| is
+ // a service and copies the data from that function into |thunk_storage|. If
+ // |storage_bytes| is too small, then the method fails.
+ virtual NTSTATUS CopyThunk(const void* target_module,
+ const char* target_name,
+ BYTE* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used);
+
+ protected:
+ // The unit test will use this member to allow local patch on a buffer.
+ HMODULE ntdll_base_;
+
+ // Handle of the child process.
+ HANDLE process_;
+
+ private:
+ // Returns true if the code pointer by target_ corresponds to the expected
+ // type of function. Saves that code on the first part of the thunk pointed
+ // by local_thunk (should be directly accessible from the parent).
+ virtual bool IsFunctionAService(void* local_thunk) const;
+
+ // Performs the actual patch of target_.
+ // local_thunk must be already fully initialized, and the first part must
+ // contain the original code. The real type of this buffer is ServiceFullThunk
+ // (yes, private). remote_thunk (real type ServiceFullThunk), must be
+ // allocated on the child, and will contain the thunk data, after this call.
+ // Returns the apropriate status code.
+ virtual NTSTATUS PerformPatch(void* local_thunk, void* remote_thunk);
+
+ // Provides basically the same functionality as IsFunctionAService but it
+ // continues even if it does not recognize the function code. remote_thunk
+ // is the address of our memory on the child.
+ bool SaveOriginalFunction(void* local_thunk, void* remote_thunk);
+
+ // true if we are allowed to patch already-patched functions.
+ bool relaxed_;
+ ULONG relative_jump_;
+
+ DISALLOW_COPY_AND_ASSIGN(ServiceResolverThunk);
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on WOW64 (32 bit ntdll on 64 bit Vista).
+class Wow64ResolverThunk : public ServiceResolverThunk {
+ public:
+ // The service resolver needs a child process to write to.
+ Wow64ResolverThunk(HANDLE process, bool relaxed)
+ : ServiceResolverThunk(process, relaxed) {}
+ ~Wow64ResolverThunk() override {}
+
+ private:
+ bool IsFunctionAService(void* local_thunk) const override;
+
+ DISALLOW_COPY_AND_ASSIGN(Wow64ResolverThunk);
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on WOW64 for Windows 8.
+class Wow64W8ResolverThunk : public ServiceResolverThunk {
+ public:
+ // The service resolver needs a child process to write to.
+ Wow64W8ResolverThunk(HANDLE process, bool relaxed)
+ : ServiceResolverThunk(process, relaxed) {}
+ ~Wow64W8ResolverThunk() override {}
+
+ private:
+ bool IsFunctionAService(void* local_thunk) const override;
+
+ DISALLOW_COPY_AND_ASSIGN(Wow64W8ResolverThunk);
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on Windows 8.
+class Win8ResolverThunk : public ServiceResolverThunk {
+ public:
+ // The service resolver needs a child process to write to.
+ Win8ResolverThunk(HANDLE process, bool relaxed)
+ : ServiceResolverThunk(process, relaxed) {}
+ ~Win8ResolverThunk() override {}
+
+ private:
+ bool IsFunctionAService(void* local_thunk) const override;
+
+ DISALLOW_COPY_AND_ASSIGN(Win8ResolverThunk);
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll on WOW64 for Windows 10.
+class Wow64W10ResolverThunk : public ServiceResolverThunk {
+ public:
+ // The service resolver needs a child process to write to.
+ Wow64W10ResolverThunk(HANDLE process, bool relaxed)
+ : ServiceResolverThunk(process, relaxed) {}
+ ~Wow64W10ResolverThunk() override {}
+
+ private:
+ bool IsFunctionAService(void* local_thunk) const override;
+
+ DISALLOW_COPY_AND_ASSIGN(Wow64W10ResolverThunk);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SERVICE_RESOLVER_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/service_resolver_32.cc b/security/sandbox/chromium/sandbox/win/src/service_resolver_32.cc
new file mode 100644
index 0000000000..d95ce0086b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/service_resolver_32.cc
@@ -0,0 +1,476 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/service_resolver.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/bit_cast.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+#pragma pack(push, 1)
+
+const BYTE kMovEax = 0xB8;
+const BYTE kMovEdx = 0xBA;
+const USHORT kMovEdxEsp = 0xD48B;
+const USHORT kCallPtrEdx = 0x12FF;
+const USHORT kCallEdx = 0xD2FF;
+const BYTE kCallEip = 0xE8;
+const BYTE kRet = 0xC2;
+const BYTE kRet2 = 0xC3;
+const USHORT kJmpEdx = 0xE2FF;
+const USHORT kXorEcx = 0xC933;
+const ULONG kLeaEdx = 0x0424548D;
+const ULONG kCallFs1 = 0xC015FF64;
+const USHORT kCallFs2 = 0;
+const BYTE kCallFs3 = 0;
+const BYTE kAddEsp1 = 0x83;
+const USHORT kAddEsp2 = 0x4C4;
+const BYTE kJmp32 = 0xE9;
+const USHORT kSysenter = 0x340F;
+
+// Service code for 32 bit systems.
+// NOTE: on win2003 "call dword ptr [edx]" is "call edx".
+struct ServiceEntry {
+ // This struct contains roughly the following code:
+ // 00 mov eax,25h
+ // 05 mov edx,offset SharedUserData!SystemCallStub (7ffe0300)
+ // 0a call dword ptr [edx]
+ // 0c ret 2Ch
+ // 0f nop
+ BYTE mov_eax; // = B8
+ ULONG service_id;
+ BYTE mov_edx; // = BA
+ ULONG stub;
+ USHORT call_ptr_edx; // = FF 12
+ BYTE ret; // = C2
+ USHORT num_params;
+ BYTE nop;
+};
+
+// Service code for 32 bit Windows 8.
+struct ServiceEntryW8 {
+ // This struct contains the following code:
+ // 00 b825000000 mov eax,25h
+ // 05 e803000000 call eip+3
+ // 0a c22c00 ret 2Ch
+ // 0d 8bd4 mov edx,esp
+ // 0f 0f34 sysenter
+ // 11 c3 ret
+ // 12 8bff mov edi,edi
+ BYTE mov_eax; // = B8
+ ULONG service_id;
+ BYTE call_eip; // = E8
+ ULONG call_offset;
+ BYTE ret_p; // = C2
+ USHORT num_params;
+ USHORT mov_edx_esp; // = BD D4
+ USHORT sysenter; // = 0F 34
+ BYTE ret; // = C3
+ USHORT nop;
+};
+
+// Service code for a 32 bit process running on a 64 bit os.
+struct Wow64Entry {
+ // This struct may contain one of two versions of code:
+ // 1. For XP, Vista and 2K3:
+ // 00 b825000000 mov eax, 25h
+ // 05 33c9 xor ecx, ecx
+ // 07 8d542404 lea edx, [esp + 4]
+ // 0b 64ff15c0000000 call dword ptr fs:[0C0h]
+ // 12 c22c00 ret 2Ch
+ //
+ // 2. For Windows 7:
+ // 00 b825000000 mov eax, 25h
+ // 05 33c9 xor ecx, ecx
+ // 07 8d542404 lea edx, [esp + 4]
+ // 0b 64ff15c0000000 call dword ptr fs:[0C0h]
+ // 12 83c404 add esp, 4
+ // 15 c22c00 ret 2Ch
+ //
+ // So we base the structure on the bigger one:
+ BYTE mov_eax; // = B8
+ ULONG service_id;
+ USHORT xor_ecx; // = 33 C9
+ ULONG lea_edx; // = 8D 54 24 04
+ ULONG call_fs1; // = 64 FF 15 C0
+ USHORT call_fs2; // = 00 00
+ BYTE call_fs3; // = 00
+ BYTE add_esp1; // = 83 or ret
+ USHORT add_esp2; // = C4 04 or num_params
+ BYTE ret; // = C2
+ USHORT num_params;
+};
+
+// Service code for a 32 bit process running on 64 bit Windows 8.
+struct Wow64EntryW8 {
+ // 00 b825000000 mov eax, 25h
+ // 05 64ff15c0000000 call dword ptr fs:[0C0h]
+ // 0b c22c00 ret 2Ch
+ // 0f 90 nop
+ BYTE mov_eax; // = B8
+ ULONG service_id;
+ ULONG call_fs1; // = 64 FF 15 C0
+ USHORT call_fs2; // = 00 00
+ BYTE call_fs3; // = 00
+ BYTE ret; // = C2
+ USHORT num_params;
+ BYTE nop;
+};
+
+// Service code for a 32 bit process running on 64 bit Windows 10.
+struct Wow64EntryW10 {
+ // 00 b828000000 mov eax, 28h
+ // 05 bab0d54877 mov edx, 7748D5B0h
+ // 09 ffd2 call edx
+ // 0b c22800 ret 28h
+ BYTE mov_eax; // = B8
+ ULONG service_id;
+ BYTE mov_edx; // = BA
+ ULONG mov_edx_param;
+ USHORT call_edx; // = FF D2
+ BYTE ret; // = C2
+ USHORT num_params;
+};
+
+// Make sure that relaxed patching works as expected.
+const size_t kMinServiceSize = offsetof(ServiceEntry, ret);
+static_assert(sizeof(ServiceEntryW8) >= kMinServiceSize,
+ "wrong service length");
+static_assert(sizeof(Wow64Entry) >= kMinServiceSize, "wrong service length");
+static_assert(sizeof(Wow64EntryW8) >= kMinServiceSize, "wrong service length");
+
+struct ServiceFullThunk {
+ union {
+ ServiceEntry original;
+ ServiceEntryW8 original_w8;
+ Wow64Entry wow_64;
+ Wow64EntryW8 wow_64_w8;
+ };
+ int internal_thunk; // Dummy member to the beginning of the internal thunk.
+};
+
+#pragma pack(pop)
+
+} // namespace
+
+namespace sandbox {
+
+NTSTATUS ServiceResolverThunk::Setup(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) {
+ NTSTATUS ret =
+ Init(target_module, interceptor_module, target_name, interceptor_name,
+ interceptor_entry_point, thunk_storage, storage_bytes);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ relative_jump_ = 0;
+ size_t thunk_bytes = GetThunkSize();
+ std::unique_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
+ ServiceFullThunk* thunk =
+ reinterpret_cast<ServiceFullThunk*>(thunk_buffer.get());
+
+ if (!IsFunctionAService(&thunk->original) &&
+ (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage))) {
+ return STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ ret = PerformPatch(thunk, thunk_storage);
+
+ if (storage_used)
+ *storage_used = thunk_bytes;
+
+ return ret;
+}
+
+size_t ServiceResolverThunk::GetThunkSize() const {
+ return offsetof(ServiceFullThunk, internal_thunk) + GetInternalThunkSize();
+}
+
+NTSTATUS ServiceResolverThunk::CopyThunk(const void* target_module,
+ const char* target_name,
+ BYTE* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) {
+ NTSTATUS ret = ResolveTarget(target_module, target_name, &target_);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ size_t thunk_bytes = GetThunkSize();
+ if (storage_bytes < thunk_bytes)
+ return STATUS_UNSUCCESSFUL;
+
+ ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(thunk_storage);
+
+ if (!IsFunctionAService(&thunk->original) &&
+ (!relaxed_ || !SaveOriginalFunction(&thunk->original, thunk_storage))) {
+ return STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ if (storage_used)
+ *storage_used = thunk_bytes;
+
+ return ret;
+}
+
+bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const {
+ ServiceEntry function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read)) {
+ return false;
+ }
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (kMovEax != function_code.mov_eax || kMovEdx != function_code.mov_edx ||
+ (kCallPtrEdx != function_code.call_ptr_edx &&
+ kCallEdx != function_code.call_ptr_edx) ||
+ kRet != function_code.ret) {
+ return false;
+ }
+
+ // Find the system call pointer if we don't already have it.
+ if (kCallEdx != function_code.call_ptr_edx) {
+ DWORD ki_system_call;
+ if (!::ReadProcessMemory(process_,
+ bit_cast<const void*>(function_code.stub),
+ &ki_system_call, sizeof(ki_system_call), &read)) {
+ return false;
+ }
+
+ if (sizeof(ki_system_call) != read)
+ return false;
+
+ HMODULE module_1, module_2;
+ // last check, call_stub should point to a KiXXSystemCall function on ntdll
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ bit_cast<const wchar_t*>(ki_system_call),
+ &module_1)) {
+ return false;
+ }
+
+ if (ntdll_base_) {
+ // This path is only taken when running the unit tests. We want to be
+ // able to patch a buffer in memory, so target_ is not inside ntdll.
+ module_2 = ntdll_base_;
+ } else {
+ if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ reinterpret_cast<const wchar_t*>(target_),
+ &module_2))
+ return false;
+ }
+
+ if (module_1 != module_2)
+ return false;
+ }
+
+ // Save the verified code
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+
+ return true;
+}
+
+NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk,
+ void* remote_thunk) {
+ ServiceEntry intercepted_code;
+ size_t bytes_to_write = sizeof(intercepted_code);
+ ServiceFullThunk* full_local_thunk =
+ reinterpret_cast<ServiceFullThunk*>(local_thunk);
+ ServiceFullThunk* full_remote_thunk =
+ reinterpret_cast<ServiceFullThunk*>(remote_thunk);
+
+ // patch the original code
+ memcpy(&intercepted_code, &full_local_thunk->original,
+ sizeof(intercepted_code));
+ intercepted_code.mov_eax = kMovEax;
+ intercepted_code.service_id = full_local_thunk->original.service_id;
+ intercepted_code.mov_edx = kMovEdx;
+ intercepted_code.stub = bit_cast<ULONG>(&full_remote_thunk->internal_thunk);
+ intercepted_code.call_ptr_edx = kJmpEdx;
+ bytes_to_write = kMinServiceSize;
+
+ if (relative_jump_) {
+ intercepted_code.mov_eax = kJmp32;
+ intercepted_code.service_id = relative_jump_;
+ bytes_to_write = offsetof(ServiceEntry, mov_edx);
+ }
+
+ // setup the thunk
+ SetInternalThunk(&full_local_thunk->internal_thunk, GetInternalThunkSize(),
+ remote_thunk, interceptor_);
+
+ size_t thunk_size = GetThunkSize();
+
+ // copy the local thunk buffer to the child
+ SIZE_T written;
+ if (!::WriteProcessMemory(process_, remote_thunk, local_thunk, thunk_size,
+ &written)) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ if (thunk_size != written)
+ return STATUS_UNSUCCESSFUL;
+
+ // and now change the function to intercept, on the child
+ if (ntdll_base_) {
+ // running a unit test
+ if (!::WriteProcessMemory(process_, target_, &intercepted_code,
+ bytes_to_write, &written))
+ return STATUS_UNSUCCESSFUL;
+ } else {
+ if (!WriteProtectedChildMemory(process_, target_, &intercepted_code,
+ bytes_to_write))
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+bool ServiceResolverThunk::SaveOriginalFunction(void* local_thunk,
+ void* remote_thunk) {
+ ServiceEntry function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read)) {
+ return false;
+ }
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (kJmp32 == function_code.mov_eax) {
+ // Plain old entry point patch. The relative jump address follows it.
+ ULONG relative = function_code.service_id;
+
+ // First, fix our copy of their patch.
+ relative += bit_cast<ULONG>(target_) - bit_cast<ULONG>(remote_thunk);
+
+ function_code.service_id = relative;
+
+ // And now, remember how to re-patch it.
+ ServiceFullThunk* full_thunk =
+ reinterpret_cast<ServiceFullThunk*>(remote_thunk);
+
+ const ULONG kJmp32Size = 5;
+
+ relative_jump_ = bit_cast<ULONG>(&full_thunk->internal_thunk) -
+ bit_cast<ULONG>(target_) - kJmp32Size;
+ }
+
+ // Save the verified code
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+
+ return true;
+}
+
+bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const {
+ Wow64Entry function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read)) {
+ return false;
+ }
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (kMovEax != function_code.mov_eax || kXorEcx != function_code.xor_ecx ||
+ kLeaEdx != function_code.lea_edx || kCallFs1 != function_code.call_fs1 ||
+ kCallFs2 != function_code.call_fs2 ||
+ kCallFs3 != function_code.call_fs3) {
+ return false;
+ }
+
+ if ((kAddEsp1 == function_code.add_esp1 &&
+ kAddEsp2 == function_code.add_esp2 && kRet == function_code.ret) ||
+ kRet == function_code.add_esp1) {
+ // Save the verified code
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+ return true;
+ }
+
+ return false;
+}
+
+bool Wow64W8ResolverThunk::IsFunctionAService(void* local_thunk) const {
+ Wow64EntryW8 function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read)) {
+ return false;
+ }
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (kMovEax != function_code.mov_eax || kCallFs1 != function_code.call_fs1 ||
+ kCallFs2 != function_code.call_fs2 ||
+ kCallFs3 != function_code.call_fs3 || kRet != function_code.ret) {
+ return false;
+ }
+
+ // Save the verified code
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+ return true;
+}
+
+bool Win8ResolverThunk::IsFunctionAService(void* local_thunk) const {
+ ServiceEntryW8 function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read)) {
+ return false;
+ }
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (kMovEax != function_code.mov_eax || kCallEip != function_code.call_eip ||
+ function_code.call_offset != 3 || kRet != function_code.ret_p ||
+ kMovEdxEsp != function_code.mov_edx_esp ||
+ kSysenter != function_code.sysenter || kRet2 != function_code.ret) {
+ return false;
+ }
+
+ // Save the verified code
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+
+ return true;
+}
+
+bool Wow64W10ResolverThunk::IsFunctionAService(void* local_thunk) const {
+ Wow64EntryW10 function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read)) {
+ return false;
+ }
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (kMovEax != function_code.mov_eax || kMovEdx != function_code.mov_edx ||
+ kCallEdx != function_code.call_edx || kRet != function_code.ret) {
+ return false;
+ }
+
+ // Save the verified code
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/service_resolver_64.cc b/security/sandbox/chromium/sandbox/win/src/service_resolver_64.cc
new file mode 100644
index 0000000000..f692d0ea4f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/service_resolver_64.cc
@@ -0,0 +1,290 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/service_resolver.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+#if defined(_M_X64)
+#pragma pack(push, 1)
+
+const ULONG kMmovR10EcxMovEax = 0xB8D18B4C;
+const USHORT kSyscall = 0x050F;
+const BYTE kRetNp = 0xC3;
+const ULONG64 kMov1 = 0x54894808244C8948;
+const ULONG64 kMov2 = 0x4C182444894C1024;
+const ULONG kMov3 = 0x20244C89;
+const USHORT kTestByte = 0x04F6;
+const BYTE kPtr = 0x25;
+const BYTE kRet = 0xC3;
+const USHORT kJne = 0x0375;
+
+// Service code for 64 bit systems.
+struct ServiceEntry {
+ // This struct contains roughly the following code:
+ // 00 mov r10,rcx
+ // 03 mov eax,52h
+ // 08 syscall
+ // 0a ret
+ // 0b xchg ax,ax
+ // 0e xchg ax,ax
+
+ ULONG mov_r10_rcx_mov_eax; // = 4C 8B D1 B8
+ ULONG service_id;
+ USHORT syscall; // = 0F 05
+ BYTE ret; // = C3
+ BYTE pad; // = 66
+ USHORT xchg_ax_ax1; // = 66 90
+ USHORT xchg_ax_ax2; // = 66 90
+};
+
+// Service code for 64 bit Windows 8.
+struct ServiceEntryW8 {
+ // This struct contains the following code:
+ // 00 48894c2408 mov [rsp+8], rcx
+ // 05 4889542410 mov [rsp+10], rdx
+ // 0a 4c89442418 mov [rsp+18], r8
+ // 0f 4c894c2420 mov [rsp+20], r9
+ // 14 4c8bd1 mov r10,rcx
+ // 17 b825000000 mov eax,25h
+ // 1c 0f05 syscall
+ // 1e c3 ret
+ // 1f 90 nop
+
+ ULONG64 mov_1; // = 48 89 4C 24 08 48 89 54
+ ULONG64 mov_2; // = 24 10 4C 89 44 24 18 4C
+ ULONG mov_3; // = 89 4C 24 20
+ ULONG mov_r10_rcx_mov_eax; // = 4C 8B D1 B8
+ ULONG service_id;
+ USHORT syscall; // = 0F 05
+ BYTE ret; // = C3
+ BYTE nop; // = 90
+};
+
+// Service code for 64 bit systems with int 2e fallback.
+struct ServiceEntryWithInt2E {
+ // This struct contains roughly the following code:
+ // 00 4c8bd1 mov r10,rcx
+ // 03 b855000000 mov eax,52h
+ // 08 f604250803fe7f01 test byte ptr SharedUserData!308, 1
+ // 10 7503 jne [over syscall]
+ // 12 0f05 syscall
+ // 14 c3 ret
+ // 15 cd2e int 2e
+ // 17 c3 ret
+
+ ULONG mov_r10_rcx_mov_eax; // = 4C 8B D1 B8
+ ULONG service_id;
+ USHORT test_byte; // = F6 04
+ BYTE ptr; // = 25
+ ULONG user_shared_data_ptr;
+ BYTE one; // = 01
+ USHORT jne_over_syscall; // = 75 03
+ USHORT syscall; // = 0F 05
+ BYTE ret; // = C3
+ USHORT int2e; // = CD 2E
+ BYTE ret2; // = C3
+};
+
+// We don't have an internal thunk for x64.
+struct ServiceFullThunk {
+ union {
+ ServiceEntry original;
+ ServiceEntryW8 original_w8;
+ ServiceEntryWithInt2E original_int2e_fallback;
+ };
+};
+
+#pragma pack(pop)
+
+bool IsService(const void* source) {
+ const ServiceEntry* service = reinterpret_cast<const ServiceEntry*>(source);
+
+ return (kMmovR10EcxMovEax == service->mov_r10_rcx_mov_eax &&
+ kSyscall == service->syscall && kRetNp == service->ret);
+}
+
+bool IsServiceW8(const void* source) {
+ const ServiceEntryW8* service =
+ reinterpret_cast<const ServiceEntryW8*>(source);
+
+ return (kMmovR10EcxMovEax == service->mov_r10_rcx_mov_eax &&
+ kMov1 == service->mov_1 && kMov2 == service->mov_2 &&
+ kMov3 == service->mov_3);
+}
+
+bool IsServiceWithInt2E(const void* source) {
+ const ServiceEntryWithInt2E* service =
+ reinterpret_cast<const ServiceEntryWithInt2E*>(source);
+
+ return (kMmovR10EcxMovEax == service->mov_r10_rcx_mov_eax &&
+ kTestByte == service->test_byte && kPtr == service->ptr &&
+ kJne == service->jne_over_syscall && kSyscall == service->syscall &&
+ kRet == service->ret && kRet == service->ret2);
+}
+
+bool IsAnyService(const void* source) {
+ return IsService(source) || IsServiceW8(source) || IsServiceWithInt2E(source);
+}
+
+#elif defined(_M_ARM64)
+#pragma pack(push, 4)
+
+const ULONG kSvc = 0xD4000001;
+const ULONG kRetNp = 0xD65F03C0;
+const ULONG kServiceIdMask = 0x001FFFE0;
+
+struct ServiceEntry {
+ ULONG svc;
+ ULONG ret;
+ ULONG64 unused;
+};
+
+struct ServiceFullThunk {
+ ServiceEntry original;
+};
+
+#pragma pack(pop)
+
+bool IsService(const void* source) {
+ const ServiceEntry* service = reinterpret_cast<const ServiceEntry*>(source);
+
+ return (kSvc == (service->svc & ~kServiceIdMask) && kRetNp == service->ret &&
+ 0 == service->unused);
+}
+
+bool IsAnyService(const void* source) {
+ return IsService(source);
+}
+
+#else
+#error "Unsupported Windows 64-bit Arch"
+#endif
+
+} // namespace
+
+namespace sandbox {
+
+NTSTATUS ServiceResolverThunk::Setup(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) {
+ NTSTATUS ret =
+ Init(target_module, interceptor_module, target_name, interceptor_name,
+ interceptor_entry_point, thunk_storage, storage_bytes);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ size_t thunk_bytes = GetThunkSize();
+ std::unique_ptr<char[]> thunk_buffer(new char[thunk_bytes]);
+ ServiceFullThunk* thunk =
+ reinterpret_cast<ServiceFullThunk*>(thunk_buffer.get());
+
+ if (!IsFunctionAService(&thunk->original))
+ return STATUS_OBJECT_NAME_COLLISION;
+
+ ret = PerformPatch(thunk, thunk_storage);
+
+ if (storage_used)
+ *storage_used = thunk_bytes;
+
+ return ret;
+}
+
+size_t ServiceResolverThunk::GetThunkSize() const {
+ return sizeof(ServiceFullThunk);
+}
+
+NTSTATUS ServiceResolverThunk::CopyThunk(const void* target_module,
+ const char* target_name,
+ BYTE* thunk_storage,
+ size_t storage_bytes,
+ size_t* storage_used) {
+ NTSTATUS ret = ResolveTarget(target_module, target_name, &target_);
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ size_t thunk_bytes = GetThunkSize();
+ if (storage_bytes < thunk_bytes)
+ return STATUS_UNSUCCESSFUL;
+
+ ServiceFullThunk* thunk = reinterpret_cast<ServiceFullThunk*>(thunk_storage);
+
+ if (!IsFunctionAService(&thunk->original))
+ return STATUS_OBJECT_NAME_COLLISION;
+
+ if (storage_used)
+ *storage_used = thunk_bytes;
+
+ return ret;
+}
+
+bool ServiceResolverThunk::IsFunctionAService(void* local_thunk) const {
+ ServiceFullThunk function_code;
+ SIZE_T read;
+ if (!::ReadProcessMemory(process_, target_, &function_code,
+ sizeof(function_code), &read))
+ return false;
+
+ if (sizeof(function_code) != read)
+ return false;
+
+ if (!IsAnyService(&function_code))
+ return false;
+
+ // Save the verified code.
+ memcpy(local_thunk, &function_code, sizeof(function_code));
+
+ return true;
+}
+
+NTSTATUS ServiceResolverThunk::PerformPatch(void* local_thunk,
+ void* remote_thunk) {
+ // Patch the original code.
+ ServiceEntry local_service;
+ DCHECK_NT(GetInternalThunkSize() <= sizeof(local_service));
+ if (!SetInternalThunk(&local_service, sizeof(local_service), nullptr,
+ interceptor_))
+ return STATUS_UNSUCCESSFUL;
+
+ // Copy the local thunk buffer to the child.
+ SIZE_T actual;
+ if (!::WriteProcessMemory(process_, remote_thunk, local_thunk,
+ sizeof(ServiceFullThunk), &actual))
+ return STATUS_UNSUCCESSFUL;
+
+ if (sizeof(ServiceFullThunk) != actual)
+ return STATUS_UNSUCCESSFUL;
+
+ // And now change the function to intercept, on the child.
+ if (ntdll_base_) {
+ // Running a unit test.
+ if (!::WriteProcessMemory(process_, target_, &local_service,
+ sizeof(local_service), &actual))
+ return STATUS_UNSUCCESSFUL;
+ } else {
+ if (!WriteProtectedChildMemory(process_, target_, &local_service,
+ sizeof(local_service)))
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+bool Wow64ResolverThunk::IsFunctionAService(void* local_thunk) const {
+ NOTREACHED_NT();
+ return false;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/service_resolver_unittest.cc b/security/sandbox/chromium/sandbox/win/src/service_resolver_unittest.cc
new file mode 100644
index 0000000000..63ea26dcbf
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/service_resolver_unittest.cc
@@ -0,0 +1,278 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for ServiceResolverThunk.
+
+#include "sandbox/win/src/service_resolver.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/bit_cast.h"
+#include "base/macros.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/resolver.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ResolverThunkTest {
+ public:
+ virtual ~ResolverThunkTest() {}
+
+ virtual sandbox::ServiceResolverThunk* resolver() = 0;
+
+ // Sets the interception target to the desired address.
+ void set_target(void* target) { fake_target_ = target; }
+
+ protected:
+ // Holds the address of the fake target.
+ void* fake_target_;
+};
+
+// This is the concrete resolver used to perform service-call type functions
+// inside ntdll.dll.
+template <typename T>
+class ResolverThunkTestImpl : public T, public ResolverThunkTest {
+ public:
+ // The service resolver needs a child process to write to.
+ explicit ResolverThunkTestImpl(bool relaxed)
+ : T(::GetCurrentProcess(), relaxed) {}
+
+ sandbox::ServiceResolverThunk* resolver() { return this; }
+
+ protected:
+ // Overrides Resolver::Init
+ virtual NTSTATUS Init(const void* target_module,
+ const void* interceptor_module,
+ const char* target_name,
+ const char* interceptor_name,
+ const void* interceptor_entry_point,
+ void* thunk_storage,
+ size_t storage_bytes) {
+ NTSTATUS ret = STATUS_SUCCESS;
+ ret = T::Init(target_module, interceptor_module, target_name,
+ interceptor_name, interceptor_entry_point, thunk_storage,
+ storage_bytes);
+ EXPECT_EQ(STATUS_SUCCESS, ret);
+
+ this->target_ = fake_target_;
+
+ return ret;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ResolverThunkTestImpl);
+};
+
+typedef ResolverThunkTestImpl<sandbox::ServiceResolverThunk> WinXpResolverTest;
+
+#if !defined(_WIN64)
+typedef ResolverThunkTestImpl<sandbox::Win8ResolverThunk> Win8ResolverTest;
+typedef ResolverThunkTestImpl<sandbox::Wow64ResolverThunk> Wow64ResolverTest;
+typedef ResolverThunkTestImpl<sandbox::Wow64W8ResolverThunk>
+ Wow64W8ResolverTest;
+typedef ResolverThunkTestImpl<sandbox::Wow64W10ResolverThunk>
+ Wow64W10ResolverTest;
+#endif
+
+const BYTE kJump32 = 0xE9;
+
+void CheckJump(void* source, void* target) {
+#pragma pack(push)
+#pragma pack(1)
+ struct Code {
+ BYTE jump;
+ ULONG delta;
+ };
+#pragma pack(pop)
+
+#if defined(_WIN64)
+ FAIL() << "Running 32-bit codepath";
+#else
+ Code* patched = reinterpret_cast<Code*>(source);
+ EXPECT_EQ(kJump32, patched->jump);
+
+ ULONG source_addr = bit_cast<ULONG>(source);
+ ULONG target_addr = bit_cast<ULONG>(target);
+ EXPECT_EQ(target_addr + 19 - source_addr, patched->delta);
+#endif
+}
+
+NTSTATUS PatchNtdllWithResolver(const char* function,
+ bool relaxed,
+ ResolverThunkTest* thunk_test) {
+ HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
+ EXPECT_TRUE(ntdll_base);
+
+ void* target =
+ reinterpret_cast<void*>(::GetProcAddress(ntdll_base, function));
+ EXPECT_TRUE(target);
+ if (!target)
+ return STATUS_UNSUCCESSFUL;
+
+ BYTE service[50];
+ memcpy(service, target, sizeof(service));
+
+ thunk_test->set_target(service);
+
+ sandbox::ServiceResolverThunk* resolver = thunk_test->resolver();
+ // Any pointer will do as an interception_entry_point
+ void* function_entry = resolver;
+ size_t thunk_size = resolver->GetThunkSize();
+ std::unique_ptr<char[]> thunk(new char[thunk_size]);
+ size_t used;
+
+ resolver->AllowLocalPatches();
+
+ NTSTATUS ret =
+ resolver->Setup(ntdll_base, nullptr, function, nullptr, function_entry,
+ thunk.get(), thunk_size, &used);
+ if (NT_SUCCESS(ret)) {
+ EXPECT_EQ(thunk_size, used);
+ EXPECT_NE(0, memcmp(service, target, sizeof(service)));
+ EXPECT_NE(kJump32, service[0]);
+
+ if (relaxed) {
+ // It's already patched, let's patch again, and simulate a direct patch.
+ service[0] = kJump32;
+ ret = resolver->Setup(ntdll_base, nullptr, function, nullptr,
+ function_entry, thunk.get(), thunk_size, &used);
+ CheckJump(service, thunk.get());
+ }
+ }
+
+ return ret;
+}
+
+std::unique_ptr<ResolverThunkTest> GetTestResolver(bool relaxed) {
+#if defined(_WIN64)
+ return std::make_unique<WinXpResolverTest>(relaxed);
+#else
+ base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
+ if (os_info->wow64_status() == base::win::OSInfo::WOW64_ENABLED) {
+ if (os_info->version() >= base::win::Version::WIN10)
+ return std::make_unique<Wow64W10ResolverTest>(relaxed);
+ if (os_info->version() >= base::win::Version::WIN8)
+ return std::make_unique<Wow64W8ResolverTest>(relaxed);
+ return std::make_unique<Wow64ResolverTest>(relaxed);
+ }
+
+ if (os_info->version() >= base::win::Version::WIN8)
+ return std::make_unique<Win8ResolverTest>(relaxed);
+
+ return std::make_unique<WinXpResolverTest>(relaxed);
+#endif
+}
+
+NTSTATUS PatchNtdll(const char* function, bool relaxed) {
+ std::unique_ptr<ResolverThunkTest> thunk_test = GetTestResolver(relaxed);
+ return PatchNtdllWithResolver(function, relaxed, thunk_test.get());
+}
+
+TEST(ServiceResolverTest, PatchesServices) {
+ NTSTATUS ret = PatchNtdll("NtClose", false);
+ EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
+
+ ret = PatchNtdll("NtCreateFile", false);
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtCreateFile, last error: " << ::GetLastError();
+
+ ret = PatchNtdll("NtCreateMutant", false);
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtCreateMutant, last error: " << ::GetLastError();
+
+ ret = PatchNtdll("NtMapViewOfSection", false);
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtMapViewOfSection, last error: " << ::GetLastError();
+}
+
+TEST(ServiceResolverTest, FailsIfNotService) {
+#if !defined(_WIN64)
+ EXPECT_NE(STATUS_SUCCESS, PatchNtdll("RtlUlongByteSwap", false));
+#endif
+
+ EXPECT_NE(STATUS_SUCCESS, PatchNtdll("LdrLoadDll", false));
+}
+
+TEST(ServiceResolverTest, PatchesPatchedServices) {
+// We don't support "relaxed mode" for Win64 apps.
+#if !defined(_WIN64)
+ NTSTATUS ret = PatchNtdll("NtClose", true);
+ EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
+
+ ret = PatchNtdll("NtCreateFile", true);
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtCreateFile, last error: " << ::GetLastError();
+
+ ret = PatchNtdll("NtCreateMutant", true);
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtCreateMutant, last error: " << ::GetLastError();
+
+ ret = PatchNtdll("NtMapViewOfSection", true);
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtMapViewOfSection, last error: " << ::GetLastError();
+#endif
+}
+
+TEST(ServiceResolverTest, MultiplePatchedServices) {
+// We don't support "relaxed mode" for Win64 apps.
+#if !defined(_WIN64)
+ std::unique_ptr<ResolverThunkTest> thunk_test = GetTestResolver(true);
+ NTSTATUS ret = PatchNtdllWithResolver("NtClose", true, thunk_test.get());
+ EXPECT_EQ(STATUS_SUCCESS, ret) << "NtClose, last error: " << ::GetLastError();
+
+ ret = PatchNtdllWithResolver("NtCreateFile", true, thunk_test.get());
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtCreateFile, last error: " << ::GetLastError();
+
+ ret = PatchNtdllWithResolver("NtCreateMutant", true, thunk_test.get());
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtCreateMutant, last error: " << ::GetLastError();
+
+ ret = PatchNtdllWithResolver("NtMapViewOfSection", true, thunk_test.get());
+ EXPECT_EQ(STATUS_SUCCESS, ret)
+ << "NtMapViewOfSection, last error: " << ::GetLastError();
+#endif
+}
+
+TEST(ServiceResolverTest, LocalPatchesAllowed) {
+ std::unique_ptr<ResolverThunkTest> thunk_test = GetTestResolver(true);
+
+ HMODULE ntdll_base = ::GetModuleHandle(L"ntdll.dll");
+ ASSERT_TRUE(ntdll_base);
+
+ const char kFunctionName[] = "NtClose";
+
+ void* target =
+ reinterpret_cast<void*>(::GetProcAddress(ntdll_base, kFunctionName));
+ ASSERT_TRUE(target);
+
+ BYTE service[50];
+ memcpy(service, target, sizeof(service));
+ thunk_test->set_target(service);
+
+ sandbox::ServiceResolverThunk* resolver = thunk_test->resolver();
+ // Any pointer will do as an interception_entry_point
+ void* function_entry = resolver;
+ size_t thunk_size = resolver->GetThunkSize();
+ std::unique_ptr<char[]> thunk(new char[thunk_size]);
+ size_t used;
+
+ NTSTATUS ret = STATUS_UNSUCCESSFUL;
+
+ // First try patching without having allowed local patches.
+ ret = resolver->Setup(ntdll_base, nullptr, kFunctionName, nullptr,
+ function_entry, thunk.get(), thunk_size, &used);
+ EXPECT_FALSE(NT_SUCCESS(ret));
+
+ // Now allow local patches and check that things work.
+ resolver->AllowLocalPatches();
+ ret = resolver->Setup(ntdll_base, nullptr, kFunctionName, nullptr,
+ function_entry, thunk.get(), thunk_size, &used);
+ EXPECT_EQ(STATUS_SUCCESS, ret);
+}
+
+} // namespace
diff --git a/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.cc b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.cc
new file mode 100644
index 0000000000..3ddea76350
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_types.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+namespace {
+
+DWORD SignalObjectAndWaitWrapper(HANDLE object_to_signal,
+ HANDLE object_to_wait_on,
+ DWORD millis,
+ BOOL alertable) {
+ // Not running in a sandboxed process so can call directly.
+ if (!g_nt.SignalAndWaitForSingleObject)
+ return SignalObjectAndWait(object_to_signal, object_to_wait_on, millis,
+ alertable);
+ // Don't support alertable.
+ CHECK_NT(!alertable);
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = millis * -10000LL;
+ NTSTATUS status = g_nt.SignalAndWaitForSingleObject(
+ object_to_signal, object_to_wait_on, alertable,
+ millis == INFINITE ? nullptr : &timeout);
+ if (!NT_SUCCESS(status))
+ return WAIT_FAILED;
+ return status;
+}
+
+DWORD WaitForSingleObjectWrapper(HANDLE handle, DWORD millis) {
+ // Not running in a sandboxed process so can call directly.
+ if (!g_nt.WaitForSingleObject)
+ return WaitForSingleObject(handle, millis);
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = millis * -10000LL;
+ NTSTATUS status = g_nt.WaitForSingleObject(
+ handle, FALSE, millis == INFINITE ? nullptr : &timeout);
+ if (!NT_SUCCESS(status))
+ return WAIT_FAILED;
+ return status;
+}
+
+} // namespace
+
+// Get the base of the data buffer of the channel; this is where the input
+// parameters get serialized. Since they get serialized directly into the
+// channel we avoid one copy.
+void* SharedMemIPCClient::GetBuffer() {
+ bool failure = false;
+ size_t ix = LockFreeChannel(&failure);
+ if (failure)
+ return nullptr;
+ return reinterpret_cast<char*>(control_) +
+ control_->channels[ix].channel_base;
+}
+
+// If we need to cancel an IPC before issuing DoCall
+// our client should call FreeBuffer with the same pointer
+// returned by GetBuffer.
+void SharedMemIPCClient::FreeBuffer(void* buffer) {
+ size_t num = ChannelIndexFromBuffer(buffer);
+ ChannelControl* channel = control_->channels;
+ LONG result = ::InterlockedExchange(&channel[num].state, kFreeChannel);
+ DCHECK_NE(kFreeChannel, static_cast<ChannelState>(result));
+}
+
+// The constructor simply casts the shared memory to the internal
+// structures. This is a cheap step that is why this IPC object can
+// and should be constructed per call.
+SharedMemIPCClient::SharedMemIPCClient(void* shared_mem)
+ : control_(reinterpret_cast<IPCControl*>(shared_mem)) {
+ first_base_ =
+ reinterpret_cast<char*>(shared_mem) + control_->channels[0].channel_base;
+ // There must be at least one channel.
+ DCHECK(0 != control_->channels_count);
+}
+
+// Do the IPC. At this point the channel should have already been
+// filled with the serialized input parameters.
+// We follow the pattern explained in the header file.
+ResultCode SharedMemIPCClient::DoCall(CrossCallParams* params,
+ CrossCallReturn* answer) {
+ if (!control_->server_alive)
+ return SBOX_ERROR_CHANNEL_ERROR;
+
+ size_t num = ChannelIndexFromBuffer(params->GetBuffer());
+ ChannelControl* channel = control_->channels;
+ // Note that the IPC tag goes outside the buffer as well inside
+ // the buffer. This should enable the server to prioritize based on
+ // IPC tags without having to de-serialize the entire message.
+ channel[num].ipc_tag = params->GetTag();
+
+ // Wait for the server to service this IPC call. After kIPCWaitTimeOut1
+ // we check if the server_alive mutex was abandoned which will indicate
+ // that the server has died.
+
+ // While the atomic signaling and waiting is not a requirement, it
+ // is nice because we save a trip to kernel.
+ DWORD wait = SignalObjectAndWaitWrapper(channel[num].ping_event,
+ channel[num].pong_event,
+ kIPCWaitTimeOut1, false);
+ if (WAIT_TIMEOUT == wait) {
+ // The server is taking too long. Enter a loop were we check if the
+ // server_alive mutex has been abandoned which would signal a server crash
+ // or else we keep waiting for a response.
+ while (true) {
+ wait = WaitForSingleObjectWrapper(control_->server_alive, 0);
+ if (WAIT_TIMEOUT == wait) {
+ // Server seems still alive. We already signaled so here we just wait.
+ wait = WaitForSingleObjectWrapper(channel[num].pong_event,
+ kIPCWaitTimeOut1);
+ if (WAIT_OBJECT_0 == wait) {
+ // The server took a long time but responded.
+ break;
+ } else if (WAIT_TIMEOUT == wait) {
+ continue;
+ } else {
+ return SBOX_ERROR_CHANNEL_ERROR;
+ }
+ } else {
+ // The server has crashed and windows has signaled the mutex as
+ // abandoned.
+ ::InterlockedExchange(&channel[num].state, kAbandonedChannel);
+ control_->server_alive = 0;
+ return SBOX_ERROR_CHANNEL_ERROR;
+ }
+ }
+ } else if (WAIT_OBJECT_0 != wait) {
+ // Probably the server crashed before the kIPCWaitTimeOut1 occurred.
+ return SBOX_ERROR_CHANNEL_ERROR;
+ }
+
+ // The server has returned an answer, copy it and free the channel.
+ memcpy_wrapper(answer, params->GetCallReturn(), sizeof(CrossCallReturn));
+
+ // Return the IPC state It can indicate that while the IPC has
+ // completed some error in the Broker has caused to not return valid
+ // results.
+ return answer->call_outcome;
+}
+
+// Locking a channel is a simple as looping over all the channels
+// looking for one that is has state = kFreeChannel and atomically
+// swapping it to kBusyChannel.
+// If there is no free channel, then we must back off so some other
+// thread makes progress and frees a channel. To back off we sleep.
+size_t SharedMemIPCClient::LockFreeChannel(bool* severe_failure) {
+ if (0 == control_->channels_count) {
+ *severe_failure = true;
+ return 0;
+ }
+ ChannelControl* channel = control_->channels;
+ do {
+ for (size_t ix = 0; ix != control_->channels_count; ++ix) {
+ if (kFreeChannel == ::InterlockedCompareExchange(
+ &channel[ix].state, kBusyChannel, kFreeChannel)) {
+ *severe_failure = false;
+ return ix;
+ }
+ }
+ // We did not find any available channel, maybe the server is dead.
+ DWORD wait =
+ WaitForSingleObjectWrapper(control_->server_alive, kIPCWaitTimeOut2);
+ if (WAIT_TIMEOUT != wait) {
+ // The server is dead and we outlive it enough to get in trouble.
+ *severe_failure = true;
+ return 0;
+ }
+ } while (true);
+}
+
+// Find out which channel we are from the pointer returned by GetBuffer.
+size_t SharedMemIPCClient::ChannelIndexFromBuffer(const void* buffer) {
+ ptrdiff_t d = reinterpret_cast<const char*>(buffer) - first_base_;
+ size_t num = d / kIPCChannelSize;
+ DCHECK_LT(num, control_->channels_count);
+ return (num);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.h b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.h
new file mode 100644
index 0000000000..73f739dece
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_client.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__
+#define SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox.h"
+
+// IPC transport implementation that uses shared memory.
+// This is the client side
+//
+// The shared memory is divided on blocks called channels, and potentially
+// it can perform as many concurrent IPC calls as channels. The IPC over
+// each channel is strictly synchronous for the client.
+//
+// Each channel as a channel control section associated with. Each control
+// section has two kernel events (known as ping and pong) and a integer
+// variable that maintains a state
+//
+// this is the state diagram of a channel:
+//
+// locked in service
+// kFreeChannel---------->BusyChannel-------------->kAckChannel
+// ^ |
+// |_________________________________________________|
+// answer ready
+//
+// The protocol is as follows:
+// 1) client finds a free channel: state = kFreeChannel
+// 2) does an atomic compare-and-swap, now state = BusyChannel
+// 3) client writes the data into the channel buffer
+// 4) client signals the ping event and waits (blocks) on the pong event
+// 5) eventually the server signals the pong event
+// 6) the client awakes and reads the answer from the same channel
+// 7) the client updates its InOut parameters with the new data from the
+// shared memory section.
+// 8) the client atomically sets the state = kFreeChannel
+//
+// In the shared memory the layout is as follows:
+//
+// [ channel count ]
+// [ channel control 0]
+// [ channel control 1]
+// [ channel control N]
+// [ channel buffer 0 ] 1024 bytes
+// [ channel buffer 1 ] 1024 bytes
+// [ channel buffer N ] 1024 bytes
+//
+// By default each channel buffer is 1024 bytes
+namespace sandbox {
+
+// the possible channel states as described above
+enum ChannelState {
+ // channel is free
+ kFreeChannel = 1,
+ // IPC in progress client side
+ kBusyChannel,
+ // IPC in progress server side
+ kAckChannel,
+ // not used right now
+ kReadyChannel,
+ // IPC abandoned by client side
+ kAbandonedChannel
+};
+
+// The next two constants control the time outs for the IPC.
+const DWORD kIPCWaitTimeOut1 = 1000; // Milliseconds.
+const DWORD kIPCWaitTimeOut2 = 50; // Milliseconds.
+
+// the channel control structure
+struct ChannelControl {
+ // points to be beginning of the channel buffer, where data goes
+ size_t channel_base;
+ // maintains the state from the ChannelState enumeration
+ volatile LONG state;
+ // the ping event is signaled by the client when the IPC data is ready on
+ // the buffer
+ HANDLE ping_event;
+ // the client waits on the pong event for the IPC answer back
+ HANDLE pong_event;
+ // the IPC unique identifier
+ IpcTag ipc_tag;
+};
+
+struct IPCControl {
+ // total number of channels available, some might be busy at a given time
+ size_t channels_count;
+ // handle to a shared mutex to detect when the server is dead
+ HANDLE server_alive;
+ // array of channel control structures
+ ChannelControl channels[1];
+};
+
+// the actual shared memory IPC implementation class. This object is designed
+// to be lightweight so it can be constructed on-site (at the calling place)
+// wherever an IPC call is needed.
+class SharedMemIPCClient {
+ public:
+ // Creates the IPC client.
+ // as parameter it takes the base address of the shared memory
+ explicit SharedMemIPCClient(void* shared_mem);
+
+ // locks a free channel and returns the channel buffer memory base. This call
+ // blocks until there is a free channel
+ void* GetBuffer();
+
+ // releases the lock on the channel, for other to use. call this if you have
+ // called GetBuffer and you want to abort but have not called yet DoCall()
+ void FreeBuffer(void* buffer);
+
+ // Performs the actual IPC call.
+ // params: The blob of packed input parameters.
+ // answer: upon IPC completion, it contains the server answer to the IPC.
+ // If the return value is not SBOX_ERROR_CHANNEL_ERROR, the caller has to free
+ // the channel.
+ // returns ALL_OK if the IPC mechanism successfully delivered. You still need
+ // to check on the answer structure to see the actual IPC result.
+ ResultCode DoCall(CrossCallParams* params, CrossCallReturn* answer);
+
+ private:
+ // Returns the index of the first free channel. It sets 'severe_failure'
+ // to true if there is an unrecoverable error that does not allow to
+ // find a channel.
+ size_t LockFreeChannel(bool* severe_failure);
+ // Return the channel index given the address of the buffer.
+ size_t ChannelIndexFromBuffer(const void* buffer);
+ IPCControl* control_;
+ // point to the first channel base
+ char* first_base_;
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SHAREDMEM_IPC_CLIENT_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.cc b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.cc
new file mode 100644
index 0000000000..181c603f80
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/ipc_args.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+
+namespace {
+// This handle must not be closed.
+volatile HANDLE g_alive_mutex = nullptr;
+} // namespace
+
+namespace sandbox {
+
+/* static */ bool SharedMemIPCServer::CreateBrokerAliveMutex() {
+ DCHECK(!g_alive_mutex);
+ // We create a initially owned mutex. If the server dies unexpectedly,
+ // the thread that owns it will fail to release the lock and windows will
+ // report to the target (when it tries to acquire it) that the wait was
+ // abandoned. Note: We purposely leak the local handle because we want it to
+ // be closed by Windows itself so it is properly marked as abandoned if the
+ // server dies.
+ g_alive_mutex = ::CreateMutexW(nullptr, true, nullptr);
+ return static_cast<bool>(g_alive_mutex);
+}
+
+SharedMemIPCServer::ServerControl::ServerControl() {}
+
+SharedMemIPCServer::ServerControl::~ServerControl() {}
+
+SharedMemIPCServer::SharedMemIPCServer(HANDLE target_process,
+ DWORD target_process_id,
+ ThreadProvider* thread_provider,
+ Dispatcher* dispatcher)
+ : client_control_(nullptr),
+ thread_provider_(thread_provider),
+ target_process_(target_process),
+ target_process_id_(target_process_id),
+ call_dispatcher_(dispatcher) {
+ DCHECK(g_alive_mutex);
+}
+
+SharedMemIPCServer::~SharedMemIPCServer() {
+ // Free the wait handles associated with the thread pool.
+ if (!thread_provider_->UnRegisterWaits(this)) {
+ // Better to leak than to crash.
+ return;
+ }
+ server_contexts_.clear();
+
+ if (client_control_)
+ ::UnmapViewOfFile(client_control_);
+}
+
+bool SharedMemIPCServer::Init(void* shared_mem,
+ uint32_t shared_size,
+ uint32_t channel_size) {
+ // The shared memory needs to be at least as big as a channel.
+ if (shared_size < channel_size) {
+ return false;
+ }
+ // The channel size should be aligned.
+ if (0 != (channel_size % 32)) {
+ return false;
+ }
+
+ // Calculate how many channels we can fit in the shared memory.
+ shared_size -= offsetof(IPCControl, channels);
+ size_t channel_count = shared_size / (sizeof(ChannelControl) + channel_size);
+
+ // If we cannot fit even one channel we bail out.
+ if (0 == channel_count) {
+ return false;
+ }
+ // Calculate the start of the first channel.
+ size_t base_start =
+ (sizeof(ChannelControl) * channel_count) + offsetof(IPCControl, channels);
+
+ client_control_ = reinterpret_cast<IPCControl*>(shared_mem);
+ client_control_->channels_count = 0;
+
+ // This is the initialization that we do per-channel. Basically:
+ // 1) make two events (ping & pong)
+ // 2) create handles to the events for the client and the server.
+ // 3) initialize the channel (client_context) with the state.
+ // 4) initialize the server side of the channel (service_context).
+ // 5) call the thread provider RegisterWait to register the ping events.
+ for (size_t ix = 0; ix != channel_count; ++ix) {
+ ChannelControl* client_context = &client_control_->channels[ix];
+ ServerControl* service_context = new ServerControl;
+ server_contexts_.push_back(base::WrapUnique(service_context));
+
+ if (!MakeEvents(&service_context->ping_event, &service_context->pong_event,
+ &client_context->ping_event, &client_context->pong_event)) {
+ return false;
+ }
+
+ client_context->channel_base = base_start;
+ client_context->state = kFreeChannel;
+
+ // Note that some of these values are available as members of this object
+ // but we put them again into the service_context because we will be called
+ // on a static method (ThreadPingEventReady). In particular, target_process_
+ // is a raw handle that is not owned by this object (it's owned by the
+ // owner of this object), and we are storing it in multiple places.
+ service_context->shared_base = reinterpret_cast<char*>(shared_mem);
+ service_context->channel_size = channel_size;
+ service_context->channel = client_context;
+ service_context->channel_buffer =
+ service_context->shared_base + client_context->channel_base;
+ service_context->dispatcher = call_dispatcher_;
+ service_context->target_info.process = target_process_;
+ service_context->target_info.process_id = target_process_id_;
+ // Advance to the next channel.
+ base_start += channel_size;
+ // Register the ping event with the threadpool.
+ thread_provider_->RegisterWait(this, service_context->ping_event.Get(),
+ ThreadPingEventReady, service_context);
+ }
+ if (!::DuplicateHandle(::GetCurrentProcess(), g_alive_mutex, target_process_,
+ &client_control_->server_alive,
+ SYNCHRONIZE | EVENT_MODIFY_STATE, false, 0)) {
+ return false;
+ }
+ // This last setting indicates to the client all is setup.
+ client_control_->channels_count = channel_count;
+ return true;
+}
+
+bool SharedMemIPCServer::InvokeCallback(const ServerControl* service_context,
+ void* ipc_buffer,
+ CrossCallReturn* call_result) {
+ // Set the default error code;
+ SetCallError(SBOX_ERROR_INVALID_IPC, call_result);
+ uint32_t output_size = 0;
+ // Parse, verify and copy the message. The handler operates on a copy
+ // of the message so the client cannot play dirty tricks by changing the
+ // data in the channel while the IPC is being processed.
+ std::unique_ptr<CrossCallParamsEx> params(CrossCallParamsEx::CreateFromBuffer(
+ ipc_buffer, service_context->channel_size, &output_size));
+ if (!params.get())
+ return false;
+
+ IpcTag tag = params->GetTag();
+ static_assert(0 == INVALID_TYPE, "incorrect type enum");
+ IPCParams ipc_params = {tag};
+
+ void* args[kMaxIpcParams];
+ if (!GetArgs(params.get(), &ipc_params, args))
+ return false;
+
+ IPCInfo ipc_info = {tag};
+ ipc_info.client_info = &service_context->target_info;
+ Dispatcher* dispatcher = service_context->dispatcher;
+ DCHECK(dispatcher);
+ bool error = true;
+ Dispatcher* handler = nullptr;
+
+ Dispatcher::CallbackGeneric callback_generic;
+ handler = dispatcher->OnMessageReady(&ipc_params, &callback_generic);
+ if (handler) {
+ switch (params->GetParamsCount()) {
+ case 0: {
+ // Ask the IPC dispatcher if it can service this IPC.
+ Dispatcher::Callback0 callback =
+ reinterpret_cast<Dispatcher::Callback0>(callback_generic);
+ if (!(handler->*callback)(&ipc_info))
+ break;
+ error = false;
+ break;
+ }
+ case 1: {
+ Dispatcher::Callback1 callback =
+ reinterpret_cast<Dispatcher::Callback1>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0]))
+ break;
+ error = false;
+ break;
+ }
+ case 2: {
+ Dispatcher::Callback2 callback =
+ reinterpret_cast<Dispatcher::Callback2>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1]))
+ break;
+ error = false;
+ break;
+ }
+ case 3: {
+ Dispatcher::Callback3 callback =
+ reinterpret_cast<Dispatcher::Callback3>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2]))
+ break;
+ error = false;
+ break;
+ }
+ case 4: {
+ Dispatcher::Callback4 callback =
+ reinterpret_cast<Dispatcher::Callback4>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2],
+ args[3]))
+ break;
+ error = false;
+ break;
+ }
+ case 5: {
+ Dispatcher::Callback5 callback =
+ reinterpret_cast<Dispatcher::Callback5>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+ args[4]))
+ break;
+ error = false;
+ break;
+ }
+ case 6: {
+ Dispatcher::Callback6 callback =
+ reinterpret_cast<Dispatcher::Callback6>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+ args[4], args[5]))
+ break;
+ error = false;
+ break;
+ }
+ case 7: {
+ Dispatcher::Callback7 callback =
+ reinterpret_cast<Dispatcher::Callback7>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+ args[4], args[5], args[6]))
+ break;
+ error = false;
+ break;
+ }
+ case 8: {
+ Dispatcher::Callback8 callback =
+ reinterpret_cast<Dispatcher::Callback8>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+ args[4], args[5], args[6], args[7]))
+ break;
+ error = false;
+ break;
+ }
+ case 9: {
+ Dispatcher::Callback9 callback =
+ reinterpret_cast<Dispatcher::Callback9>(callback_generic);
+ if (!(handler->*callback)(&ipc_info, args[0], args[1], args[2], args[3],
+ args[4], args[5], args[6], args[7], args[8]))
+ break;
+ error = false;
+ break;
+ }
+ default: {
+ NOTREACHED();
+ break;
+ }
+ }
+ }
+
+ if (error) {
+ if (handler)
+ SetCallError(SBOX_ERROR_FAILED_IPC, call_result);
+ } else {
+ memcpy(call_result, &ipc_info.return_info, sizeof(*call_result));
+ SetCallSuccess(call_result);
+ if (params->IsInOut()) {
+ // Maybe the params got changed by the broker. We need to upadte the
+ // memory section.
+ memcpy(ipc_buffer, params.get(), output_size);
+ }
+ }
+
+ ReleaseArgs(&ipc_params, args);
+
+ return !error;
+}
+
+// This function gets called by a thread from the thread pool when a
+// ping event fires. The context is the same as passed in the RegisterWait()
+// call above.
+void __stdcall SharedMemIPCServer::ThreadPingEventReady(void* context,
+ unsigned char) {
+ if (!context) {
+ DCHECK(false);
+ return;
+ }
+ ServerControl* service_context = reinterpret_cast<ServerControl*>(context);
+ // Since the event fired, the channel *must* be busy. Change to kAckChannel
+ // while we service it.
+ LONG last_state = ::InterlockedCompareExchange(
+ &service_context->channel->state, kAckChannel, kBusyChannel);
+ if (kBusyChannel != last_state) {
+ DCHECK(false);
+ return;
+ }
+
+ // Prepare the result structure. At this point we will return some result
+ // even if the IPC is invalid, malformed or has no handler.
+ CrossCallReturn call_result = {0};
+ void* buffer = service_context->channel_buffer;
+
+ InvokeCallback(service_context, buffer, &call_result);
+
+ // Copy the answer back into the channel and signal the pong event. This
+ // should wake up the client so it can finish the ipc cycle.
+ CrossCallParams* call_params = reinterpret_cast<CrossCallParams*>(buffer);
+ memcpy(call_params->GetCallReturn(), &call_result, sizeof(call_result));
+ ::InterlockedExchange(&service_context->channel->state, kAckChannel);
+ ::SetEvent(service_context->pong_event.Get());
+}
+
+bool SharedMemIPCServer::MakeEvents(base::win::ScopedHandle* server_ping,
+ base::win::ScopedHandle* server_pong,
+ HANDLE* client_ping,
+ HANDLE* client_pong) {
+ // Note that the IPC client has no right to delete the events. That would
+ // cause problems. The server *owns* the events.
+ const DWORD kDesiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE;
+
+ // The events are auto reset, and start not signaled.
+ server_ping->Set(::CreateEventW(nullptr, false, false, nullptr));
+ if (!::DuplicateHandle(::GetCurrentProcess(), server_ping->Get(),
+ target_process_, client_ping, kDesiredAccess, false,
+ 0)) {
+ return false;
+ }
+
+ server_pong->Set(::CreateEventW(nullptr, false, false, nullptr));
+ if (!::DuplicateHandle(::GetCurrentProcess(), server_pong->Get(),
+ target_process_, client_pong, kDesiredAccess, false,
+ 0)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.h b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.h
new file mode 100644
index 0000000000..abf0876ea4
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sharedmem_ipc_server.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SHAREDMEM_IPC_SERVER_H_
+#define SANDBOX_SRC_SHAREDMEM_IPC_SERVER_H_
+
+#include <stdint.h>
+
+#include <list>
+#include <memory>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_params.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+
+// IPC transport implementation that uses shared memory.
+// This is the server side
+//
+// The server side has knowledge about the layout of the shared memory
+// and the state transitions. Both are explained in sharedmem_ipc_client.h
+//
+// As opposed to SharedMemIPClient, the Server object should be one for the
+// entire lifetime of the target process. The server is in charge of creating
+// the events (ping, pong) both for the client and for the target that are used
+// to signal the IPC and also in charge of setting the initial state of the
+// channels.
+//
+// When an IPC is ready, the server relies on being called by on the
+// ThreadPingEventReady callback. The IPC server then retrieves the buffer,
+// marshals it into a CrossCallParam object and calls the Dispatcher, who is in
+// charge of fulfilling the IPC request.
+namespace sandbox {
+
+// the shared memory implementation of the IPC server. There should be one
+// of these objects per target (IPC client) process
+class SharedMemIPCServer {
+ public:
+ // Creates the IPC server.
+ // target_process: handle to the target process. It must be suspended. It is
+ // unfortunate to receive a raw handle (and store it inside this object) as
+ // that dilutes ownership of the process, but in practice a SharedMemIPCServer
+ // is owned by TargetProcess, which calls this method, and owns the handle, so
+ // everything is safe. If that changes, we should break this dependency and
+ // duplicate the handle instead.
+ // target_process_id: process id of the target process.
+ // thread_provider: a thread provider object.
+ // dispatcher: an object that can service IPC calls.
+ SharedMemIPCServer(HANDLE target_process,
+ DWORD target_process_id,
+ ThreadProvider* thread_provider,
+ Dispatcher* dispatcher);
+
+ ~SharedMemIPCServer();
+
+ // Initializes the server structures, shared memory structures and
+ // creates the kernels events used to signal the IPC.
+ bool Init(void* shared_mem, uint32_t shared_size, uint32_t channel_size);
+
+ // Create the mutex used by clients to check if the broker process crashed.
+ // This function must be called only once, from a thread that will live as
+ // long as the whole broker process will. This call must occur prior to any
+ // SharedMemIPCServer creation.
+ static bool CreateBrokerAliveMutex();
+
+ private:
+ // Allow tests to be marked DISABLED_. Note that FLAKY_ and FAILS_ prefixes
+ // do not work with sandbox tests.
+ FRIEND_TEST_ALL_PREFIXES(IPCTest, SharedMemServerTests);
+ // When an event fires (IPC request). A thread from the ThreadProvider
+ // will call this function. The context parameter should be the same as
+ // provided when ThreadProvider::RegisterWait was called.
+ static void __stdcall ThreadPingEventReady(void* context, unsigned char);
+
+ // Makes the client and server events. This function is called once
+ // per channel.
+ bool MakeEvents(base::win::ScopedHandle* server_ping,
+ base::win::ScopedHandle* server_pong,
+ HANDLE* client_ping,
+ HANDLE* client_pong);
+
+ // A copy this structure is maintained per channel.
+ // Note that a lot of the fields are just the same of what we have in the IPC
+ // object itself. It is better to have the copies since we can dispatch in the
+ // static method without worrying about converting back to a member function
+ // call or about threading issues.
+ struct ServerControl {
+ ServerControl();
+ ~ServerControl();
+
+ // This channel server ping event.
+ base::win::ScopedHandle ping_event;
+ // This channel server pong event.
+ base::win::ScopedHandle pong_event;
+ // The size of this channel.
+ uint32_t channel_size;
+ // The pointer to the actual channel data.
+ char* channel_buffer;
+ // The pointer to the base of the shared memory.
+ char* shared_base;
+ // A pointer to this channel's client-side control structure this structure
+ // lives in the shared memory.
+ ChannelControl* channel;
+ // the IPC dispatcher associated with this channel.
+ Dispatcher* dispatcher;
+ // The target process information associated with this channel.
+ ClientInfo target_info;
+ };
+
+ // Looks for the appropriate handler for this IPC and invokes it.
+ static bool InvokeCallback(const ServerControl* service_context,
+ void* ipc_buffer,
+ CrossCallReturn* call_result);
+
+ // Points to the shared memory channel control which lives at
+ // the start of the shared section.
+ IPCControl* client_control_;
+
+ // Keeps track of the server side objects that are used to answer an IPC.
+ std::list<std::unique_ptr<ServerControl>> server_contexts_;
+
+ // The thread provider provides the threads that call back into this object
+ // when the IPC events fire.
+ ThreadProvider* thread_provider_;
+
+ // The IPC object is associated with a target process.
+ HANDLE target_process_;
+
+ // The target process id associated with the IPC object.
+ DWORD target_process_id_;
+
+ // The dispatcher handles 'ready' IPC calls.
+ Dispatcher* call_dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(SharedMemIPCServer);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SHAREDMEM_IPC_SERVER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sid.cc b/security/sandbox/chromium/sandbox/win/src/sid.cc
new file mode 100644
index 0000000000..a97ca340ed
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sid.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sid.h"
+
+#include <memory>
+
+#include <sddl.h>
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+DWORD WellKnownCapabilityToRid(WellKnownCapabilities capability) {
+ switch (capability) {
+ case kInternetClient:
+ return SECURITY_CAPABILITY_INTERNET_CLIENT;
+ case kInternetClientServer:
+ return SECURITY_CAPABILITY_INTERNET_CLIENT_SERVER;
+ case kPrivateNetworkClientServer:
+ return SECURITY_CAPABILITY_PRIVATE_NETWORK_CLIENT_SERVER;
+ case kPicturesLibrary:
+ return SECURITY_CAPABILITY_PICTURES_LIBRARY;
+ case kVideosLibrary:
+ return SECURITY_CAPABILITY_VIDEOS_LIBRARY;
+ case kMusicLibrary:
+ return SECURITY_CAPABILITY_MUSIC_LIBRARY;
+ case kDocumentsLibrary:
+ return SECURITY_CAPABILITY_DOCUMENTS_LIBRARY;
+ case kEnterpriseAuthentication:
+ return SECURITY_CAPABILITY_ENTERPRISE_AUTHENTICATION;
+ case kSharedUserCertificates:
+ return SECURITY_CAPABILITY_SHARED_USER_CERTIFICATES;
+ case kRemovableStorage:
+ return SECURITY_CAPABILITY_REMOVABLE_STORAGE;
+ case kAppointments:
+ return SECURITY_CAPABILITY_APPOINTMENTS;
+ case kContacts:
+ return SECURITY_CAPABILITY_CONTACTS;
+ default:
+ break;
+ }
+ return 0;
+}
+
+} // namespace
+
+Sid::Sid() : sid_() {}
+
+Sid::Sid(PSID sid) : sid_() {
+ ::CopySid(SECURITY_MAX_SID_SIZE, sid_, sid);
+}
+
+Sid::Sid(const SID* sid) : sid_() {
+ ::CopySid(SECURITY_MAX_SID_SIZE, sid_, const_cast<SID*>(sid));
+}
+
+Sid::Sid(WELL_KNOWN_SID_TYPE type) {
+ DWORD size_sid = SECURITY_MAX_SID_SIZE;
+ bool result = ::CreateWellKnownSid(type, nullptr, sid_, &size_sid);
+ DCHECK(result);
+ (void)result;
+}
+
+Sid Sid::FromKnownCapability(WellKnownCapabilities capability) {
+ DWORD capability_rid = WellKnownCapabilityToRid(capability);
+ if (!capability_rid)
+ return Sid();
+ SID_IDENTIFIER_AUTHORITY capability_authority = {
+ SECURITY_APP_PACKAGE_AUTHORITY};
+ DWORD sub_authorities[] = {SECURITY_CAPABILITY_BASE_RID, capability_rid};
+ return FromSubAuthorities(&capability_authority, 2, sub_authorities);
+}
+
+Sid Sid::FromNamedCapability(const wchar_t* capability_name) {
+ RtlDeriveCapabilitySidsFromNameFunction derive_capability_sids = nullptr;
+ ResolveNTFunctionPtr("RtlDeriveCapabilitySidsFromName",
+ &derive_capability_sids);
+ RtlInitUnicodeStringFunction init_unicode_string = nullptr;
+ ResolveNTFunctionPtr("RtlInitUnicodeString", &init_unicode_string);
+
+ if (!derive_capability_sids || !init_unicode_string)
+ return Sid();
+
+ if (!capability_name || ::wcslen(capability_name) == 0)
+ return Sid();
+
+ UNICODE_STRING name = {};
+ init_unicode_string(&name, capability_name);
+ Sid capability_sid;
+ Sid group_sid;
+
+ NTSTATUS status =
+ derive_capability_sids(&name, group_sid.sid_, capability_sid.sid_);
+ if (!NT_SUCCESS(status))
+ return Sid();
+
+ return capability_sid;
+}
+
+Sid Sid::FromSddlString(const wchar_t* sddl_sid) {
+ PSID converted_sid;
+ if (!::ConvertStringSidToSid(sddl_sid, &converted_sid))
+ return Sid();
+
+ return Sid(converted_sid);
+}
+
+Sid Sid::FromSubAuthorities(PSID_IDENTIFIER_AUTHORITY identifier_authority,
+ BYTE sub_authority_count,
+ PDWORD sub_authorities) {
+ Sid sid;
+ if (!::InitializeSid(sid.sid_, identifier_authority, sub_authority_count))
+ return Sid();
+
+ for (DWORD index = 0; index < sub_authority_count; ++index) {
+ PDWORD sub_authority = GetSidSubAuthority(sid.sid_, index);
+ *sub_authority = sub_authorities[index];
+ }
+ return sid;
+}
+
+Sid Sid::AllRestrictedApplicationPackages() {
+ SID_IDENTIFIER_AUTHORITY package_authority = {SECURITY_APP_PACKAGE_AUTHORITY};
+ DWORD sub_authorities[] = {SECURITY_APP_PACKAGE_BASE_RID,
+ SECURITY_BUILTIN_PACKAGE_ANY_RESTRICTED_PACKAGE};
+ return FromSubAuthorities(&package_authority, 2, sub_authorities);
+}
+
+Sid Sid::GenerateRandomSid() {
+ SID_IDENTIFIER_AUTHORITY package_authority = {SECURITY_NULL_SID_AUTHORITY};
+ DWORD sub_authorities[4] = {};
+ base::RandBytes(&sub_authorities, sizeof(sub_authorities));
+ return FromSubAuthorities(&package_authority, _countof(sub_authorities),
+ sub_authorities);
+}
+
+PSID Sid::GetPSID() const {
+ return const_cast<BYTE*>(sid_);
+}
+
+bool Sid::IsValid() const {
+ return !!::IsValidSid(GetPSID());
+}
+
+// Converts the SID to an SDDL format string.
+bool Sid::ToSddlString(std::wstring* sddl_string) const {
+ LPWSTR sid = nullptr;
+ if (!::ConvertSidToStringSid(GetPSID(), &sid))
+ return false;
+ std::unique_ptr<void, LocalFreeDeleter> sid_ptr(sid);
+ *sddl_string = sid;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sid.h b/security/sandbox/chromium/sandbox/win/src/sid.h
new file mode 100644
index 0000000000..745f471054
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sid.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SID_H_
+#define SANDBOX_SRC_SID_H_
+
+#include <windows.h>
+
+#include <string>
+
+namespace sandbox {
+
+// Known capabilities defined in Windows 8.
+enum WellKnownCapabilities {
+ kInternetClient,
+ kInternetClientServer,
+ kPrivateNetworkClientServer,
+ kPicturesLibrary,
+ kVideosLibrary,
+ kMusicLibrary,
+ kDocumentsLibrary,
+ kEnterpriseAuthentication,
+ kSharedUserCertificates,
+ kRemovableStorage,
+ kAppointments,
+ kContacts,
+ kMaxWellKnownCapability
+};
+
+// This class is used to hold and generate SIDS.
+class Sid {
+ public:
+ // As PSID is just a void* make it explicit.
+ explicit Sid(PSID sid);
+ // Constructors initializing the object with the SID passed.
+ // This is a converting constructor. It is not explicit.
+ Sid(const SID* sid);
+ Sid(WELL_KNOWN_SID_TYPE type);
+
+ // Create a Sid from an AppContainer capability name. The name can be
+ // completely arbitrary.
+ static Sid FromNamedCapability(const wchar_t* capability_name);
+ // Create a Sid from a known capability enumeration value. The Sids
+ // match with the list defined in Windows 8.
+ static Sid FromKnownCapability(WellKnownCapabilities capability);
+ // Create a Sid from a SDDL format string, such as S-1-1-0.
+ static Sid FromSddlString(const wchar_t* sddl_sid);
+ // Create a Sid from a set of sub authorities.
+ static Sid FromSubAuthorities(PSID_IDENTIFIER_AUTHORITY identifier_authority,
+ BYTE sub_authority_count,
+ PDWORD sub_authorities);
+ // Create the restricted all application packages sid.
+ static Sid AllRestrictedApplicationPackages();
+ // Generate a random SID value.
+ static Sid GenerateRandomSid();
+
+ // Returns sid_.
+ PSID GetPSID() const;
+
+ // Gets whether the sid is valid.
+ bool IsValid() const;
+
+ // Converts the SID to a SDDL format string.
+ bool ToSddlString(std::wstring* sddl_string) const;
+
+ private:
+ Sid();
+ BYTE sid_[SECURITY_MAX_SID_SIZE];
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SID_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sid_unittest.cc b/security/sandbox/chromium/sandbox/win/src/sid_unittest.cc
new file mode 100644
index 0000000000..81186cd0be
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sid_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for the sid class.
+
+#include "sandbox/win/src/sid.h"
+
+#include <sddl.h>
+
+#include "base/win/atl.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+bool EqualSid(const Sid& sid, const ATL::CSid& compare_sid) {
+ if (!sid.IsValid())
+ return false;
+ return !!::EqualSid(sid.GetPSID(), const_cast<SID*>(compare_sid.GetPSID()));
+}
+
+bool EqualSid(const Sid& sid, const wchar_t* sddl_sid) {
+ PSID compare_sid;
+ if (!sid.IsValid())
+ return false;
+ if (!::ConvertStringSidToSid(sddl_sid, &compare_sid))
+ return false;
+ bool equal = !!::EqualSid(sid.GetPSID(), compare_sid);
+ ::LocalFree(compare_sid);
+ return equal;
+}
+
+struct KnownCapabilityTestEntry {
+ WellKnownCapabilities capability;
+ const wchar_t* sddl_sid;
+};
+
+struct NamedCapabilityTestEntry {
+ const wchar_t* capability_name;
+ const wchar_t* sddl_sid;
+};
+
+} // namespace
+
+// Tests the creation of a Sid.
+TEST(SidTest, Constructors) {
+ ATL::CSid sid_world = ATL::Sids::World();
+ PSID sid_world_pointer = const_cast<SID*>(sid_world.GetPSID());
+
+ // Check the SID* constructor.
+ Sid sid_sid_star(sid_world_pointer);
+ ASSERT_TRUE(EqualSid(sid_sid_star, sid_world));
+
+ // Check the copy constructor.
+ Sid sid_copy(sid_sid_star);
+ ASSERT_TRUE(EqualSid(sid_copy, sid_world));
+
+ Sid sid_sddl = Sid::FromSddlString(L"S-1-1-0");
+ ASSERT_TRUE(sid_sddl.IsValid());
+ ASSERT_TRUE(EqualSid(sid_sddl, sid_world));
+
+ Sid sid_sddl_invalid = Sid::FromSddlString(L"X-1-1-0");
+ ASSERT_FALSE(sid_sddl_invalid.IsValid());
+
+ Sid sid_sddl_empty = Sid::FromSddlString(L"");
+ ASSERT_FALSE(sid_sddl_empty.IsValid());
+
+ // Note that the WELL_KNOWN_SID_TYPE constructor is tested in the GetPSID
+ // test. AppContainer related constructors are tested in AppContainer.
+}
+
+// Tests the method GetPSID
+TEST(SidTest, GetPSID) {
+ // Check for non-null result;
+ ASSERT_NE(nullptr, Sid(::WinLocalSid).GetPSID());
+ ASSERT_NE(nullptr, Sid(::WinCreatorOwnerSid).GetPSID());
+ ASSERT_NE(nullptr, Sid(::WinBatchSid).GetPSID());
+
+ ASSERT_TRUE(EqualSid(Sid(::WinNullSid), ATL::Sids::Null()));
+
+ ASSERT_TRUE(EqualSid(Sid(::WinWorldSid), ATL::Sids::World()));
+
+ ASSERT_TRUE(EqualSid(Sid(::WinDialupSid), ATL::Sids::Dialup()));
+
+ ASSERT_TRUE(EqualSid(Sid(::WinNetworkSid), ATL::Sids::Network()));
+
+ ASSERT_TRUE(
+ EqualSid(Sid(::WinBuiltinAdministratorsSid), ATL::Sids::Admins()));
+
+ ASSERT_TRUE(EqualSid(Sid(::WinBuiltinUsersSid), ATL::Sids::Users()));
+
+ ASSERT_TRUE(EqualSid(Sid(::WinBuiltinGuestsSid), ATL::Sids::Guests()));
+
+ ASSERT_TRUE(EqualSid(Sid(::WinProxySid), ATL::Sids::Proxy()));
+}
+
+TEST(SidTest, KnownCapability) {
+ if (base::win::GetVersion() < base::win::Version::WIN8)
+ return;
+
+ Sid sid_invalid_well_known =
+ Sid::FromKnownCapability(kMaxWellKnownCapability);
+ EXPECT_FALSE(sid_invalid_well_known.IsValid());
+
+ const KnownCapabilityTestEntry capabilities[] = {
+ {kInternetClient, L"S-1-15-3-1"},
+ {kInternetClientServer, L"S-1-15-3-2"},
+ {kPrivateNetworkClientServer, L"S-1-15-3-3"},
+ {kPicturesLibrary, L"S-1-15-3-4"},
+ {kVideosLibrary, L"S-1-15-3-5"},
+ {kMusicLibrary, L"S-1-15-3-6"},
+ {kDocumentsLibrary, L"S-1-15-3-7"},
+ {kEnterpriseAuthentication, L"S-1-15-3-8"},
+ {kSharedUserCertificates, L"S-1-15-3-9"},
+ {kRemovableStorage, L"S-1-15-3-10"},
+ {kAppointments, L"S-1-15-3-11"},
+ {kContacts, L"S-1-15-3-12"},
+ };
+
+ for (auto capability : capabilities) {
+ EXPECT_TRUE(EqualSid(Sid::FromKnownCapability(capability.capability),
+ capability.sddl_sid))
+ << "Known Capability: " << capability.sddl_sid;
+ }
+}
+
+TEST(SidTest, NamedCapability) {
+ if (base::win::GetVersion() < base::win::Version::WIN10)
+ return;
+
+ Sid sid_nullptr = Sid::FromNamedCapability(nullptr);
+ EXPECT_FALSE(sid_nullptr.IsValid());
+
+ Sid sid_empty = Sid::FromNamedCapability(L"");
+ EXPECT_FALSE(sid_empty.IsValid());
+
+ const NamedCapabilityTestEntry capabilities[] = {
+ {L"internetClient", L"S-1-15-3-1"},
+ {L"internetClientServer", L"S-1-15-3-2"},
+ {L"registryRead",
+ L"S-1-15-3-1024-1065365936-1281604716-3511738428-"
+ "1654721687-432734479-3232135806-4053264122-3456934681"},
+ {L"lpacCryptoServices",
+ L"S-1-15-3-1024-3203351429-2120443784-2872670797-"
+ "1918958302-2829055647-4275794519-765664414-2751773334"},
+ {L"enterpriseAuthentication", L"S-1-15-3-8"},
+ {L"privateNetworkClientServer", L"S-1-15-3-3"}};
+
+ for (auto capability : capabilities) {
+ EXPECT_TRUE(EqualSid(Sid::FromNamedCapability(capability.capability_name),
+ capability.sddl_sid))
+ << "Named Capability: " << capability.sddl_sid;
+ }
+}
+
+TEST(SidTest, Sddl) {
+ Sid sid_sddl = Sid::FromSddlString(L"S-1-1-0");
+ ASSERT_TRUE(sid_sddl.IsValid());
+ std::wstring sddl_str;
+ ASSERT_TRUE(sid_sddl.ToSddlString(&sddl_str));
+ ASSERT_EQ(L"S-1-1-0", sddl_str);
+}
+
+TEST(SidTest, SubAuthorities) {
+ DWORD world_subauthorities[] = {0};
+ SID_IDENTIFIER_AUTHORITY world_authority = {SECURITY_WORLD_SID_AUTHORITY};
+ Sid sid_world =
+ Sid::FromSubAuthorities(&world_authority, 1, world_subauthorities);
+ ASSERT_TRUE(EqualSid(sid_world, ATL::Sids::World()));
+ ASSERT_TRUE(Sid::FromSubAuthorities(&world_authority, 0, nullptr).IsValid());
+
+ DWORD admin_subauthorities[] = {32, 544};
+ SID_IDENTIFIER_AUTHORITY nt_authority = {SECURITY_NT_AUTHORITY};
+ Sid sid_admin =
+ Sid::FromSubAuthorities(&nt_authority, 2, admin_subauthorities);
+ ASSERT_TRUE(EqualSid(sid_admin, ATL::Sids::Admins()));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/signed_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/signed_dispatcher.cc
new file mode 100644
index 0000000000..49e7cbe946
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/signed_dispatcher.cc
@@ -0,0 +1,68 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/signed_dispatcher.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/strings/string_util.h"
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/signed_interception.h"
+#include "sandbox/win/src/signed_policy.h"
+
+namespace sandbox {
+
+SignedDispatcher::SignedDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall create_params = {
+ {IpcTag::NTCREATESECTION, {VOIDPTR_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&SignedDispatcher::CreateSection)};
+
+ ipc_calls_.push_back(create_params);
+}
+
+bool SignedDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ if (service == IpcTag::NTCREATESECTION)
+ return INTERCEPT_NT(manager, NtCreateSection, CREATE_SECTION_ID, 32);
+ return false;
+}
+
+bool SignedDispatcher::CreateSection(IPCInfo* ipc, HANDLE file_handle) {
+ // Duplicate input handle from target to broker.
+ HANDLE local_file_handle = nullptr;
+ if (!::DuplicateHandle((*ipc->client_info).process, file_handle,
+ ::GetCurrentProcess(), &local_file_handle,
+ FILE_MAP_EXECUTE, false, 0)) {
+ return false;
+ }
+
+ base::win::ScopedHandle local_handle(local_file_handle);
+ std::wstring path;
+ if (!GetPathFromHandle(local_handle.Get(), &path))
+ return false;
+ const wchar_t* module_name = path.c_str();
+ CountedParameterSet<NameBased> params;
+ params[NameBased::NAME] = ParamPickerMake(module_name);
+
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::NTCREATESECTION, params.GetBase());
+
+ // Return operation status on the IPC.
+ HANDLE section_handle = nullptr;
+ ipc->return_info.nt_status = SignedPolicy::CreateSectionAction(
+ result, *ipc->client_info, local_handle, &section_handle);
+ ipc->return_info.handle = section_handle;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/signed_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/signed_dispatcher.h
new file mode 100644
index 0000000000..38435481f6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/signed_dispatcher.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SIGNED_DISPATCHER_H_
+#define SANDBOX_WIN_SRC_SIGNED_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles signed-binary related IPC calls.
+class SignedDispatcher : public Dispatcher {
+ public:
+ explicit SignedDispatcher(PolicyBase* policy_base);
+ ~SignedDispatcher() override {}
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to CreateSection in the target.
+ bool CreateSection(IPCInfo* ipc, HANDLE file_handle);
+
+ PolicyBase* policy_base_;
+ DISALLOW_COPY_AND_ASSIGN(SignedDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SIGNED_DISPATCHER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/signed_interception.cc b/security/sandbox/chromium/sandbox/win/src/signed_interception.cc
new file mode 100644
index 0000000000..4f4310d605
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/signed_interception.cc
@@ -0,0 +1,97 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/signed_interception.h"
+
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+
+namespace sandbox {
+
+NTSTATUS WINAPI
+TargetNtCreateSection(NtCreateSectionFunction orig_CreateSection,
+ PHANDLE section_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PLARGE_INTEGER maximum_size,
+ ULONG section_page_protection,
+ ULONG allocation_attributes,
+ HANDLE file_handle) {
+ do {
+ // The section only needs to have SECTION_MAP_EXECUTE, but the permissions
+ // vary depending on the OS. Windows 1903 and higher requests (SECTION_QUERY
+ // | SECTION_MAP_READ | SECTION_MAP_EXECUTE) while previous OS versions also
+ // request SECTION_MAP_WRITE. Just check for EXECUTE.
+ if (!(desired_access & SECTION_MAP_EXECUTE))
+ break;
+ if (object_attributes)
+ break;
+ if (maximum_size)
+ break;
+ if (section_page_protection != PAGE_EXECUTE)
+ break;
+ if (allocation_attributes != SEC_IMAGE)
+ break;
+
+ mozilla::sandboxing::LogBlocked("NtCreateSection");
+
+ // IPC must be fully started.
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> path;
+
+ if (!NtGetPathFromHandle(file_handle, &path))
+ break;
+
+ const wchar_t* const_name = path.get();
+
+ CountedParameterSet<NameBased> params;
+ params[NameBased::NAME] = ParamPickerMake(const_name);
+
+ // Check if this will be sent to the broker.
+ if (!QueryBroker(IpcTag::NTCREATESECTION, params.GetBase()))
+ break;
+
+ if (!ValidParameter(section_handle, sizeof(HANDLE), WRITE))
+ break;
+
+ CrossCallReturn answer = {0};
+ answer.nt_status = STATUS_INVALID_IMAGE_HASH;
+ SharedMemIPCClient ipc(memory);
+ ResultCode code =
+ CrossCall(ipc, IpcTag::NTCREATESECTION, file_handle, &answer);
+
+ if (code != SBOX_ALL_OK)
+ break;
+
+ if (!NT_SUCCESS(answer.nt_status))
+ break;
+
+ __try {
+ *section_handle = answer.handle;
+ mozilla::sandboxing::LogAllowed("NtCreateSection");
+ return answer.nt_status;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ } while (false);
+
+ // Fall back to the original API in all failure cases.
+ return orig_CreateSection(section_handle, desired_access, object_attributes,
+ maximum_size, section_page_protection,
+ allocation_attributes, file_handle);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/signed_interception.h b/security/sandbox/chromium/sandbox/win/src/signed_interception.h
new file mode 100644
index 0000000000..a50ec38222
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/signed_interception.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SIGNED_INTERCEPTION_H_
+#define SANDBOX_WIN_SRC_SIGNED_INTERCEPTION_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+// Interceptor for NtCreateSection
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateSection(NtCreateSectionFunction orig_CreateSection,
+ PHANDLE section_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ PLARGE_INTEGER maximum_size,
+ ULONG section_page_protection,
+ ULONG allocation_attributes,
+ HANDLE file_handle);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SIGNED_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/signed_policy.cc b/security/sandbox/chromium/sandbox/win/src/signed_policy.cc
new file mode 100644
index 0000000000..ccf11defe7
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/signed_policy.cc
@@ -0,0 +1,102 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/signed_policy.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace {
+
+bool IsValidNtPath(const base::FilePath& name) {
+ UNICODE_STRING uni_name;
+ OBJECT_ATTRIBUTES obj_attr;
+ sandbox::InitObjectAttribs(name.value(), OBJ_CASE_INSENSITIVE, nullptr,
+ &obj_attr, &uni_name, nullptr);
+
+ NtQueryAttributesFileFunction NtQueryAttributesFile = nullptr;
+ ResolveNTFunctionPtr("NtQueryAttributesFile", &NtQueryAttributesFile);
+ FILE_BASIC_INFORMATION file_info;
+ return NtQueryAttributesFile &&
+ NT_SUCCESS(NtQueryAttributesFile(&obj_attr, &file_info));
+}
+
+} // namespace
+
+namespace sandbox {
+
+bool SignedPolicy::GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ // Only support one semantic.
+ if (TargetPolicy::SIGNED_ALLOW_LOAD != semantics) {
+ return false;
+ }
+
+ base::FilePath file_path(name);
+ base::FilePath nt_filename;
+ std::wstring nt_path_name;
+ if (GetNtPathFromWin32Path(file_path.DirName().value().c_str(),
+ &nt_path_name)) {
+ base::FilePath nt_path(nt_path_name);
+ nt_filename = nt_path.Append(file_path.BaseName());
+ } else if (IsValidNtPath(file_path)) {
+ nt_filename = std::move(file_path);
+ } else {
+ return false;
+ }
+
+ // Create a rule to ASK_BROKER if name matches.
+ PolicyRule signed_policy(ASK_BROKER);
+ if (!signed_policy.AddStringMatch(
+ IF, NameBased::NAME, nt_filename.value().c_str(), CASE_INSENSITIVE)) {
+ return false;
+ }
+ if (!policy->AddRule(IpcTag::NTCREATESECTION, &signed_policy)) {
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS SignedPolicy::CreateSectionAction(
+ EvalResult eval_result,
+ const ClientInfo& client_info,
+ const base::win::ScopedHandle& local_file_handle,
+ HANDLE* target_section_handle) {
+ NtCreateSectionFunction NtCreateSection = nullptr;
+ ResolveNTFunctionPtr("NtCreateSection", &NtCreateSection);
+
+ // The only action supported is ASK_BROKER which means create the requested
+ // section as specified.
+ if (ASK_BROKER != eval_result)
+ return false;
+
+ HANDLE local_section_handle = nullptr;
+ NTSTATUS status = NtCreateSection(&local_section_handle,
+ SECTION_QUERY | SECTION_MAP_WRITE |
+ SECTION_MAP_READ | SECTION_MAP_EXECUTE,
+ nullptr, 0, PAGE_EXECUTE, SEC_IMAGE,
+ local_file_handle.Get());
+ if (!local_section_handle)
+ return status;
+
+ // Duplicate section handle back to the target.
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_section_handle,
+ client_info.process, target_section_handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ return status;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/signed_policy.h b/security/sandbox/chromium/sandbox/win/src/signed_policy.h
new file mode 100644
index 0000000000..d22af4d4dc
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/signed_policy.h
@@ -0,0 +1,39 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SIGNED_POLICY_H_
+#define SANDBOX_WIN_SRC_SIGNED_POLICY_H_
+
+#include <stdint.h>
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+// This class centralizes most of the knowledge related to signed policy
+class SignedPolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level
+ // policy rule.
+ static bool GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ // Performs the desired policy action on a request.
+ // client_info is the target process that is making the request and
+ // eval_result is the desired policy action to accomplish.
+ static NTSTATUS CreateSectionAction(
+ EvalResult eval_result,
+ const ClientInfo& client_info,
+ const base::win::ScopedHandle& local_file_handle,
+ HANDLE* section_handle);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SIGNED_POLICY_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/sync_dispatcher.cc
new file mode 100644
index 0000000000..d728e1d831
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_dispatcher.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sync_dispatcher.h"
+
+#include <stdint.h>
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/interceptors.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_broker.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sync_interception.h"
+#include "sandbox/win/src/sync_policy.h"
+
+namespace sandbox {
+
+SyncDispatcher::SyncDispatcher(PolicyBase* policy_base)
+ : policy_base_(policy_base) {
+ static const IPCCall create_params = {
+ {IpcTag::CREATEEVENT, {WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&SyncDispatcher::CreateEvent)};
+
+ static const IPCCall open_params = {
+ {IpcTag::OPENEVENT, {WCHAR_TYPE, UINT32_TYPE}},
+ reinterpret_cast<CallbackGeneric>(&SyncDispatcher::OpenEvent)};
+
+ ipc_calls_.push_back(create_params);
+ ipc_calls_.push_back(open_params);
+}
+
+bool SyncDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ if (service == IpcTag::CREATEEVENT) {
+ return INTERCEPT_NT(manager, NtCreateEvent, CREATE_EVENT_ID, 24);
+ }
+ return (service == IpcTag::OPENEVENT) &&
+ INTERCEPT_NT(manager, NtOpenEvent, OPEN_EVENT_ID, 16);
+}
+
+bool SyncDispatcher::CreateEvent(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t event_type,
+ uint32_t initial_state) {
+ const wchar_t* event_name = name->c_str();
+ CountedParameterSet<NameBased> params;
+ params[NameBased::NAME] = ParamPickerMake(event_name);
+
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::CREATEEVENT, params.GetBase());
+ HANDLE handle = nullptr;
+ // Return operation status on the IPC.
+ ipc->return_info.nt_status = SyncPolicy::CreateEventAction(
+ result, *ipc->client_info, *name, event_type, initial_state, &handle);
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+bool SyncDispatcher::OpenEvent(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t desired_access) {
+ const wchar_t* event_name = name->c_str();
+
+ CountedParameterSet<OpenEventParams> params;
+ params[OpenEventParams::NAME] = ParamPickerMake(event_name);
+ params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access);
+
+ EvalResult result =
+ policy_base_->EvalPolicy(IpcTag::OPENEVENT, params.GetBase());
+ HANDLE handle = nullptr;
+ // Return operation status on the IPC.
+ ipc->return_info.nt_status = SyncPolicy::OpenEventAction(
+ result, *ipc->client_info, *name, desired_access, &handle);
+ ipc->return_info.handle = handle;
+ return true;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/sync_dispatcher.h
new file mode 100644
index 0000000000..d4bc025a0b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_dispatcher.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SYNC_DISPATCHER_H_
+#define SANDBOX_SRC_SYNC_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// This class handles sync-related IPC calls.
+class SyncDispatcher : public Dispatcher {
+ public:
+ explicit SyncDispatcher(PolicyBase* policy_base);
+ ~SyncDispatcher() override {}
+
+ // Dispatcher interface.
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Processes IPC requests coming from calls to CreateEvent in the target.
+ bool CreateEvent(IPCInfo* ipc,
+ std::wstring* name,
+ uint32_t event_type,
+ uint32_t initial_state);
+
+ // Processes IPC requests coming from calls to OpenEvent in the target.
+ bool OpenEvent(IPCInfo* ipc, std::wstring* name, uint32_t desired_access);
+
+ PolicyBase* policy_base_;
+ DISALLOW_COPY_AND_ASSIGN(SyncDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SYNC_DISPATCHER_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_interception.cc b/security/sandbox/chromium/sandbox/win/src/sync_interception.cc
new file mode 100644
index 0000000000..9ec680e2fd
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_interception.cc
@@ -0,0 +1,177 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sync_interception.h"
+
+#include <stdint.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/policy_target.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+#include "sandbox/win/src/target_services.h"
+#include "mozilla/sandboxing/sandboxLogging.h"
+
+namespace sandbox {
+
+ResultCode ProxyCreateEvent(LPCWSTR name,
+ uint32_t initial_state,
+ EVENT_TYPE event_type,
+ void* ipc_memory,
+ CrossCallReturn* answer) {
+ CountedParameterSet<NameBased> params;
+ params[NameBased::NAME] = ParamPickerMake(name);
+
+ if (!QueryBroker(IpcTag::CREATEEVENT, params.GetBase()))
+ return SBOX_ERROR_GENERIC;
+
+ SharedMemIPCClient ipc(ipc_memory);
+ ResultCode code = CrossCall(ipc, IpcTag::CREATEEVENT, name, event_type,
+ initial_state, answer);
+ return code;
+}
+
+ResultCode ProxyOpenEvent(LPCWSTR name,
+ uint32_t desired_access,
+ void* ipc_memory,
+ CrossCallReturn* answer) {
+ CountedParameterSet<OpenEventParams> params;
+ params[OpenEventParams::NAME] = ParamPickerMake(name);
+ params[OpenEventParams::ACCESS] = ParamPickerMake(desired_access);
+
+ if (!QueryBroker(IpcTag::OPENEVENT, params.GetBase()))
+ return SBOX_ERROR_GENERIC;
+
+ SharedMemIPCClient ipc(ipc_memory);
+ ResultCode code =
+ CrossCall(ipc, IpcTag::OPENEVENT, name, desired_access, answer);
+
+ return code;
+}
+
+NTSTATUS WINAPI TargetNtCreateEvent(NtCreateEventFunction orig_CreateEvent,
+ PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ EVENT_TYPE event_type,
+ BOOLEAN initial_state) {
+ NTSTATUS status =
+ orig_CreateEvent(event_handle, desired_access, object_attributes,
+ event_type, initial_state);
+ if (status != STATUS_ACCESS_DENIED || !object_attributes)
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtCreatEvent",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
+ // The RootDirectory points to BaseNamedObjects. We can ignore it.
+ object_attribs_copy.RootDirectory = nullptr;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes = 0;
+ NTSTATUS ret =
+ AllocAndCopyName(&object_attribs_copy, &name, &attributes, nullptr);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ CrossCallReturn answer = {0};
+ answer.nt_status = status;
+ ResultCode code = ProxyCreateEvent(name.get(), initial_state, event_type,
+ memory, &answer);
+
+ if (code != SBOX_ALL_OK) {
+ status = answer.nt_status;
+ break;
+ }
+ __try {
+ *event_handle = answer.handle;
+ status = STATUS_SUCCESS;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ mozilla::sandboxing::LogAllowed("NtCreateEvent",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+NTSTATUS WINAPI TargetNtOpenEvent(NtOpenEventFunction orig_OpenEvent,
+ PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes) {
+ NTSTATUS status =
+ orig_OpenEvent(event_handle, desired_access, object_attributes);
+ if (status != STATUS_ACCESS_DENIED || !object_attributes)
+ return status;
+
+ mozilla::sandboxing::LogBlocked("NtOpenEvent",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+
+ // We don't trust that the IPC can work this early.
+ if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
+ return status;
+
+ do {
+ if (!ValidParameter(event_handle, sizeof(HANDLE), WRITE))
+ break;
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ break;
+
+ OBJECT_ATTRIBUTES object_attribs_copy = *object_attributes;
+ // The RootDirectory points to BaseNamedObjects. We can ignore it.
+ object_attribs_copy.RootDirectory = nullptr;
+
+ std::unique_ptr<wchar_t, NtAllocDeleter> name;
+ uint32_t attributes = 0;
+ NTSTATUS ret =
+ AllocAndCopyName(&object_attribs_copy, &name, &attributes, nullptr);
+ if (!NT_SUCCESS(ret) || !name)
+ break;
+
+ CrossCallReturn answer = {0};
+ answer.nt_status = status;
+ ResultCode code =
+ ProxyOpenEvent(name.get(), desired_access, memory, &answer);
+
+ if (code != SBOX_ALL_OK) {
+ status = answer.nt_status;
+ break;
+ }
+ __try {
+ *event_handle = answer.handle;
+ status = STATUS_SUCCESS;
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ break;
+ }
+ mozilla::sandboxing::LogAllowed("NtOpenEvent",
+ object_attributes->ObjectName->Buffer,
+ object_attributes->ObjectName->Length);
+ } while (false);
+
+ return status;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_interception.h b/security/sandbox/chromium/sandbox/win/src/sync_interception.h
new file mode 100644
index 0000000000..c21e7ee7b2
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_interception.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SYNC_INTERCEPTION_H_
+#define SANDBOX_WIN_SRC_SYNC_INTERCEPTION_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+typedef NTSTATUS(WINAPI* NtCreateEventFunction)(
+ PHANDLE EventHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes,
+ EVENT_TYPE EventType,
+ BOOLEAN InitialState);
+
+typedef NTSTATUS(WINAPI* NtOpenEventFunction)(
+ PHANDLE EventHandle,
+ ACCESS_MASK DesiredAccess,
+ POBJECT_ATTRIBUTES ObjectAttributes);
+
+// Interceptors for NtCreateEvent/NtOpenEvent
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtCreateEvent(NtCreateEventFunction orig_CreateEvent,
+ PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes,
+ EVENT_TYPE event_type,
+ BOOLEAN initial_state);
+
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtOpenEvent(NtOpenEventFunction orig_OpenEvent,
+ PHANDLE event_handle,
+ ACCESS_MASK desired_access,
+ POBJECT_ATTRIBUTES object_attributes);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SYNC_INTERCEPTION_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_policy.cc b/security/sandbox/chromium/sandbox/win/src/sync_policy.cc
new file mode 100644
index 0000000000..cdc34dd241
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_policy.cc
@@ -0,0 +1,243 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sync_policy.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_engine_opcodes.h"
+#include "sandbox/win/src/policy_params.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sandbox_utils.h"
+#include "sandbox/win/src/sync_interception.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+// Provides functionality to resolve a symbolic link within the object
+// directory passed in.
+NTSTATUS ResolveSymbolicLink(const std::wstring& directory_name,
+ const std::wstring& name,
+ std::wstring* target) {
+ NtOpenDirectoryObjectFunction NtOpenDirectoryObject = nullptr;
+ ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
+
+ NtQuerySymbolicLinkObjectFunction NtQuerySymbolicLinkObject = nullptr;
+ ResolveNTFunctionPtr("NtQuerySymbolicLinkObject", &NtQuerySymbolicLinkObject);
+
+ NtOpenSymbolicLinkObjectFunction NtOpenSymbolicLinkObject = nullptr;
+ ResolveNTFunctionPtr("NtOpenSymbolicLinkObject", &NtOpenSymbolicLinkObject);
+
+ NtCloseFunction NtClose = nullptr;
+ ResolveNTFunctionPtr("NtClose", &NtClose);
+
+ OBJECT_ATTRIBUTES symbolic_link_directory_attributes = {};
+ UNICODE_STRING symbolic_link_directory_string = {};
+ InitObjectAttribs(directory_name, OBJ_CASE_INSENSITIVE, nullptr,
+ &symbolic_link_directory_attributes,
+ &symbolic_link_directory_string, nullptr);
+
+ HANDLE symbolic_link_directory = nullptr;
+ NTSTATUS status =
+ NtOpenDirectoryObject(&symbolic_link_directory, DIRECTORY_QUERY,
+ &symbolic_link_directory_attributes);
+ if (!NT_SUCCESS(status))
+ return status;
+
+ OBJECT_ATTRIBUTES symbolic_link_attributes = {};
+ UNICODE_STRING name_string = {};
+ InitObjectAttribs(name, OBJ_CASE_INSENSITIVE, symbolic_link_directory,
+ &symbolic_link_attributes, &name_string, nullptr);
+
+ HANDLE symbolic_link = nullptr;
+ status = NtOpenSymbolicLinkObject(&symbolic_link, GENERIC_READ,
+ &symbolic_link_attributes);
+ CHECK(NT_SUCCESS(NtClose(symbolic_link_directory)));
+ if (!NT_SUCCESS(status))
+ return status;
+
+ UNICODE_STRING target_path = {};
+ unsigned long target_length = 0;
+ status =
+ NtQuerySymbolicLinkObject(symbolic_link, &target_path, &target_length);
+ if (status != STATUS_BUFFER_TOO_SMALL) {
+ CHECK(NT_SUCCESS(NtClose(symbolic_link)));
+ return status;
+ }
+
+ target_path.Length = 0;
+ target_path.MaximumLength = static_cast<USHORT>(target_length);
+ target_path.Buffer = new wchar_t[target_path.MaximumLength + 1];
+ status =
+ NtQuerySymbolicLinkObject(symbolic_link, &target_path, &target_length);
+ if (NT_SUCCESS(status))
+ target->assign(target_path.Buffer, target_length);
+
+ CHECK(NT_SUCCESS(NtClose(symbolic_link)));
+ delete[] target_path.Buffer;
+ return status;
+}
+
+NTSTATUS GetBaseNamedObjectsDirectory(HANDLE* directory) {
+ static HANDLE base_named_objects_handle = nullptr;
+ if (base_named_objects_handle) {
+ *directory = base_named_objects_handle;
+ return STATUS_SUCCESS;
+ }
+
+ NtOpenDirectoryObjectFunction NtOpenDirectoryObject = nullptr;
+ ResolveNTFunctionPtr("NtOpenDirectoryObject", &NtOpenDirectoryObject);
+
+ DWORD session_id = 0;
+ ProcessIdToSessionId(::GetCurrentProcessId(), &session_id);
+
+ std::wstring base_named_objects_path;
+
+ NTSTATUS status = ResolveSymbolicLink(L"\\Sessions\\BNOLINKS",
+ base::StringPrintf(L"%d", session_id),
+ &base_named_objects_path);
+ if (!NT_SUCCESS(status)) {
+ DLOG(ERROR) << "Failed to resolve BaseNamedObjects path. Error: " << status;
+ return status;
+ }
+
+ UNICODE_STRING directory_name = {};
+ OBJECT_ATTRIBUTES object_attributes = {};
+ InitObjectAttribs(base_named_objects_path, OBJ_CASE_INSENSITIVE, nullptr,
+ &object_attributes, &directory_name, nullptr);
+ status = NtOpenDirectoryObject(&base_named_objects_handle,
+ DIRECTORY_ALL_ACCESS, &object_attributes);
+ if (NT_SUCCESS(status))
+ *directory = base_named_objects_handle;
+ return status;
+}
+
+bool SyncPolicy::GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy) {
+ std::wstring mod_name(name);
+ if (mod_name.empty()) {
+ return false;
+ }
+
+ if (TargetPolicy::EVENTS_ALLOW_ANY != semantics &&
+ TargetPolicy::EVENTS_ALLOW_READONLY != semantics) {
+ // Other flags are not valid for sync policy yet.
+ NOTREACHED();
+ return false;
+ }
+
+ // Add the open rule.
+ EvalResult result = ASK_BROKER;
+ PolicyRule open(result);
+
+ if (!open.AddStringMatch(IF, OpenEventParams::NAME, name, CASE_INSENSITIVE))
+ return false;
+
+ if (TargetPolicy::EVENTS_ALLOW_READONLY == semantics) {
+ // We consider all flags that are not known to be readonly as potentially
+ // used for write.
+ uint32_t allowed_flags = SYNCHRONIZE | GENERIC_READ | READ_CONTROL;
+ uint32_t restricted_flags = ~allowed_flags;
+ open.AddNumberMatch(IF_NOT, OpenEventParams::ACCESS, restricted_flags, AND);
+ }
+
+ if (!policy->AddRule(IpcTag::OPENEVENT, &open))
+ return false;
+
+ // If it's not a read only, add the create rule.
+ if (TargetPolicy::EVENTS_ALLOW_READONLY != semantics) {
+ PolicyRule create(result);
+ if (!create.AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE))
+ return false;
+
+ if (!policy->AddRule(IpcTag::CREATEEVENT, &create))
+ return false;
+ }
+
+ return true;
+}
+
+NTSTATUS SyncPolicy::CreateEventAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& event_name,
+ uint32_t event_type,
+ uint32_t initial_state,
+ HANDLE* handle) {
+ NtCreateEventFunction NtCreateEvent = nullptr;
+ ResolveNTFunctionPtr("NtCreateEvent", &NtCreateEvent);
+
+ // The only action supported is ASK_BROKER which means create the requested
+ // file as specified.
+ if (ASK_BROKER != eval_result)
+ return false;
+
+ HANDLE object_directory = nullptr;
+ NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
+ if (status != STATUS_SUCCESS)
+ return status;
+
+ UNICODE_STRING unicode_event_name = {};
+ OBJECT_ATTRIBUTES object_attributes = {};
+ InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
+ &object_attributes, &unicode_event_name, nullptr);
+
+ HANDLE local_handle = nullptr;
+ status = NtCreateEvent(&local_handle, EVENT_ALL_ACCESS, &object_attributes,
+ static_cast<EVENT_TYPE>(event_type),
+ static_cast<BOOLEAN>(initial_state != 0));
+ if (!local_handle)
+ return status;
+
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ return status;
+}
+
+NTSTATUS SyncPolicy::OpenEventAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& event_name,
+ uint32_t desired_access,
+ HANDLE* handle) {
+ NtOpenEventFunction NtOpenEvent = nullptr;
+ ResolveNTFunctionPtr("NtOpenEvent", &NtOpenEvent);
+
+ // The only action supported is ASK_BROKER which means create the requested
+ // event as specified.
+ if (ASK_BROKER != eval_result)
+ return false;
+
+ HANDLE object_directory = nullptr;
+ NTSTATUS status = GetBaseNamedObjectsDirectory(&object_directory);
+ if (status != STATUS_SUCCESS)
+ return status;
+
+ UNICODE_STRING unicode_event_name = {};
+ OBJECT_ATTRIBUTES object_attributes = {};
+ InitObjectAttribs(event_name, OBJ_CASE_INSENSITIVE, object_directory,
+ &object_attributes, &unicode_event_name, nullptr);
+
+ HANDLE local_handle = nullptr;
+ status = NtOpenEvent(&local_handle, desired_access, &object_attributes);
+ if (!local_handle)
+ return status;
+
+ if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
+ client_info.process, handle, 0, false,
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
+ return STATUS_ACCESS_DENIED;
+ }
+ return status;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_policy.h b/security/sandbox/chromium/sandbox/win/src/sync_policy.h
new file mode 100644
index 0000000000..2eb4124a82
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_policy.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_SYNC_POLICY_H__
+#define SANDBOX_SRC_SYNC_POLICY_H__
+
+#include <stdint.h>
+
+#include <string>
+
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace sandbox {
+
+// This class centralizes most of the knowledge related to sync policy
+class SyncPolicy {
+ public:
+ // Creates the required low-level policy rules to evaluate a high-level
+ // policy rule for sync calls, in particular open or create actions.
+ // name is the sync object name, semantics is the desired semantics for the
+ // open or create and policy is the policy generator to which the rules are
+ // going to be added.
+ static bool GenerateRules(const wchar_t* name,
+ TargetPolicy::Semantics semantics,
+ LowLevelPolicy* policy);
+
+ // Performs the desired policy action on a request.
+ // client_info is the target process that is making the request and
+ // eval_result is the desired policy action to accomplish.
+ static NTSTATUS CreateEventAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& event_name,
+ uint32_t event_type,
+ uint32_t initial_state,
+ HANDLE* handle);
+ static NTSTATUS OpenEventAction(EvalResult eval_result,
+ const ClientInfo& client_info,
+ const std::wstring& event_name,
+ uint32_t desired_access,
+ HANDLE* handle);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_SYNC_POLICY_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_policy_test.cc b/security/sandbox/chromium/sandbox/win/src/sync_policy_test.cc
new file mode 100644
index 0000000000..97f60d359f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_policy_test.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/sync_policy_test.h"
+
+#include "base/win/scoped_handle.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+SBOX_TESTS_COMMAND int Event_Open(int argc, wchar_t** argv) {
+ if (argc != 2)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ DWORD desired_access = SYNCHRONIZE;
+ if (L'f' == argv[0][0])
+ desired_access = EVENT_ALL_ACCESS;
+
+ base::win::ScopedHandle event_open(
+ ::OpenEvent(desired_access, false, argv[1]));
+ DWORD error_open = ::GetLastError();
+
+ if (event_open.IsValid())
+ return SBOX_TEST_SUCCEEDED;
+
+ if (ERROR_ACCESS_DENIED == error_open || ERROR_BAD_PATHNAME == error_open ||
+ ERROR_FILE_NOT_FOUND == error_open)
+ return SBOX_TEST_DENIED;
+
+ return SBOX_TEST_FAILED;
+}
+
+SBOX_TESTS_COMMAND int Event_CreateOpen(int argc, wchar_t** argv) {
+ if (argc < 2 || argc > 3)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ wchar_t* event_name = nullptr;
+ if (3 == argc)
+ event_name = argv[2];
+
+ bool manual_reset = false;
+ bool initial_state = false;
+ if (L't' == argv[0][0])
+ manual_reset = true;
+ if (L't' == argv[1][0])
+ initial_state = true;
+
+ base::win::ScopedHandle event_create(
+ ::CreateEvent(nullptr, manual_reset, initial_state, event_name));
+ DWORD error_create = ::GetLastError();
+ base::win::ScopedHandle event_open;
+ if (event_name)
+ event_open.Set(::OpenEvent(EVENT_ALL_ACCESS, false, event_name));
+
+ if (event_create.IsValid()) {
+ DWORD wait = ::WaitForSingleObject(event_create.Get(), 0);
+ if (initial_state && WAIT_OBJECT_0 != wait)
+ return SBOX_TEST_FAILED;
+
+ if (!initial_state && WAIT_TIMEOUT != wait)
+ return SBOX_TEST_FAILED;
+ }
+
+ if (event_name) {
+ // Both event_open and event_create have to be valid.
+ if (event_open.IsValid() && event_create.IsValid())
+ return SBOX_TEST_SUCCEEDED;
+
+ if ((event_open.IsValid() && !event_create.IsValid()) ||
+ (!event_open.IsValid() && event_create.IsValid())) {
+ return SBOX_TEST_FAILED;
+ }
+ } else {
+ // Only event_create has to be valid.
+ if (event_create.Get())
+ return SBOX_TEST_SUCCEEDED;
+ }
+
+ if (ERROR_ACCESS_DENIED == error_create || ERROR_BAD_PATHNAME == error_create)
+ return SBOX_TEST_DENIED;
+
+ return SBOX_TEST_FAILED;
+}
+
+// Tests the creation of events using all the possible combinations.
+TEST(SyncPolicyTest, TestEvent) {
+ TestRunner runner;
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_ANY, L"test1"));
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_ANY, L"test2"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f t"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t t"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f test1"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f test2"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f t test1"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t t test2"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f f test3"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t f test4"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f t test3"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t t test4"));
+}
+
+// Tests opening events with read only access.
+TEST(SyncPolicyTest, TestEventReadOnly) {
+ TestRunner runner;
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_READONLY, L"test1"));
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_READONLY, L"test2"));
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_READONLY, L"test5"));
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_READONLY, L"test6"));
+
+ base::win::ScopedHandle handle1(
+ ::CreateEvent(nullptr, false, false, L"test1"));
+ base::win::ScopedHandle handle2(
+ ::CreateEvent(nullptr, false, false, L"test2"));
+ base::win::ScopedHandle handle3(
+ ::CreateEvent(nullptr, false, false, L"test3"));
+ base::win::ScopedHandle handle4(
+ ::CreateEvent(nullptr, false, false, L"test4"));
+
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen f f"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_CreateOpen t f"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test1"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"Event_Open s test2"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open f test3"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_Open s test4"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f f test5"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t f test6"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen f t test5"));
+ EXPECT_EQ(SBOX_TEST_DENIED, runner.RunTest(L"Event_CreateOpen t t test6"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_policy_test.h b/security/sandbox/chromium/sandbox/win/src/sync_policy_test.h
new file mode 100644
index 0000000000..4f354b35be
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/sync_policy_test.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
+#define SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
+
+#include "sandbox/win/tests/common/controller.h"
+
+namespace sandbox {
+
+// Opens the named event received on argv[1]. The requested access is
+// EVENT_ALL_ACCESS if argv[0] starts with 'f', or SYNCHRONIZE otherwise.
+SBOX_TESTS_COMMAND int Event_Open(int argc, wchar_t **argv);
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_SYNC_POLICY_TEST_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/target_interceptions.cc b/security/sandbox/chromium/sandbox/win/src/target_interceptions.cc
new file mode 100644
index 0000000000..1b467814c6
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/target_interceptions.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/target_interceptions.h"
+
+#include "base/win/static_constants.h"
+#include "sandbox/win/src/interception_agent.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace sandbox {
+
+SANDBOX_INTERCEPT NtExports g_nt;
+
+const char KERNEL32_DLL_NAME[] = "kernel32.dll";
+
+enum SectionLoadState {
+ kBeforeKernel32,
+ kAfterKernel32,
+};
+
+// Hooks NtMapViewOfSection to detect the load of DLLs. If hot patching is
+// required for this dll, this functions patches it.
+NTSTATUS WINAPI
+TargetNtMapViewOfSection(NtMapViewOfSectionFunction orig_MapViewOfSection,
+ HANDLE section,
+ HANDLE process,
+ PVOID* base,
+ ULONG_PTR zero_bits,
+ SIZE_T commit_size,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size,
+ SECTION_INHERIT inherit,
+ ULONG allocation_type,
+ ULONG protect) {
+ NTSTATUS ret = orig_MapViewOfSection(section, process, base, zero_bits,
+ commit_size, offset, view_size, inherit,
+ allocation_type, protect);
+ static SectionLoadState s_state = kBeforeKernel32;
+
+ do {
+ if (!NT_SUCCESS(ret))
+ break;
+
+ if (!IsSameProcess(process))
+ break;
+
+ // Only check for verifier.dll or kernel32.dll loading if we haven't moved
+ // past that state yet.
+ if (s_state == kBeforeKernel32) {
+ const char* ansi_module_name =
+ GetAnsiImageInfoFromModule(reinterpret_cast<HMODULE>(*base));
+
+ // _strnicmp below may hit read access violations for some sections. We
+ // find what looks like a valid export directory for a PE module but the
+ // pointer to the module name will be pointing to invalid memory.
+ __try {
+ // Don't initialize the heap if verifier.dll is being loaded. This
+ // indicates Application Verifier is enabled and we should wait until
+ // the next module is loaded.
+ if (ansi_module_name &&
+ (g_nt._strnicmp(
+ ansi_module_name, base::win::kApplicationVerifierDllName,
+ g_nt.strlen(base::win::kApplicationVerifierDllName) + 1) == 0))
+ break;
+
+ if (ansi_module_name &&
+ (g_nt._strnicmp(ansi_module_name, KERNEL32_DLL_NAME,
+ sizeof(KERNEL32_DLL_NAME)) == 0)) {
+ s_state = kAfterKernel32;
+ }
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ }
+ }
+
+ if (!InitHeap())
+ break;
+
+ if (!IsValidImageSection(section, base, offset, view_size))
+ break;
+
+ UINT image_flags;
+ UNICODE_STRING* module_name =
+ GetImageInfoFromModule(reinterpret_cast<HMODULE>(*base), &image_flags);
+ UNICODE_STRING* file_name = GetBackingFilePath(*base);
+
+ if ((!module_name) && (image_flags & MODULE_HAS_CODE)) {
+ // If the module has no exports we retrieve the module name from the
+ // full path of the mapped section.
+ module_name = ExtractModuleName(file_name);
+ }
+
+ InterceptionAgent* agent = InterceptionAgent::GetInterceptionAgent();
+
+ if (agent) {
+ if (!agent->OnDllLoad(file_name, module_name, *base)) {
+ // Interception agent is demanding to un-map the module.
+ g_nt.UnmapViewOfSection(process, *base);
+ *base = nullptr;
+ ret = STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (module_name)
+ operator delete(module_name, NT_ALLOC);
+
+ if (file_name)
+ operator delete(file_name, NT_ALLOC);
+
+ } while (false);
+
+ return ret;
+}
+
+NTSTATUS WINAPI
+TargetNtUnmapViewOfSection(NtUnmapViewOfSectionFunction orig_UnmapViewOfSection,
+ HANDLE process,
+ PVOID base) {
+ NTSTATUS ret = orig_UnmapViewOfSection(process, base);
+
+ if (!NT_SUCCESS(ret))
+ return ret;
+
+ if (!IsSameProcess(process))
+ return ret;
+
+ InterceptionAgent* agent = InterceptionAgent::GetInterceptionAgent();
+
+ if (agent)
+ agent->OnDllUnload(base);
+
+ return ret;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/target_interceptions.h b/security/sandbox/chromium/sandbox/win/src/target_interceptions.h
new file mode 100644
index 0000000000..fac1c65c27
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/target_interceptions.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_TARGET_INTERCEPTIONS_H_
+#define SANDBOX_WIN_SRC_TARGET_INTERCEPTIONS_H_
+
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+extern "C" {
+
+// Interception of NtMapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being loaded, so we can patch them if needed.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtMapViewOfSection(NtMapViewOfSectionFunction orig_MapViewOfSection,
+ HANDLE section,
+ HANDLE process,
+ PVOID* base,
+ ULONG_PTR zero_bits,
+ SIZE_T commit_size,
+ PLARGE_INTEGER offset,
+ PSIZE_T view_size,
+ SECTION_INHERIT inherit,
+ ULONG allocation_type,
+ ULONG protect);
+
+// Interception of NtUnmapViewOfSection on the child process.
+// It should never be called directly. This function provides the means to
+// detect dlls being unloaded, so we can clean up our interceptions.
+SANDBOX_INTERCEPT NTSTATUS WINAPI
+TargetNtUnmapViewOfSection(NtUnmapViewOfSectionFunction orig_UnmapViewOfSection,
+ HANDLE process,
+ PVOID base);
+
+} // extern "C"
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_TARGET_INTERCEPTIONS_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/target_process.cc b/security/sandbox/chromium/sandbox/win/src/target_process.cc
new file mode 100644
index 0000000000..4661267d1e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/target_process.cc
@@ -0,0 +1,393 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/target_process.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/free_deleter.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/process/environment_internal.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/policy_low_level.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/security_capabilities.h"
+#include "sandbox/win/src/sharedmem_ipc_server.h"
+#include "sandbox/win/src/sid.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+namespace {
+
+void CopyPolicyToTarget(const void* source, size_t size, void* dest) {
+ if (!source || !size)
+ return;
+ memcpy(dest, source, size);
+ sandbox::PolicyGlobal* policy =
+ reinterpret_cast<sandbox::PolicyGlobal*>(dest);
+
+ size_t offset = reinterpret_cast<size_t>(source);
+
+ for (size_t i = 0; i < sandbox::kMaxServiceCount; i++) {
+ size_t buffer = reinterpret_cast<size_t>(policy->entry[i]);
+ if (buffer) {
+ buffer -= offset;
+ policy->entry[i] = reinterpret_cast<sandbox::PolicyBuffer*>(buffer);
+ }
+ }
+}
+
+bool GetTokenAppContainerSid(HANDLE token_handle,
+ std::unique_ptr<Sid>* app_container_sid) {
+ std::vector<char> app_container_info(sizeof(TOKEN_APPCONTAINER_INFORMATION) +
+ SECURITY_MAX_SID_SIZE);
+ DWORD return_length;
+
+ if (!::GetTokenInformation(
+ token_handle, TokenAppContainerSid, app_container_info.data(),
+ base::checked_cast<DWORD>(app_container_info.size()),
+ &return_length)) {
+ return false;
+ }
+
+ PTOKEN_APPCONTAINER_INFORMATION info =
+ reinterpret_cast<PTOKEN_APPCONTAINER_INFORMATION>(
+ app_container_info.data());
+ if (!info->TokenAppContainer)
+ return false;
+ *app_container_sid = std::unique_ptr<Sid>(new Sid(info->TokenAppContainer));
+ return true;
+}
+
+bool GetProcessAppContainerSid(HANDLE process,
+ std::unique_ptr<Sid>* app_container_sid) {
+ HANDLE token_handle;
+ if (!::OpenProcessToken(process, TOKEN_QUERY, &token_handle))
+ return false;
+ base::win::ScopedHandle process_token(token_handle);
+
+ return GetTokenAppContainerSid(process_token.Get(), app_container_sid);
+}
+
+bool GetAppContainerImpersonationToken(
+ HANDLE process,
+ HANDLE initial_token,
+ const std::vector<Sid>& capabilities,
+ base::win::ScopedHandle* impersonation_token) {
+ std::unique_ptr<Sid> app_container_sid;
+ if (!GetProcessAppContainerSid(process, &app_container_sid)) {
+ return false;
+ }
+ SecurityCapabilities security_caps(*app_container_sid, capabilities);
+ return CreateLowBoxToken(initial_token, IMPERSONATION, &security_caps,
+ nullptr, 0, impersonation_token) == ERROR_SUCCESS;
+}
+
+} // namespace
+
+SANDBOX_INTERCEPT HANDLE g_shared_section;
+SANDBOX_INTERCEPT size_t g_shared_IPC_size;
+SANDBOX_INTERCEPT size_t g_shared_policy_size;
+
+TargetProcess::TargetProcess(base::win::ScopedHandle initial_token,
+ base::win::ScopedHandle lockdown_token,
+ HANDLE job,
+ ThreadProvider* thread_pool,
+ const std::vector<Sid>& impersonation_capabilities)
+ // This object owns everything initialized here except thread_pool and
+ // the job_ handle. The Job handle is closed by BrokerServices and results
+ // eventually in a call to our dtor.
+ : lockdown_token_(std::move(lockdown_token)),
+ initial_token_(std::move(initial_token)),
+ job_(job),
+ thread_pool_(thread_pool),
+ base_address_(nullptr),
+ impersonation_capabilities_(impersonation_capabilities) {}
+
+TargetProcess::~TargetProcess() {
+ // Give a chance to the process to die. In most cases the JOB_KILL_ON_CLOSE
+ // will take effect only when the context changes. As far as the testing went,
+ // this wait was enough to switch context and kill the processes in the job.
+ // If this process is already dead, the function will return without waiting.
+ // For now, this wait is there only to do a best effort to prevent some leaks
+ // from showing up in purify.
+ if (sandbox_process_info_.IsValid()) {
+ ::WaitForSingleObject(sandbox_process_info_.process_handle(), 50);
+ // Terminate the process if it's still alive, as its IPC server is going
+ // away. 1 is RESULT_CODE_KILLED.
+ ::TerminateProcess(sandbox_process_info_.process_handle(), 1);
+ }
+
+ // ipc_server_ references our process handle, so make sure the former is shut
+ // down before the latter is closed (by ScopedProcessInformation).
+ ipc_server_.reset();
+}
+
+// Creates the target (child) process suspended and assigns it to the job
+// object.
+ResultCode TargetProcess::Create(
+ const wchar_t* exe_path,
+ const wchar_t* command_line,
+ bool inherit_handles,
+ const base::win::StartupInformation& startup_info,
+ base::win::ScopedProcessInformation* target_info,
+ base::EnvironmentMap& env_changes,
+ DWORD* win_error) {
+ exe_name_.reset(_wcsdup(exe_path));
+
+ // the command line needs to be writable by CreateProcess().
+ std::unique_ptr<wchar_t, base::FreeDeleter> cmd_line(_wcsdup(command_line));
+
+ // Start the target process suspended.
+ DWORD flags =
+ CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS;
+
+ if (startup_info.has_extended_startup_info())
+ flags |= EXTENDED_STARTUPINFO_PRESENT;
+
+ if (job_ && base::win::GetVersion() < base::win::Version::WIN8) {
+ // Windows 8 implements nested jobs, but for older systems we need to
+ // break out of any job we're in to enforce our restrictions.
+ flags |= CREATE_BREAKAWAY_FROM_JOB;
+ }
+
+ LPTCH original_environment = GetEnvironmentStrings();
+ base::NativeEnvironmentString new_environment =
+ base::internal::AlterEnvironment(original_environment, env_changes);
+ // Ignore return value? What can we do?
+ FreeEnvironmentStrings(original_environment);
+ LPVOID new_env_ptr = (void*)new_environment.data();
+
+ PROCESS_INFORMATION temp_process_info = {};
+ if (!::CreateProcessAsUserW(lockdown_token_.Get(), exe_path, cmd_line.get(),
+ nullptr, // No security attribute.
+ nullptr, // No thread attribute.
+ inherit_handles, flags,
+ new_env_ptr,
+ nullptr, // Use current directory of the caller.
+ startup_info.startup_info(),
+ &temp_process_info)) {
+ *win_error = ::GetLastError();
+ return SBOX_ERROR_CREATE_PROCESS;
+ }
+ base::win::ScopedProcessInformation process_info(temp_process_info);
+
+ if (job_) {
+ // Assign the suspended target to the windows job object.
+ if (!::AssignProcessToJobObject(job_, process_info.process_handle())) {
+ *win_error = ::GetLastError();
+ ::TerminateProcess(process_info.process_handle(), 0);
+ return SBOX_ERROR_ASSIGN_PROCESS_TO_JOB_OBJECT;
+ }
+ }
+
+ if (initial_token_.IsValid()) {
+ HANDLE impersonation_token = initial_token_.Get();
+ base::win::ScopedHandle app_container_token;
+ if (GetAppContainerImpersonationToken(
+ process_info.process_handle(), impersonation_token,
+ impersonation_capabilities_, &app_container_token)) {
+ impersonation_token = app_container_token.Get();
+ }
+
+ // Change the token of the main thread of the new process for the
+ // impersonation token with more rights. This allows the target to start;
+ // otherwise it will crash too early for us to help.
+ HANDLE temp_thread = process_info.thread_handle();
+ if (!::SetThreadToken(&temp_thread, impersonation_token)) {
+ *win_error = ::GetLastError();
+ ::TerminateProcess(process_info.process_handle(), 0);
+ return SBOX_ERROR_SET_THREAD_TOKEN;
+ }
+ initial_token_.Close();
+ }
+
+ if (!target_info->DuplicateFrom(process_info)) {
+ *win_error = ::GetLastError(); // This may or may not be correct.
+ ::TerminateProcess(process_info.process_handle(), 0);
+ return SBOX_ERROR_DUPLICATE_TARGET_INFO;
+ }
+
+ base_address_ = GetProcessBaseAddress(process_info.process_handle());
+ DCHECK(base_address_);
+ if (!base_address_) {
+ *win_error = ::GetLastError();
+ ::TerminateProcess(process_info.process_handle(), 0);
+ return SBOX_ERROR_CANNOT_FIND_BASE_ADDRESS;
+ }
+
+ sandbox_process_info_.Set(process_info.Take());
+ return SBOX_ALL_OK;
+}
+
+ResultCode TargetProcess::TransferVariable(const char* name,
+ void* address,
+ size_t size) {
+ if (!sandbox_process_info_.IsValid())
+ return SBOX_ERROR_UNEXPECTED_CALL;
+
+ void* child_var = address;
+
+#if SANDBOX_EXPORTS
+ HMODULE module = ::LoadLibrary(exe_name_.get());
+ if (!module)
+ return SBOX_ERROR_CANNOT_LOADLIBRARY_EXECUTABLE;
+
+ child_var = reinterpret_cast<void*>(::GetProcAddress(module, name));
+ ::FreeLibrary(module);
+
+ if (!child_var)
+ return SBOX_ERROR_CANNOT_FIND_VARIABLE_ADDRESS;
+
+ size_t offset =
+ reinterpret_cast<char*>(child_var) - reinterpret_cast<char*>(module);
+ child_var = reinterpret_cast<char*>(MainModule()) + offset;
+#endif
+
+ SIZE_T written;
+ if (!::WriteProcessMemory(sandbox_process_info_.process_handle(), child_var,
+ address, size, &written))
+ return SBOX_ERROR_CANNOT_WRITE_VARIABLE_VALUE;
+
+ if (written != size)
+ return SBOX_ERROR_INVALID_WRITE_VARIABLE_SIZE;
+
+ return SBOX_ALL_OK;
+}
+
+// Construct the IPC server and the IPC dispatcher. When the target does
+// an IPC it will eventually call the dispatcher.
+ResultCode TargetProcess::Init(Dispatcher* ipc_dispatcher,
+ void* policy,
+ uint32_t shared_IPC_size,
+ uint32_t shared_policy_size,
+ DWORD* win_error) {
+ // We need to map the shared memory on the target. This is necessary for
+ // any IPC that needs to take place, even if the target has not yet hit
+ // the main( ) function or even has initialized the CRT. So here we set
+ // the handle to the shared section. The target on the first IPC must do
+ // the rest, which boils down to calling MapViewofFile()
+
+ // We use this single memory pool for IPC and for policy.
+ DWORD shared_mem_size =
+ static_cast<DWORD>(shared_IPC_size + shared_policy_size);
+ shared_section_.Set(::CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr,
+ PAGE_READWRITE | SEC_COMMIT, 0,
+ shared_mem_size, nullptr));
+ if (!shared_section_.IsValid()) {
+ *win_error = ::GetLastError();
+ return SBOX_ERROR_CREATE_FILE_MAPPING;
+ }
+
+ void* shared_memory = ::MapViewOfFile(
+ shared_section_.Get(), FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);
+ if (!shared_memory) {
+ *win_error = ::GetLastError();
+ return SBOX_ERROR_MAP_VIEW_OF_SHARED_SECTION;
+ }
+
+ CopyPolicyToTarget(policy, shared_policy_size,
+ reinterpret_cast<char*>(shared_memory) + shared_IPC_size);
+
+ ResultCode ret;
+ // Set the global variables in the target. These are not used on the broker.
+ g_shared_IPC_size = shared_IPC_size;
+ ret = TransferVariable("g_shared_IPC_size", &g_shared_IPC_size,
+ sizeof(g_shared_IPC_size));
+ g_shared_IPC_size = 0;
+ if (SBOX_ALL_OK != ret) {
+ *win_error = ::GetLastError();
+ return ret;
+ }
+ g_shared_policy_size = shared_policy_size;
+ ret = TransferVariable("g_shared_policy_size", &g_shared_policy_size,
+ sizeof(g_shared_policy_size));
+ g_shared_policy_size = 0;
+ if (SBOX_ALL_OK != ret) {
+ *win_error = ::GetLastError();
+ return ret;
+ }
+
+ ipc_server_.reset(new SharedMemIPCServer(
+ sandbox_process_info_.process_handle(),
+ sandbox_process_info_.process_id(), thread_pool_, ipc_dispatcher));
+
+ if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize))
+ return SBOX_ERROR_NO_SPACE;
+
+ DWORD access = FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY;
+ HANDLE target_shared_section;
+ if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_.Get(),
+ sandbox_process_info_.process_handle(),
+ &target_shared_section, access, false, 0)) {
+ *win_error = ::GetLastError();
+ return SBOX_ERROR_DUPLICATE_SHARED_SECTION;
+ }
+
+ g_shared_section = target_shared_section;
+ ret = TransferVariable("g_shared_section", &g_shared_section,
+ sizeof(g_shared_section));
+ g_shared_section = nullptr;
+ if (SBOX_ALL_OK != ret) {
+ *win_error = ::GetLastError();
+ return ret;
+ }
+
+ // After this point we cannot use this handle anymore.
+ ::CloseHandle(sandbox_process_info_.TakeThreadHandle());
+
+ return SBOX_ALL_OK;
+}
+
+void TargetProcess::Terminate() {
+ if (!sandbox_process_info_.IsValid())
+ return;
+
+ ::TerminateProcess(sandbox_process_info_.process_handle(), 0);
+}
+
+ResultCode TargetProcess::AssignLowBoxToken(
+ const base::win::ScopedHandle& token) {
+ if (!token.IsValid())
+ return SBOX_ALL_OK;
+ PROCESS_ACCESS_TOKEN process_access_token = {};
+ process_access_token.token = token.Get();
+
+ NtSetInformationProcess SetInformationProcess = nullptr;
+ ResolveNTFunctionPtr("NtSetInformationProcess", &SetInformationProcess);
+
+ NTSTATUS status = SetInformationProcess(
+ sandbox_process_info_.process_handle(),
+ static_cast<PROCESS_INFORMATION_CLASS>(NtProcessInformationAccessToken),
+ &process_access_token, sizeof(process_access_token));
+ if (!NT_SUCCESS(status)) {
+ ::SetLastError(GetLastErrorFromNtStatus(status));
+ return SBOX_ERROR_SET_LOW_BOX_TOKEN;
+ }
+ return SBOX_ALL_OK;
+}
+
+TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) {
+ TargetProcess* target =
+ new TargetProcess(base::win::ScopedHandle(), base::win::ScopedHandle(),
+ nullptr, nullptr, std::vector<Sid>());
+ PROCESS_INFORMATION process_info = {};
+ process_info.hProcess = process;
+ target->sandbox_process_info_.Set(process_info);
+ target->base_address_ = base_address;
+ return target;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/target_process.h b/security/sandbox/chromium/sandbox/win/src/target_process.h
new file mode 100644
index 0000000000..c489ed7bc1
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/target_process.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_WIN_SRC_TARGET_PROCESS_H_
+#define SANDBOX_WIN_SRC_TARGET_PROCESS_H_
+
+#include <windows.h>
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/environment.h"
+#include "base/memory/free_deleter.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace base {
+namespace win {
+
+class StartupInformation;
+
+} // namespace win
+} // namespace base
+
+namespace sandbox {
+
+class SharedMemIPCServer;
+class Sid;
+class ThreadProvider;
+
+// TargetProcess models a target instance (child process). Objects of this
+// class are owned by the Policy used to create them.
+class TargetProcess {
+ public:
+ // The constructor takes ownership of |initial_token| and |lockdown_token|
+ TargetProcess(base::win::ScopedHandle initial_token,
+ base::win::ScopedHandle lockdown_token,
+ HANDLE job,
+ ThreadProvider* thread_pool,
+ const std::vector<Sid>& impersonation_capabilities);
+ ~TargetProcess();
+
+ // TODO(cpu): Currently there does not seem to be a reason to implement
+ // reference counting for this class since is internal, but kept the
+ // the same interface so the interception framework does not need to be
+ // touched at this point.
+ void AddRef() {}
+ void Release() {}
+
+ // Creates the new target process. The process is created suspended.
+ ResultCode Create(const wchar_t* exe_path,
+ const wchar_t* command_line,
+ bool inherit_handles,
+ const base::win::StartupInformation& startup_info,
+ base::win::ScopedProcessInformation* target_info,
+ base::EnvironmentMap& env_map,
+ DWORD* win_error);
+
+ // Assign a new lowbox token to the process post creation. The process
+ // must still be in its initial suspended state, however this still
+ // might fail in the presence of third-party software.
+ ResultCode AssignLowBoxToken(const base::win::ScopedHandle& token);
+
+ // Destroys the target process.
+ void Terminate();
+
+ // Creates the IPC objects such as the BrokerDispatcher and the
+ // IPC server. The IPC server uses the services of the thread_pool.
+ ResultCode Init(Dispatcher* ipc_dispatcher,
+ void* policy,
+ uint32_t shared_IPC_size,
+ uint32_t shared_policy_size,
+ DWORD* win_error);
+
+ // Returns the handle to the target process.
+ HANDLE Process() const { return sandbox_process_info_.process_handle(); }
+
+ // Returns the handle to the job object that the target process belongs to.
+ HANDLE Job() const { return job_; }
+
+ // Returns the address of the target main exe. This is used by the
+ // interceptions framework.
+ HMODULE MainModule() const {
+ return reinterpret_cast<HMODULE>(base_address_);
+ }
+
+ // Returns the name of the executable.
+ const wchar_t* Name() const { return exe_name_.get(); }
+
+ // Returns the process id.
+ DWORD ProcessId() const { return sandbox_process_info_.process_id(); }
+
+ // Returns the handle to the main thread.
+ HANDLE MainThread() const { return sandbox_process_info_.thread_handle(); }
+
+ // Transfers variable at |address| of |size| bytes from broker to target.
+ ResultCode TransferVariable(const char* name, void* address, size_t size);
+
+ private:
+ // Details of the target process.
+ base::win::ScopedProcessInformation sandbox_process_info_;
+ // The token associated with the process. It provides the core of the
+ // sbox security.
+ base::win::ScopedHandle lockdown_token_;
+ // The token given to the initial thread so that the target process can
+ // start. It has more powers than the lockdown_token.
+ base::win::ScopedHandle initial_token_;
+ // Kernel handle to the shared memory used by the IPC server.
+ base::win::ScopedHandle shared_section_;
+ // Job object containing the target process.
+ HANDLE job_;
+ // Reference to the IPC subsystem.
+ std::unique_ptr<SharedMemIPCServer> ipc_server_;
+ // Provides the threads used by the IPC. This class does not own this pointer.
+ ThreadProvider* thread_pool_;
+ // Base address of the main executable
+ void* base_address_;
+ // Full name of the target executable.
+ std::unique_ptr<wchar_t, base::FreeDeleter> exe_name_;
+ /// List of capability sids for use when impersonating in an AC process.
+ std::vector<Sid> impersonation_capabilities_;
+
+ // Function used for testing.
+ friend TargetProcess* MakeTestTargetProcess(HANDLE process,
+ HMODULE base_address);
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(TargetProcess);
+};
+
+// Creates a mock TargetProcess used for testing interceptions.
+// TODO(cpu): It seems that this method is not going to be used anymore.
+TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address);
+
+} // namespace sandbox
+
+#endif // SANDBOX_WIN_SRC_TARGET_PROCESS_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.cc b/security/sandbox/chromium/sandbox/win/src/target_services.cc
new file mode 100644
index 0000000000..a80e0106ef
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/target_services.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/target_services.h"
+
+#include <new>
+
+#include <process.h>
+#include <stdint.h>
+
+#include "base/win/windows_version.h"
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/handle_closer_agent.h"
+#include "sandbox/win/src/handle_interception.h"
+#include "sandbox/win/src/heap_helper.h"
+#include "sandbox/win/src/line_break_interception.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/process_mitigations.h"
+#include "sandbox/win/src/restricted_token_utils.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sandbox_types.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+
+namespace sandbox {
+namespace {
+
+// Flushing a cached key is triggered by just opening the key and closing the
+// resulting handle. RegDisablePredefinedCache() is the documented way to flush
+// HKCU so do not use it with this function.
+bool FlushRegKey(HKEY root) {
+ HKEY key;
+ if (ERROR_SUCCESS ==
+ ::RegOpenKeyExW(root, nullptr, 0, MAXIMUM_ALLOWED, &key)) {
+ if (ERROR_SUCCESS != ::RegCloseKey(key))
+ return false;
+ }
+ return true;
+}
+
+// This function forces advapi32.dll to release some internally cached handles
+// that were made during calls to RegOpenkey and RegOpenKeyEx if it is called
+// with a more restrictive token. Returns true if the flushing is succesful
+// although this behavior is undocumented and there is no guarantee that in
+// fact this will happen in future versions of windows.
+bool FlushCachedRegHandles() {
+ return (FlushRegKey(HKEY_LOCAL_MACHINE) && FlushRegKey(HKEY_CLASSES_ROOT) &&
+ FlushRegKey(HKEY_USERS));
+}
+
+// Cleans up this process if CSRSS will be disconnected, as this disconnection
+// is not supported Windows behavior.
+// Currently, this step requires closing a heap that this shared with csrss.exe.
+// Closing the ALPC Port handle to csrss.exe leaves this heap in an invalid
+// state. This causes problems if anyone enumerates the heap.
+bool CsrssDisconnectCleanup() {
+ HANDLE csr_port_heap = FindCsrPortHeap();
+ if (!csr_port_heap) {
+ DLOG(ERROR) << "Failed to find CSR Port heap handle";
+ return false;
+ }
+ HeapDestroy(csr_port_heap);
+ return true;
+}
+
+// Used by EnumSystemLocales for warming up.
+static BOOL CALLBACK EnumLocalesProcEx(LPWSTR lpLocaleString,
+ DWORD dwFlags,
+ LPARAM lParam) {
+ return TRUE;
+}
+
+// Additional warmup done just when CSRSS is being disconnected.
+bool CsrssDisconnectWarmup() {
+ return ::EnumSystemLocalesEx(EnumLocalesProcEx, LOCALE_WINDOWS, 0, 0);
+}
+
+// Checks if we have handle entries pending and runs the closer.
+// Updates is_csrss_connected based on which handle types are closed.
+bool CloseOpenHandles(bool* is_csrss_connected) {
+ if (HandleCloserAgent::NeedsHandlesClosed()) {
+ HandleCloserAgent handle_closer;
+ handle_closer.InitializeHandlesToClose(is_csrss_connected);
+ if (!*is_csrss_connected) {
+ if (!CsrssDisconnectWarmup() || !CsrssDisconnectCleanup()) {
+ return false;
+ }
+ }
+ if (!handle_closer.CloseHandles())
+ return false;
+ }
+ return true;
+}
+
+// Warm up language subsystems before the sandbox is turned on.
+// Tested on Win8.1 x64:
+// This needs to happen after RevertToSelf() is called, because (at least) in
+// the case of GetUserDefaultLCID() it checks the TEB to see if the process is
+// impersonating (TEB!IsImpersonating). If it is, the cached locale information
+// is not used, nor is it set. Therefore, calls after RevertToSelf() will not
+// have warmed-up values to use.
+bool WarmupWindowsLocales() {
+ // NOTE(liamjm): When last checked (Win 8.1 x64) it wasn't necessary to
+ // warmup all of these functions, but let's not assume that.
+ ::GetUserDefaultLangID();
+ ::GetUserDefaultLCID();
+ wchar_t localeName[LOCALE_NAME_MAX_LENGTH] = {0};
+ return (0 != ::GetUserDefaultLocaleName(localeName, LOCALE_NAME_MAX_LENGTH));
+}
+
+// Used as storage for g_target_services, because other allocation facilities
+// are not available early. We can't use a regular function static because on
+// VS2015, because the CRT tries to acquire a lock to guard initialization, but
+// this code runs before the CRT is initialized.
+char g_target_services_memory[sizeof(TargetServicesBase)];
+TargetServicesBase* g_target_services = nullptr;
+
+} // namespace
+
+SANDBOX_INTERCEPT IntegrityLevel g_shared_delayed_integrity_level =
+ INTEGRITY_LEVEL_LAST;
+SANDBOX_INTERCEPT MitigationFlags g_shared_delayed_mitigations = 0;
+
+TargetServicesBase::TargetServicesBase() {}
+
+ResultCode TargetServicesBase::Init() {
+ process_state_.SetInitCalled();
+ return SBOX_ALL_OK;
+}
+
+// Failure here is a breach of security so the process is terminated.
+void TargetServicesBase::LowerToken() {
+ if (ERROR_SUCCESS !=
+ SetProcessIntegrityLevel(g_shared_delayed_integrity_level))
+ ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_INTEGRITY);
+ process_state_.SetRevertedToSelf();
+ // If the client code as called RegOpenKey, advapi32.dll has cached some
+ // handles. The following code gets rid of them.
+ if (!::RevertToSelf())
+ ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_DROPTOKEN);
+ if (!FlushCachedRegHandles())
+ ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_FLUSHANDLES);
+ if (ERROR_SUCCESS != ::RegDisablePredefinedCache())
+ ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CACHEDISABLE);
+ if (!WarmupWindowsLocales())
+ ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_WARMUP);
+ bool is_csrss_connected = true;
+ if (!CloseOpenHandles(&is_csrss_connected))
+ ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_CLOSEHANDLES);
+ process_state_.SetCsrssConnected(is_csrss_connected);
+ // Enabling mitigations must happen last otherwise handle closing breaks
+ if (g_shared_delayed_mitigations &&
+ !ApplyProcessMitigationsToCurrentProcess(g_shared_delayed_mitigations))
+ ::TerminateProcess(::GetCurrentProcess(), SBOX_FATAL_MITIGATION);
+}
+
+ProcessState* TargetServicesBase::GetState() {
+ return &process_state_;
+}
+
+TargetServicesBase* TargetServicesBase::GetInstance() {
+ // Leak on purpose TargetServicesBase.
+ if (!g_target_services)
+ g_target_services = new (g_target_services_memory) TargetServicesBase;
+ return g_target_services;
+}
+
+// The broker services a 'test' IPC service with the PING tag.
+bool TargetServicesBase::TestIPCPing(int version) {
+ void* memory = GetGlobalIPCMemory();
+ if (!memory)
+ return false;
+ SharedMemIPCClient ipc(memory);
+ CrossCallReturn answer = {0};
+
+ if (1 == version) {
+ uint32_t tick1 = ::GetTickCount();
+ uint32_t cookie = 717115;
+ ResultCode code = CrossCall(ipc, IpcTag::PING1, cookie, &answer);
+
+ if (SBOX_ALL_OK != code) {
+ return false;
+ }
+ // We should get two extended returns values from the IPC, one is the
+ // tick count on the broker and the other is the cookie times two.
+ if ((answer.extended_count != 2)) {
+ return false;
+ }
+ // We test the first extended answer to be within the bounds of the tick
+ // count only if there was no tick count wraparound.
+ uint32_t tick2 = ::GetTickCount();
+ if (tick2 >= tick1) {
+ if ((answer.extended[0].unsigned_int < tick1) ||
+ (answer.extended[0].unsigned_int > tick2)) {
+ return false;
+ }
+ }
+
+ if (answer.extended[1].unsigned_int != cookie * 2) {
+ return false;
+ }
+ } else if (2 == version) {
+ uint32_t cookie = 717111;
+ InOutCountedBuffer counted_buffer(&cookie, sizeof(cookie));
+ ResultCode code = CrossCall(ipc, IpcTag::PING2, counted_buffer, &answer);
+
+ if (SBOX_ALL_OK != code) {
+ return false;
+ }
+ if (cookie != 717111 * 3) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+ProcessState::ProcessState()
+ : process_state_(ProcessStateInternal::NONE), csrss_connected_(true) {}
+
+bool ProcessState::InitCalled() const {
+ return process_state_ >= ProcessStateInternal::INIT_CALLED;
+}
+
+bool ProcessState::RevertedToSelf() const {
+ return process_state_ >= ProcessStateInternal::REVERTED_TO_SELF;
+}
+
+bool ProcessState::IsCsrssConnected() const {
+ return csrss_connected_;
+}
+
+void ProcessState::SetInitCalled() {
+ if (process_state_ < ProcessStateInternal::INIT_CALLED)
+ process_state_ = ProcessStateInternal::INIT_CALLED;
+}
+
+void ProcessState::SetRevertedToSelf() {
+ if (process_state_ < ProcessStateInternal::REVERTED_TO_SELF)
+ process_state_ = ProcessStateInternal::REVERTED_TO_SELF;
+}
+
+void ProcessState::SetCsrssConnected(bool csrss_connected) {
+ csrss_connected_ = csrss_connected;
+}
+
+ResultCode TargetServicesBase::DuplicateHandle(HANDLE source_handle,
+ DWORD target_process_id,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ DWORD options) {
+ return sandbox::DuplicateHandleProxy(source_handle, target_process_id,
+ target_handle, desired_access, options);
+}
+
+ResultCode TargetServicesBase::GetComplexLineBreaks(const WCHAR* text,
+ uint32_t length,
+ uint8_t* break_before) {
+ return sandbox::GetComplexLineBreaksProxy(text, length, break_before);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.h b/security/sandbox/chromium/sandbox/win/src/target_services.h
new file mode 100644
index 0000000000..1d70d4cd34
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/target_services.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_TARGET_SERVICES_H__
+#define SANDBOX_SRC_TARGET_SERVICES_H__
+
+#include "base/macros.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+class ProcessState {
+ public:
+ ProcessState();
+ // Returns true if main has been called.
+ bool InitCalled() const;
+ // Returns true if LowerToken has been called.
+ bool RevertedToSelf() const;
+ // Returns true if Csrss is connected.
+ bool IsCsrssConnected() const;
+ // Set the current state.
+ void SetInitCalled();
+ void SetRevertedToSelf();
+ void SetCsrssConnected(bool csrss_connected);
+
+ private:
+ enum class ProcessStateInternal { NONE = 0, INIT_CALLED, REVERTED_TO_SELF };
+
+ ProcessStateInternal process_state_;
+ bool csrss_connected_;
+ DISALLOW_COPY_AND_ASSIGN(ProcessState);
+};
+
+// This class is an implementation of the TargetServices.
+// Look in the documentation of sandbox::TargetServices for more info.
+// Do NOT add a destructor to this class without changing the implementation of
+// the factory method.
+class TargetServicesBase : public TargetServices {
+ public:
+ TargetServicesBase();
+
+ // Public interface of TargetServices.
+ ResultCode Init() override;
+ void LowerToken() override;
+ ProcessState* GetState() override;
+ ResultCode DuplicateHandle(HANDLE source_handle,
+ DWORD target_process_id,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ DWORD options) override;
+ ResultCode GetComplexLineBreaks(const WCHAR* text, uint32_t length,
+ uint8_t* break_before) final;
+
+ // Factory method.
+ static TargetServicesBase* GetInstance();
+
+ // Sends a simple IPC Message that has a well-known answer. Returns true
+ // if the IPC was successful and false otherwise. There are 2 versions of
+ // this test: 1 and 2. The first one send a simple message while the
+ // second one send a message with an in/out param.
+ bool TestIPCPing(int version);
+
+ private:
+ ~TargetServicesBase() {}
+ ProcessState process_state_;
+ DISALLOW_COPY_AND_ASSIGN(TargetServicesBase);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_TARGET_SERVICES_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/threadpool_unittest.cc b/security/sandbox/chromium/sandbox/win/src/threadpool_unittest.cc
new file mode 100644
index 0000000000..3f951b761b
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/threadpool_unittest.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/win2k_threadpool.h"
+
+#include <stdint.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+void __stdcall EmptyCallBack(void*, unsigned char) {}
+
+void __stdcall TestCallBack(void* context, unsigned char) {
+ HANDLE event = reinterpret_cast<HANDLE>(context);
+ ::SetEvent(event);
+}
+
+namespace sandbox {
+
+// Test that register and unregister work, part 1.
+TEST(IPCTest, ThreadPoolRegisterTest1) {
+ Win2kThreadPool thread_pool;
+
+ EXPECT_EQ(0u, thread_pool.OutstandingWaits());
+
+ HANDLE event1 = ::CreateEventW(nullptr, false, false, nullptr);
+ HANDLE event2 = ::CreateEventW(nullptr, false, false, nullptr);
+
+ uint32_t context = 0;
+ EXPECT_FALSE(thread_pool.RegisterWait(0, event1, EmptyCallBack, &context));
+ EXPECT_EQ(0u, thread_pool.OutstandingWaits());
+
+ EXPECT_TRUE(thread_pool.RegisterWait(this, event1, EmptyCallBack, &context));
+ EXPECT_EQ(1u, thread_pool.OutstandingWaits());
+ EXPECT_TRUE(thread_pool.RegisterWait(this, event2, EmptyCallBack, &context));
+ EXPECT_EQ(2u, thread_pool.OutstandingWaits());
+
+ EXPECT_TRUE(thread_pool.UnRegisterWaits(this));
+ EXPECT_EQ(0u, thread_pool.OutstandingWaits());
+
+ EXPECT_TRUE(::CloseHandle(event1));
+ EXPECT_TRUE(::CloseHandle(event2));
+}
+
+// Test that register and unregister work, part 2.
+TEST(IPCTest, ThreadPoolRegisterTest2) {
+ Win2kThreadPool thread_pool;
+
+ HANDLE event1 = ::CreateEventW(nullptr, false, false, nullptr);
+ HANDLE event2 = ::CreateEventW(nullptr, false, false, nullptr);
+
+ uint32_t context = 0;
+ uint32_t c1 = 0;
+ uint32_t c2 = 0;
+
+ EXPECT_TRUE(thread_pool.RegisterWait(&c1, event1, EmptyCallBack, &context));
+ EXPECT_EQ(1u, thread_pool.OutstandingWaits());
+ EXPECT_TRUE(thread_pool.RegisterWait(&c2, event2, EmptyCallBack, &context));
+ EXPECT_EQ(2u, thread_pool.OutstandingWaits());
+
+ EXPECT_TRUE(thread_pool.UnRegisterWaits(&c2));
+ EXPECT_EQ(1u, thread_pool.OutstandingWaits());
+ EXPECT_TRUE(thread_pool.UnRegisterWaits(&c2));
+ EXPECT_EQ(1u, thread_pool.OutstandingWaits());
+
+ EXPECT_TRUE(thread_pool.UnRegisterWaits(&c1));
+ EXPECT_EQ(0u, thread_pool.OutstandingWaits());
+
+ EXPECT_TRUE(::CloseHandle(event1));
+ EXPECT_TRUE(::CloseHandle(event2));
+}
+
+// Test that the thread pool has at least a thread that services an event.
+// Test that when the event is un-registered is no longer serviced.
+TEST(IPCTest, ThreadPoolSignalAndWaitTest) {
+ Win2kThreadPool thread_pool;
+
+ // The events are auto reset and start not signaled.
+ HANDLE event1 = ::CreateEventW(nullptr, false, false, nullptr);
+ HANDLE event2 = ::CreateEventW(nullptr, false, false, nullptr);
+
+ EXPECT_TRUE(thread_pool.RegisterWait(this, event1, TestCallBack, event2));
+
+ EXPECT_EQ(WAIT_OBJECT_0, ::SignalObjectAndWait(event1, event2, 5000, false));
+ EXPECT_EQ(WAIT_OBJECT_0, ::SignalObjectAndWait(event1, event2, 5000, false));
+
+ EXPECT_TRUE(thread_pool.UnRegisterWaits(this));
+ EXPECT_EQ(0u, thread_pool.OutstandingWaits());
+
+ EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+ ::SignalObjectAndWait(event1, event2, 1000, false));
+
+ EXPECT_TRUE(::CloseHandle(event1));
+ EXPECT_TRUE(::CloseHandle(event2));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc
new file mode 100644
index 0000000000..3c8f8e25e5
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc
@@ -0,0 +1,178 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/top_level_dispatcher.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/filesystem_dispatcher.h"
+#include "sandbox/win/src/handle_dispatcher.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/line_break_dispatcher.h"
+#include "sandbox/win/src/named_pipe_dispatcher.h"
+#include "sandbox/win/src/process_mitigations_win32k_dispatcher.h"
+#include "sandbox/win/src/process_thread_dispatcher.h"
+#include "sandbox/win/src/registry_dispatcher.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+#include "sandbox/win/src/signed_dispatcher.h"
+#include "sandbox/win/src/sync_dispatcher.h"
+
+namespace sandbox {
+
+TopLevelDispatcher::TopLevelDispatcher(PolicyBase* policy) : policy_(policy) {
+ // Initialize the IPC dispatcher array.
+ memset(ipc_targets_, 0, sizeof(ipc_targets_));
+ Dispatcher* dispatcher;
+
+ dispatcher = new FilesystemDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::NTCREATEFILE)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTOPENFILE)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTSETINFO_RENAME)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTQUERYATTRIBUTESFILE)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTQUERYFULLATTRIBUTESFILE)] =
+ dispatcher;
+ filesystem_dispatcher_.reset(dispatcher);
+
+ dispatcher = new NamedPipeDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::CREATENAMEDPIPEW)] = dispatcher;
+ named_pipe_dispatcher_.reset(dispatcher);
+
+ dispatcher = new ThreadProcessDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::NTOPENTHREAD)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTOPENPROCESS)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::CREATEPROCESSW)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTOPENPROCESSTOKEN)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTOPENPROCESSTOKENEX)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::CREATETHREAD)] = dispatcher;
+ thread_process_dispatcher_.reset(dispatcher);
+
+ dispatcher = new SyncDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::CREATEEVENT)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::OPENEVENT)] = dispatcher;
+ sync_dispatcher_.reset(dispatcher);
+
+ dispatcher = new RegistryDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::NTCREATEKEY)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::NTOPENKEY)] = dispatcher;
+ registry_dispatcher_.reset(dispatcher);
+
+ dispatcher = new HandleDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::DUPLICATEHANDLEPROXY)] = dispatcher;
+ handle_dispatcher_.reset(dispatcher);
+
+ dispatcher = new ProcessMitigationsWin32KDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_GDIDLLINITIALIZE)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETSTOCKOBJECT)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::USER_REGISTERCLASSW)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::USER_ENUMDISPLAYMONITORS)] =
+ dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::USER_ENUMDISPLAYDEVICES)] =
+ dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::USER_GETMONITORINFO)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_CREATEOPMPROTECTEDOUTPUTS)] =
+ dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETCERTIFICATE)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETCERTIFICATESIZE)] =
+ dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_DESTROYOPMPROTECTEDOUTPUT)] =
+ dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_CONFIGUREOPMPROTECTEDOUTPUT)] =
+ dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETOPMINFORMATION)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETOPMRANDOMNUMBER)] =
+ dispatcher;
+ ipc_targets_[static_cast<size_t>(
+ IpcTag::GDI_GETSUGGESTEDOPMPROTECTEDOUTPUTARRAYSIZE)] = dispatcher;
+ ipc_targets_[static_cast<size_t>(
+ IpcTag::GDI_SETOPMSIGNINGKEYANDSEQUENCENUMBERS)] = dispatcher;
+ process_mitigations_win32k_dispatcher_.reset(dispatcher);
+
+ dispatcher = new SignedDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::NTCREATESECTION)] = dispatcher;
+ signed_dispatcher_.reset(dispatcher);
+
+ dispatcher = new LineBreakDispatcher(policy_);
+ ipc_targets_[static_cast<size_t>(IpcTag::GETCOMPLEXLINEBREAKS)] = dispatcher;
+ line_break_dispatcher_.reset(dispatcher);
+}
+
+TopLevelDispatcher::~TopLevelDispatcher() {}
+
+// When an IPC is ready in any of the targets we get called. We manage an array
+// of IPC dispatchers which are keyed on the IPC tag so we normally delegate
+// to the appropriate dispatcher unless we can handle the IPC call ourselves.
+Dispatcher* TopLevelDispatcher::OnMessageReady(IPCParams* ipc,
+ CallbackGeneric* callback) {
+ DCHECK(callback);
+ static const IPCParams ping1 = {IpcTag::PING1, {UINT32_TYPE}};
+ static const IPCParams ping2 = {IpcTag::PING2, {INOUTPTR_TYPE}};
+
+ if (ping1.Matches(ipc) || ping2.Matches(ipc)) {
+ *callback = reinterpret_cast<CallbackGeneric>(
+ static_cast<Callback1>(&TopLevelDispatcher::Ping));
+ return this;
+ }
+
+ Dispatcher* dispatcher = GetDispatcher(ipc->ipc_tag);
+ if (!dispatcher) {
+ NOTREACHED();
+ return nullptr;
+ }
+ return dispatcher->OnMessageReady(ipc, callback);
+}
+
+// Delegate to the appropriate dispatcher.
+bool TopLevelDispatcher::SetupService(InterceptionManager* manager,
+ IpcTag service) {
+ if (IpcTag::PING1 == service || IpcTag::PING2 == service)
+ return true;
+
+ Dispatcher* dispatcher = GetDispatcher(service);
+ if (!dispatcher) {
+ NOTREACHED();
+ return false;
+ }
+ return dispatcher->SetupService(manager, service);
+}
+
+// We service PING message which is a way to test a round trip of the
+// IPC subsystem. We receive a integer cookie and we are expected to return the
+// cookie times two (or three) and the current tick count.
+bool TopLevelDispatcher::Ping(IPCInfo* ipc, void* arg1) {
+ switch (ipc->ipc_tag) {
+ case IpcTag::PING1: {
+ IPCInt ipc_int(arg1);
+ uint32_t cookie = ipc_int.As32Bit();
+ ipc->return_info.extended_count = 2;
+ ipc->return_info.extended[0].unsigned_int = ::GetTickCount();
+ ipc->return_info.extended[1].unsigned_int = 2 * cookie;
+ return true;
+ }
+ case IpcTag::PING2: {
+ CountedBuffer* io_buffer = reinterpret_cast<CountedBuffer*>(arg1);
+ if (sizeof(uint32_t) != io_buffer->Size())
+ return false;
+
+ uint32_t* cookie = reinterpret_cast<uint32_t*>(io_buffer->Buffer());
+ *cookie = (*cookie) * 3;
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+Dispatcher* TopLevelDispatcher::GetDispatcher(IpcTag ipc_tag) {
+ if (ipc_tag >= IpcTag::LAST || ipc_tag <= IpcTag::UNUSED)
+ return nullptr;
+
+ return ipc_targets_[static_cast<size_t>(ipc_tag)];
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.h b/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.h
new file mode 100644
index 0000000000..a80ce1ef5d
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_TOP_LEVEL_DISPATCHER_H__
+#define SANDBOX_SRC_TOP_LEVEL_DISPATCHER_H__
+
+#include <memory>
+
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+#include "sandbox/win/src/interception.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/sandbox_policy_base.h"
+
+namespace sandbox {
+
+// Top level dispatcher which hands requests to the appropriate service
+// dispatchers.
+class TopLevelDispatcher : public Dispatcher {
+ public:
+ // |policy| must outlive this class.
+ explicit TopLevelDispatcher(PolicyBase* policy);
+ ~TopLevelDispatcher() override;
+
+ Dispatcher* OnMessageReady(IPCParams* ipc,
+ CallbackGeneric* callback) override;
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
+
+ private:
+ // Test IPC provider.
+ bool Ping(IPCInfo* ipc, void* cookie);
+
+ // Returns a dispatcher from ipc_targets_.
+ Dispatcher* GetDispatcher(IpcTag ipc_tag);
+
+ PolicyBase* policy_;
+ std::unique_ptr<Dispatcher> filesystem_dispatcher_;
+ std::unique_ptr<Dispatcher> named_pipe_dispatcher_;
+ std::unique_ptr<Dispatcher> thread_process_dispatcher_;
+ std::unique_ptr<Dispatcher> sync_dispatcher_;
+ std::unique_ptr<Dispatcher> registry_dispatcher_;
+ std::unique_ptr<Dispatcher> handle_dispatcher_;
+ std::unique_ptr<Dispatcher> process_mitigations_win32k_dispatcher_;
+ std::unique_ptr<Dispatcher> signed_dispatcher_;
+ std::unique_ptr<Dispatcher> line_break_dispatcher_;
+ Dispatcher* ipc_targets_[kMaxIpcTag];
+
+ DISALLOW_COPY_AND_ASSIGN(TopLevelDispatcher);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_TOP_LEVEL_DISPATCHER_H__
diff --git a/security/sandbox/chromium/sandbox/win/src/unload_dll_test.cc b/security/sandbox/chromium/sandbox/win/src/unload_dll_test.cc
new file mode 100644
index 0000000000..0acb178987
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/unload_dll_test.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/scoped_handle.h"
+#include "build/build_config.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "sandbox/win/src/target_services.h"
+#include "sandbox/win/tests/common/controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+// Loads and or unloads a DLL passed in the second parameter of argv.
+// The first parameter of argv is 'L' = load, 'U' = unload or 'B' for both.
+SBOX_TESTS_COMMAND int UseOneDLL(int argc, wchar_t** argv) {
+ if (argc != 2)
+ return SBOX_TEST_FAILED_TO_RUN_TEST;
+ int rv = SBOX_TEST_FAILED_TO_RUN_TEST;
+
+ wchar_t option = (argv[0])[0];
+ if ((option == L'L') || (option == L'B')) {
+ HMODULE module1 = ::LoadLibraryW(argv[1]);
+ rv = (!module1) ? SBOX_TEST_FAILED : SBOX_TEST_SUCCEEDED;
+ }
+
+ if ((option == L'U') || (option == L'B')) {
+ HMODULE module2 = ::GetModuleHandleW(argv[1]);
+ rv = ::FreeLibrary(module2) ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+ }
+ return rv;
+}
+
+// Opens an event passed as the first parameter of argv.
+SBOX_TESTS_COMMAND int SimpleOpenEvent(int argc, wchar_t** argv) {
+ if (argc != 1)
+ return SBOX_TEST_FAILED_TO_EXECUTE_COMMAND;
+
+ base::win::ScopedHandle event_open(::OpenEvent(SYNCHRONIZE, false, argv[0]));
+ return event_open.Get() ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
+}
+
+// Fails on Windows ARM64: https://crbug.com/905526
+#if defined(ARCH_CPU_ARM64)
+#define MAYBE_BaselineAvicapDll DISABLED_BaselineAvicapDll
+#else
+#define MAYBE_BaselineAvicapDll BaselineAvicapDll
+#endif
+TEST(UnloadDllTest, MAYBE_BaselineAvicapDll) {
+ TestRunner runner;
+ runner.SetTestState(BEFORE_REVERT);
+ runner.SetTimeout(2000);
+ // Add a sync rule, because that ensures that the interception agent has
+ // more than one item in its internal table.
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_ANY, L"t0001"));
+
+ // Note for the puzzled: avicap32.dll is a 64-bit dll in 64-bit versions of
+ // windows so this test and the others just work.
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"UseOneDLL L avicap32.dll"));
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"UseOneDLL B avicap32.dll"));
+}
+
+TEST(UnloadDllTest, UnloadAviCapDllNoPatching) {
+ TestRunner runner;
+ runner.SetTestState(BEFORE_REVERT);
+ runner.SetTimeout(2000);
+ sandbox::TargetPolicy* policy = runner.GetPolicy();
+ policy->AddDllToUnload(L"avicap32.dll");
+ EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL L avicap32.dll"));
+ EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL B avicap32.dll"));
+}
+
+TEST(UnloadDllTest, UnloadAviCapDllWithPatching) {
+ TestRunner runner;
+ runner.SetTimeout(2000);
+ runner.SetTestState(BEFORE_REVERT);
+ sandbox::TargetPolicy* policy = runner.GetPolicy();
+ policy->AddDllToUnload(L"avicap32.dll");
+
+ base::win::ScopedHandle handle1(
+ ::CreateEvent(nullptr, false, false, L"tst0001"));
+
+ // Add a couple of rules that ensures that the interception agent add EAT
+ // patching on the client which makes sure that the unload dll record does
+ // not interact badly with them.
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_REGISTRY,
+ TargetPolicy::REG_ALLOW_ANY,
+ L"HKEY_LOCAL_MACHINE\\Software\\Microsoft"));
+ EXPECT_TRUE(runner.AddRule(TargetPolicy::SUBSYS_SYNC,
+ TargetPolicy::EVENTS_ALLOW_ANY, L"tst0001"));
+
+ EXPECT_EQ(SBOX_TEST_FAILED, runner.RunTest(L"UseOneDLL L avicap32.dll"));
+
+ runner.SetTestState(AFTER_REVERT);
+ EXPECT_EQ(SBOX_TEST_SUCCEEDED, runner.RunTest(L"SimpleOpenEvent tst0001"));
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/win2k_threadpool.cc b/security/sandbox/chromium/sandbox/win/src/win2k_threadpool.cc
new file mode 100644
index 0000000000..49cc68bb00
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/win2k_threadpool.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/win2k_threadpool.h"
+
+#include <stddef.h>
+
+#include "sandbox/win/src/win_utils.h"
+
+namespace sandbox {
+
+Win2kThreadPool::Win2kThreadPool() {
+ ::InitializeCriticalSection(&lock_);
+}
+
+bool Win2kThreadPool::RegisterWait(const void* cookie,
+ HANDLE waitable_object,
+ CrossCallIPCCallback callback,
+ void* context) {
+ if (0 == cookie) {
+ return false;
+ }
+ HANDLE pool_object = nullptr;
+ // create a wait for a kernel object, with no timeout
+ if (!::RegisterWaitForSingleObject(&pool_object, waitable_object, callback,
+ context, INFINITE, WT_EXECUTEDEFAULT)) {
+ return false;
+ }
+ PoolObject pool_obj = {cookie, pool_object};
+ AutoLock lock(&lock_);
+ pool_objects_.push_back(pool_obj);
+ return true;
+}
+
+bool Win2kThreadPool::UnRegisterWaits(void* cookie) {
+ if (0 == cookie) {
+ return false;
+ }
+ AutoLock lock(&lock_);
+ bool success = true;
+ PoolObjects::iterator it = pool_objects_.begin();
+ while (it != pool_objects_.end()) {
+ if (it->cookie == cookie) {
+ HANDLE wait = it->wait;
+ it = pool_objects_.erase(it);
+ success &= (::UnregisterWaitEx(wait, INVALID_HANDLE_VALUE) != 0);
+ } else {
+ ++it;
+ }
+ }
+ return success;
+}
+
+size_t Win2kThreadPool::OutstandingWaits() {
+ AutoLock lock(&lock_);
+ return pool_objects_.size();
+}
+
+Win2kThreadPool::~Win2kThreadPool() {
+ // Here we used to unregister all the pool wait handles. Now, following the
+ // rest of the code we avoid lengthy or blocking calls given that the process
+ // is being torn down.
+ ::DeleteCriticalSection(&lock_);
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/win2k_threadpool.h b/security/sandbox/chromium/sandbox/win/src/win2k_threadpool.h
new file mode 100644
index 0000000000..c4d539dd7f
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/win2k_threadpool.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_WIN2K_THREADPOOL_H_
+#define SANDBOX_SRC_WIN2K_THREADPOOL_H_
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <list>
+#include "base/macros.h"
+#include "sandbox/win/src/crosscall_server.h"
+
+namespace sandbox {
+
+// Win2kThreadPool a simple implementation of a thread provider as required
+// for the sandbox IPC subsystem. See sandbox\crosscall_server.h for the details
+// and requirements of this interface.
+//
+// Implementing the thread provider as a thread pool is desirable in the case
+// of shared memory IPC because it can generate a large number of waitable
+// events: as many as channels. A thread pool does not create a thread per
+// event, instead maintains a few idle threads but can create more if the need
+// arises.
+//
+// This implementation simply thunks to the nice thread pool API of win2k.
+class Win2kThreadPool : public ThreadProvider {
+ public:
+ Win2kThreadPool();
+ ~Win2kThreadPool() override;
+
+ bool RegisterWait(const void* cookie,
+ HANDLE waitable_object,
+ CrossCallIPCCallback callback,
+ void* context) override;
+
+ bool UnRegisterWaits(void* cookie) override;
+
+ // Returns the total number of wait objects associated with
+ // the thread pool.
+ size_t OutstandingWaits();
+
+ private:
+ // record to keep track of a wait and its associated cookie.
+ struct PoolObject {
+ const void* cookie;
+ HANDLE wait;
+ };
+ // The list of pool wait objects.
+ typedef std::list<PoolObject> PoolObjects;
+ PoolObjects pool_objects_;
+ // This lock protects the list of pool wait objects.
+ CRITICAL_SECTION lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(Win2kThreadPool);
+};
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_WIN2K_THREADPOOL_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/sandbox/chromium/sandbox/win/src/win_utils.cc
new file mode 100644
index 0000000000..8fb345a239
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/win_utils.cc
@@ -0,0 +1,619 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/win_utils.h"
+
+#include <psapi.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/numerics/safe_math.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/win/pe_image.h"
+#include "sandbox/win/src/internal_types.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+
+namespace {
+
+const size_t kDriveLetterLen = 3;
+
+constexpr wchar_t kNTDotPrefix[] = L"\\\\.\\";
+const size_t kNTDotPrefixLen = base::size(kNTDotPrefix) - 1;
+
+// Holds the information about a known registry key.
+struct KnownReservedKey {
+ const wchar_t* name;
+ HKEY key;
+};
+
+// Contains all the known registry key by name and by handle.
+const KnownReservedKey kKnownKey[] = {
+ {L"HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT},
+ {L"HKEY_CURRENT_USER", HKEY_CURRENT_USER},
+ {L"HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE},
+ {L"HKEY_USERS", HKEY_USERS},
+ {L"HKEY_PERFORMANCE_DATA", HKEY_PERFORMANCE_DATA},
+ {L"HKEY_PERFORMANCE_TEXT", HKEY_PERFORMANCE_TEXT},
+ {L"HKEY_PERFORMANCE_NLSTEXT", HKEY_PERFORMANCE_NLSTEXT},
+ {L"HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG},
+ {L"HKEY_DYN_DATA", HKEY_DYN_DATA}};
+
+// These functions perform case independent path comparisons.
+bool EqualPath(const std::wstring& first, const std::wstring& second) {
+ return _wcsicmp(first.c_str(), second.c_str()) == 0;
+}
+
+bool EqualPath(const std::wstring& first,
+ size_t first_offset,
+ const std::wstring& second,
+ size_t second_offset) {
+ return _wcsicmp(first.c_str() + first_offset,
+ second.c_str() + second_offset) == 0;
+}
+
+bool EqualPath(const std::wstring& first,
+ const wchar_t* second,
+ size_t second_len) {
+ return _wcsnicmp(first.c_str(), second, second_len) == 0;
+}
+
+bool EqualPath(const std::wstring& first,
+ size_t first_offset,
+ const wchar_t* second,
+ size_t second_len) {
+ return _wcsnicmp(first.c_str() + first_offset, second, second_len) == 0;
+}
+
+// Returns true if |path| starts with "\??\" and returns a path without that
+// component.
+bool IsNTPath(const std::wstring& path, std::wstring* trimmed_path) {
+ if ((path.size() < sandbox::kNTPrefixLen) ||
+ !EqualPath(path, sandbox::kNTPrefix, sandbox::kNTPrefixLen)) {
+ *trimmed_path = path;
+ return false;
+ }
+
+ *trimmed_path = path.substr(sandbox::kNTPrefixLen);
+ return true;
+}
+
+// Returns true if |path| starts with "\Device\" and returns a path without that
+// component.
+bool IsDevicePath(const std::wstring& path, std::wstring* trimmed_path) {
+ if ((path.size() < sandbox::kNTDevicePrefixLen) ||
+ (!EqualPath(path, sandbox::kNTDevicePrefix,
+ sandbox::kNTDevicePrefixLen))) {
+ *trimmed_path = path;
+ return false;
+ }
+
+ *trimmed_path = path.substr(sandbox::kNTDevicePrefixLen);
+ return true;
+}
+
+// Returns the offset to the path seperator following
+// "\Device\HarddiskVolumeX" in |path|.
+size_t PassHarddiskVolume(const std::wstring& path) {
+ static constexpr wchar_t pattern[] = L"\\Device\\HarddiskVolume";
+ const size_t patternLen = base::size(pattern) - 1;
+
+ // First, check for |pattern|.
+ if ((path.size() < patternLen) || (!EqualPath(path, pattern, patternLen)))
+ return std::wstring::npos;
+
+ // Find the next path separator, after the pattern match.
+ return path.find_first_of(L'\\', patternLen - 1);
+}
+
+// Returns true if |path| starts with "\Device\HarddiskVolumeX\" and returns a
+// path without that component. |removed| will hold the prefix removed.
+bool IsDeviceHarddiskPath(const std::wstring& path,
+ std::wstring* trimmed_path,
+ std::wstring* removed) {
+ size_t offset = PassHarddiskVolume(path);
+ if (offset == std::wstring::npos)
+ return false;
+
+ // Remove up to and including the path separator.
+ *removed = path.substr(0, offset + 1);
+ // Remaining path starts after the path separator.
+ *trimmed_path = path.substr(offset + 1);
+ return true;
+}
+
+bool StartsWithDriveLetter(const std::wstring& path) {
+ if (path.size() < kDriveLetterLen)
+ return false;
+
+ if (path[1] != L':' || path[2] != L'\\')
+ return false;
+
+ return base::IsAsciiAlpha(path[0]);
+}
+
+// Removes "\\\\.\\" from the path.
+void RemoveImpliedDevice(std::wstring* path) {
+ if (EqualPath(*path, kNTDotPrefix, kNTDotPrefixLen))
+ *path = path->substr(kNTDotPrefixLen);
+}
+
+} // namespace
+
+namespace sandbox {
+
+// Returns true if the provided path points to a pipe.
+bool IsPipe(const std::wstring& path) {
+ size_t start = 0;
+ if (EqualPath(path, sandbox::kNTPrefix, sandbox::kNTPrefixLen))
+ start = sandbox::kNTPrefixLen;
+
+ const wchar_t kPipe[] = L"pipe\\";
+ if (path.size() < start + base::size(kPipe) - 1)
+ return false;
+
+ return EqualPath(path, start, kPipe, base::size(kPipe) - 1);
+}
+
+HKEY GetReservedKeyFromName(const std::wstring& name) {
+ for (size_t i = 0; i < base::size(kKnownKey); ++i) {
+ if (name == kKnownKey[i].name)
+ return kKnownKey[i].key;
+ }
+
+ return nullptr;
+}
+
+bool ResolveRegistryName(std::wstring name, std::wstring* resolved_name) {
+ for (size_t i = 0; i < base::size(kKnownKey); ++i) {
+ if (name.find(kKnownKey[i].name) == 0) {
+ HKEY key;
+ DWORD disposition;
+ if (ERROR_SUCCESS != ::RegCreateKeyEx(kKnownKey[i].key, L"", 0, nullptr,
+ 0, MAXIMUM_ALLOWED, nullptr, &key,
+ &disposition))
+ return false;
+
+ bool result = GetPathFromHandle(key, resolved_name);
+ ::RegCloseKey(key);
+
+ if (!result)
+ return false;
+
+ *resolved_name += name.substr(wcslen(kKnownKey[i].name));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// |full_path| can have any of the following forms:
+// \??\c:\some\foo\bar
+// \Device\HarddiskVolume0\some\foo\bar
+// \??\HarddiskVolume0\some\foo\bar
+// \??\UNC\SERVER\Share\some\foo\bar
+DWORD IsReparsePoint(const std::wstring& full_path) {
+ // Check if it's a pipe. We can't query the attributes of a pipe.
+ if (IsPipe(full_path))
+ return ERROR_NOT_A_REPARSE_POINT;
+
+ std::wstring path;
+ bool nt_path = IsNTPath(full_path, &path);
+ bool has_drive = StartsWithDriveLetter(path);
+ bool is_device_path = IsDevicePath(path, &path);
+
+ if (!has_drive && !is_device_path && !nt_path)
+ return ERROR_INVALID_NAME;
+
+ if (!has_drive) {
+ // Add Win32 device namespace prefix, required for some Windows APIs.
+ path.insert(0, kNTDotPrefix);
+ }
+
+ // Ensure that volume path matches start of path.
+ wchar_t vol_path[MAX_PATH];
+ if (!::GetVolumePathNameW(path.c_str(), vol_path, MAX_PATH)) {
+ // This will fail if this is a device that isn't volume related, which can't
+ // then be a reparse point.
+ return is_device_path ? ERROR_NOT_A_REPARSE_POINT : ERROR_INVALID_NAME;
+ }
+
+ // vol_path includes a trailing slash, so reduce size for path and loop check.
+ size_t vol_path_len = wcslen(vol_path) - 1;
+ if (!EqualPath(path, vol_path, vol_path_len)) {
+ return ERROR_INVALID_NAME;
+ }
+
+ do {
+ DWORD attributes = ::GetFileAttributes(path.c_str());
+ if (INVALID_FILE_ATTRIBUTES == attributes) {
+ DWORD error = ::GetLastError();
+ if (error != ERROR_FILE_NOT_FOUND && error != ERROR_PATH_NOT_FOUND &&
+ error != ERROR_INVALID_FUNCTION &&
+ error != ERROR_INVALID_NAME) {
+ // Unexpected error.
+ return error;
+ }
+ } else if (FILE_ATTRIBUTE_REPARSE_POINT & attributes) {
+ // This is a reparse point.
+ return ERROR_SUCCESS;
+ }
+
+ path.resize(path.rfind(L'\\'));
+ } while (path.size() > vol_path_len); // Skip root dir.
+
+ return ERROR_NOT_A_REPARSE_POINT;
+}
+
+// We get a |full_path| of the forms accepted by IsReparsePoint(), and the name
+// we'll get from |handle| will be \device\harddiskvolume1\some\foo\bar.
+bool SameObject(HANDLE handle, const wchar_t* full_path) {
+ // Check if it's a pipe.
+ if (IsPipe(full_path))
+ return true;
+
+ std::wstring actual_path;
+ if (!GetPathFromHandle(handle, &actual_path))
+ return false;
+
+ std::wstring path(full_path);
+ DCHECK_NT(!path.empty());
+
+ // This may end with a backslash.
+ if (path.back() == L'\\') {
+ path.pop_back();
+ }
+
+ // Perfect match (case-insensitive check).
+ if (EqualPath(actual_path, path))
+ return true;
+
+ bool nt_path = IsNTPath(path, &path);
+ bool has_drive = StartsWithDriveLetter(path);
+
+ if (!has_drive && nt_path) {
+ std::wstring simple_actual_path;
+ if (IsDevicePath(path, &path)) {
+ if (IsDevicePath(actual_path, &simple_actual_path)) {
+ // Perfect match (case-insensitive check).
+ return (EqualPath(simple_actual_path, path));
+ } else {
+ return false;
+ }
+ } else {
+ // Add Win32 device namespace for GetVolumePathName.
+ path.insert(0, kNTDotPrefix);
+ }
+ }
+
+ // Get the volume path in the same format as actual_path.
+ wchar_t vol_path[MAX_PATH];
+ if (!::GetVolumePathName(path.c_str(), vol_path, MAX_PATH)) {
+ return false;
+ }
+ size_t vol_path_len = wcslen(vol_path);
+ base::string16 nt_vol;
+ if (!GetNtPathFromWin32Path(vol_path, &nt_vol)) {
+ return false;
+ }
+
+ // The two paths should be the same length.
+ if (nt_vol.size() + path.size() - vol_path_len != actual_path.size()) {
+ return false;
+ }
+
+ // Check the volume matches.
+ if (!EqualPath(actual_path, nt_vol.c_str(), nt_vol.size())) {
+ return false;
+ }
+
+ // Check the path after the volume matches.
+ if (!EqualPath(actual_path, nt_vol.size(), path, vol_path_len)) {
+ return false;
+ }
+
+ return true;
+}
+
+// Just make a best effort here. There are lots of corner cases that we're
+// not expecting - and will fail to make long.
+bool ConvertToLongPath(std::wstring* native_path,
+ const std::wstring* drive_letter) {
+ if (IsPipe(*native_path))
+ return true;
+
+ bool is_device_harddisk_path = false;
+ bool is_nt_path = false;
+ bool added_implied_device = false;
+ std::wstring temp_path;
+ std::wstring to_restore;
+
+ // Process a few prefix types.
+ if (IsNTPath(*native_path, &temp_path)) {
+ // "\??\"
+ if (!StartsWithDriveLetter(temp_path)) {
+ // Prepend with "\\.\".
+ temp_path = std::wstring(kNTDotPrefix) + temp_path;
+ added_implied_device = true;
+ }
+ is_nt_path = true;
+ } else if (IsDeviceHarddiskPath(*native_path, &temp_path, &to_restore)) {
+ // "\Device\HarddiskVolumeX\" - hacky attempt making ::GetLongPathName
+ // work for native device paths. Remove "\Device\HarddiskVolumeX\" and
+ // replace with drive letter.
+
+ // Nothing we can do if we don't have a drive letter. Leave |native_path|
+ // as is.
+ if (!drive_letter || drive_letter->empty())
+ return false;
+ temp_path = *drive_letter + temp_path;
+ is_device_harddisk_path = true;
+ } else if (IsDevicePath(*native_path, &temp_path)) {
+ // "\Device\" - there's nothing we can do to convert to long here.
+ return false;
+ }
+
+ DWORD size = MAX_PATH;
+ std::unique_ptr<wchar_t[]> long_path_buf(new wchar_t[size]);
+
+ DWORD return_value =
+ ::GetLongPathName(temp_path.c_str(), long_path_buf.get(), size);
+ while (return_value >= size) {
+ size *= 2;
+ long_path_buf.reset(new wchar_t[size]);
+ return_value =
+ ::GetLongPathName(temp_path.c_str(), long_path_buf.get(), size);
+ }
+
+ DWORD last_error = ::GetLastError();
+ if (0 == return_value && (ERROR_FILE_NOT_FOUND == last_error ||
+ ERROR_PATH_NOT_FOUND == last_error ||
+ ERROR_INVALID_NAME == last_error)) {
+ // The file does not exist, but maybe a sub path needs to be expanded.
+ std::wstring::size_type last_slash = temp_path.rfind(L'\\');
+ if (std::wstring::npos == last_slash)
+ return false;
+
+ std::wstring begin = temp_path.substr(0, last_slash);
+ std::wstring end = temp_path.substr(last_slash);
+ if (!ConvertToLongPath(&begin))
+ return false;
+
+ // Ok, it worked. Let's reset the return value.
+ temp_path = begin + end;
+ return_value = 1;
+ } else if (0 != return_value) {
+ temp_path = long_path_buf.get();
+ }
+
+ // If successful, re-apply original namespace prefix before returning.
+ if (return_value != 0) {
+ if (added_implied_device)
+ RemoveImpliedDevice(&temp_path);
+
+ if (is_nt_path) {
+ *native_path = kNTPrefix;
+ *native_path += temp_path;
+ } else if (is_device_harddisk_path) {
+ // Remove the added drive letter.
+ temp_path = temp_path.substr(kDriveLetterLen);
+ *native_path = to_restore;
+ *native_path += temp_path;
+ } else {
+ *native_path = temp_path;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool GetPathFromHandle(HANDLE handle, std::wstring* path) {
+ NtQueryObjectFunction NtQueryObject = nullptr;
+ ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
+
+ OBJECT_NAME_INFORMATION initial_buffer;
+ OBJECT_NAME_INFORMATION* name = &initial_buffer;
+ ULONG size = sizeof(initial_buffer);
+ // Query the name information a first time to get the size of the name.
+ // Windows XP requires that the size of the buffer passed in here be != 0.
+ NTSTATUS status =
+ NtQueryObject(handle, ObjectNameInformation, name, size, &size);
+
+ std::unique_ptr<BYTE[]> name_ptr;
+ if (size) {
+ name_ptr.reset(new BYTE[size]);
+ name = reinterpret_cast<OBJECT_NAME_INFORMATION*>(name_ptr.get());
+
+ // Query the name information a second time to get the name of the
+ // object referenced by the handle.
+ status = NtQueryObject(handle, ObjectNameInformation, name, size, &size);
+ }
+
+ if (STATUS_SUCCESS != status)
+ return false;
+
+ path->assign(name->ObjectName.Buffer,
+ name->ObjectName.Length / sizeof(name->ObjectName.Buffer[0]));
+ return true;
+}
+
+bool GetNtPathFromWin32Path(const std::wstring& path, std::wstring* nt_path) {
+ HANDLE file = ::CreateFileW(
+ path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ if (file == INVALID_HANDLE_VALUE)
+ return false;
+ bool rv = GetPathFromHandle(file, nt_path);
+ ::CloseHandle(file);
+ return rv;
+}
+
+bool WriteProtectedChildMemory(HANDLE child_process,
+ void* address,
+ const void* buffer,
+ size_t length,
+ DWORD writeProtection) {
+ // First, remove the protections.
+ DWORD old_protection;
+ if (!::VirtualProtectEx(child_process, address, length, writeProtection,
+ &old_protection))
+ return false;
+
+ SIZE_T written;
+ bool ok =
+ ::WriteProcessMemory(child_process, address, buffer, length, &written) &&
+ (length == written);
+
+ // Always attempt to restore the original protection.
+ if (!::VirtualProtectEx(child_process, address, length, old_protection,
+ &old_protection))
+ return false;
+
+ return ok;
+}
+
+bool CopyToChildMemory(HANDLE child,
+ const void* local_buffer,
+ size_t buffer_bytes,
+ void** remote_buffer) {
+ DCHECK(remote_buffer);
+ if (0 == buffer_bytes) {
+ *remote_buffer = nullptr;
+ return true;
+ }
+
+ // Allocate memory in the target process without specifying the address
+ void* remote_data = ::VirtualAllocEx(child, nullptr, buffer_bytes, MEM_COMMIT,
+ PAGE_READWRITE);
+ if (!remote_data)
+ return false;
+
+ SIZE_T bytes_written;
+ bool success = ::WriteProcessMemory(child, remote_data, local_buffer,
+ buffer_bytes, &bytes_written);
+ if (!success || bytes_written != buffer_bytes) {
+ ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
+ return false;
+ }
+
+ *remote_buffer = remote_data;
+
+ return true;
+}
+
+DWORD GetLastErrorFromNtStatus(NTSTATUS status) {
+ RtlNtStatusToDosErrorFunction NtStatusToDosError = nullptr;
+ ResolveNTFunctionPtr("RtlNtStatusToDosError", &NtStatusToDosError);
+ return NtStatusToDosError(status);
+}
+
+// This function uses the undocumented PEB ImageBaseAddress field to extract
+// the base address of the new process.
+void* GetProcessBaseAddress(HANDLE process) {
+ NtQueryInformationProcessFunction query_information_process = nullptr;
+ ResolveNTFunctionPtr("NtQueryInformationProcess", &query_information_process);
+ if (!query_information_process)
+ return nullptr;
+ PROCESS_BASIC_INFORMATION process_basic_info = {};
+ NTSTATUS status = query_information_process(
+ process, ProcessBasicInformation, &process_basic_info,
+ sizeof(process_basic_info), nullptr);
+ if (STATUS_SUCCESS != status)
+ return nullptr;
+
+ PEB peb = {};
+ SIZE_T bytes_read = 0;
+ if (!::ReadProcessMemory(process, process_basic_info.PebBaseAddress, &peb,
+ sizeof(peb), &bytes_read) ||
+ (sizeof(peb) != bytes_read)) {
+ return nullptr;
+ }
+
+ void* base_address = peb.ImageBaseAddress;
+ char magic[2] = {};
+ if (!::ReadProcessMemory(process, base_address, magic, sizeof(magic),
+ &bytes_read) ||
+ (sizeof(magic) != bytes_read)) {
+ return nullptr;
+ }
+
+ if (magic[0] != 'M' || magic[1] != 'Z')
+ return nullptr;
+
+#if defined(_M_ARM64)
+ // Windows 10 on ARM64 has multi-threaded DLL loading that does not work with
+ // the sandbox. (On x86 this gets disabled by hook detection code that was not
+ // ported to ARM64). This overwrites the LoaderThreads value in the process
+ // parameters part of the PEB, if it is set to the default of 0 (which
+ // actually means it defaults to 4 loading threads). This is an undocumented
+ // field so there is a, probably small, risk that it might change or move in
+ // the future. In order to slightly guard against that we only update if the
+ // value is currently 0.
+ auto processParameters = reinterpret_cast<uint8_t*>(peb.ProcessParameters);
+ const uint32_t loaderThreadsOffset = 0x40c;
+ uint32_t maxLoaderThreads = 0;
+ BOOL memoryRead = ::ReadProcessMemory(
+ process, processParameters + loaderThreadsOffset, &maxLoaderThreads,
+ sizeof(maxLoaderThreads), &bytes_read);
+ if (memoryRead && (sizeof(maxLoaderThreads) == bytes_read) &&
+ (maxLoaderThreads == 0)) {
+ maxLoaderThreads = 1;
+ WriteProtectedChildMemory(process, processParameters + loaderThreadsOffset,
+ &maxLoaderThreads, sizeof(maxLoaderThreads),
+ PAGE_READWRITE);
+ }
+#endif
+
+ return base_address;
+}
+
+DWORD GetTokenInformation(HANDLE token,
+ TOKEN_INFORMATION_CLASS info_class,
+ std::unique_ptr<BYTE[]>* buffer) {
+ // Get the required buffer size.
+ DWORD size = 0;
+ ::GetTokenInformation(token, info_class, nullptr, 0, &size);
+ if (!size) {
+ return ::GetLastError();
+ }
+
+ auto temp_buffer = std::make_unique<BYTE[]>(size);
+ if (!::GetTokenInformation(token, info_class, temp_buffer.get(), size,
+ &size)) {
+ return ::GetLastError();
+ }
+
+ *buffer = std::move(temp_buffer);
+ return ERROR_SUCCESS;
+}
+
+} // namespace sandbox
+
+void ResolveNTFunctionPtr(const char* name, void* ptr) {
+ static volatile HMODULE ntdll = nullptr;
+
+ if (!ntdll) {
+ HMODULE ntdll_local = ::GetModuleHandle(sandbox::kNtdllName);
+ // Use PEImage to sanity-check that we have a valid ntdll handle.
+ base::win::PEImage ntdll_peimage(ntdll_local);
+ CHECK_NT(ntdll_peimage.VerifyMagic());
+ // Race-safe way to set static ntdll.
+ ::InterlockedCompareExchangePointer(
+ reinterpret_cast<PVOID volatile*>(&ntdll), ntdll_local, nullptr);
+ }
+
+ CHECK_NT(ntdll);
+ FARPROC* function_ptr = reinterpret_cast<FARPROC*>(ptr);
+ *function_ptr = ::GetProcAddress(ntdll, name);
+ CHECK_NT(*function_ptr);
+}
diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.h b/security/sandbox/chromium/sandbox/win/src/win_utils.h
new file mode 100644
index 0000000000..7c848f2f08
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/win_utils.h
@@ -0,0 +1,156 @@
+// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_WIN_UTILS_H_
+#define SANDBOX_SRC_WIN_UTILS_H_
+
+#include <stddef.h>
+#include <windows.h>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "sandbox/win/src/nt_internals.h"
+
+namespace sandbox {
+
+// Prefix for path used by NT calls.
+const wchar_t kNTPrefix[] = L"\\??\\";
+const size_t kNTPrefixLen = base::size(kNTPrefix) - 1;
+
+const wchar_t kNTDevicePrefix[] = L"\\Device\\";
+const size_t kNTDevicePrefixLen = base::size(kNTDevicePrefix) - 1;
+
+// Automatically acquires and releases a lock when the object is
+// is destroyed.
+class AutoLock {
+ public:
+ // Acquires the lock.
+ explicit AutoLock(CRITICAL_SECTION* lock) : lock_(lock) {
+ ::EnterCriticalSection(lock);
+ }
+
+ // Releases the lock;
+ ~AutoLock() { ::LeaveCriticalSection(lock_); }
+
+ private:
+ CRITICAL_SECTION* lock_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AutoLock);
+};
+
+// Basic implementation of a singleton which calls the destructor
+// when the exe is shutting down or the DLL is being unloaded.
+template <typename Derived>
+class SingletonBase {
+ public:
+ static Derived* GetInstance() {
+ static Derived* instance = nullptr;
+ if (!instance) {
+ instance = new Derived();
+ // Microsoft CRT extension. In an exe this this called after
+ // winmain returns, in a dll is called in DLL_PROCESS_DETACH
+ _onexit(OnExit);
+ }
+ return instance;
+ }
+
+ private:
+ // this is the function that gets called by the CRT when the
+ // process is shutting down.
+ static int __cdecl OnExit() {
+ delete GetInstance();
+ return 0;
+ }
+};
+
+// Function object which invokes LocalFree on its parameter, which must be
+// a pointer. Can be used to store LocalAlloc pointers in std::unique_ptr:
+//
+// std::unique_ptr<int, sandbox::LocalFreeDeleter> foo_ptr(
+// static_cast<int*>(LocalAlloc(LMEM_FIXED, sizeof(int))));
+struct LocalFreeDeleter {
+ inline void operator()(void* ptr) const { ::LocalFree(ptr); }
+};
+
+// Convert a short path (C:\path~1 or \\??\\c:\path~1) to the long version of
+// the path. If the path is not a valid filesystem path, the function returns
+// false and argument is not modified.
+// - If passing in a short native device path (\Device\HarddiskVolumeX\path~1),
+// a drive letter string (c:\) must also be provided.
+bool ConvertToLongPath(std::wstring* path,
+ const std::wstring* drive_letter = nullptr);
+
+// Returns ERROR_SUCCESS if the path contains a reparse point,
+// ERROR_NOT_A_REPARSE_POINT if there's no reparse point in this path, or an
+// error code when the function fails.
+// This function is not smart. It looks for each element in the path and
+// returns true if any of them is a reparse point.
+DWORD IsReparsePoint(const std::wstring& full_path);
+
+// Returns true if the handle corresponds to the object pointed by this path.
+bool SameObject(HANDLE handle, const wchar_t* full_path);
+
+// Resolves a handle to an nt path. Returns true if the handle can be resolved.
+bool GetPathFromHandle(HANDLE handle, std::wstring* path);
+
+// Resolves a win32 path to an nt path using GetPathFromHandle. The path must
+// exist. Returs true if the translation was succesful.
+bool GetNtPathFromWin32Path(const std::wstring& path, std::wstring* nt_path);
+
+// Translates a reserved key name to its handle.
+// For example "HKEY_LOCAL_MACHINE" returns HKEY_LOCAL_MACHINE.
+// Returns nullptr if the name does not represent any reserved key name.
+HKEY GetReservedKeyFromName(const std::wstring& name);
+
+// Resolves a user-readable registry path to a system-readable registry path.
+// For example, HKEY_LOCAL_MACHINE\\Software\\microsoft is translated to
+// \\registry\\machine\\software\\microsoft. Returns false if the path
+// cannot be resolved.
+bool ResolveRegistryName(std::wstring name, std::wstring* resolved_name);
+
+// Writes |length| bytes from the provided |buffer| into the address space of
+// |child_process|, at the specified |address|, preserving the original write
+// protection attributes. Returns true on success.
+bool WriteProtectedChildMemory(HANDLE child_process,
+ void* address,
+ const void* buffer,
+ size_t length,
+ DWORD writeProtection = PAGE_WRITECOPY);
+
+// Allocates |buffer_bytes| in child (PAGE_READWRITE) and copies data
+// from |local_buffer| in this process into |child|. |remote_buffer|
+// contains the address in the chile. If a zero byte copy is
+// requested |true| is returned and no allocation or copying is
+// attempted. Returns false if allocation or copying fails. If
+// copying fails, the allocation will be reversed.
+bool CopyToChildMemory(HANDLE child,
+ const void* local_buffer,
+ size_t buffer_bytes,
+ void** remote_buffer);
+
+// Returns true if the provided path points to a pipe.
+bool IsPipe(const std::wstring& path);
+
+// Converts a NTSTATUS code to a Win32 error code.
+DWORD GetLastErrorFromNtStatus(NTSTATUS status);
+
+// Returns the address of the main exe module in memory taking in account
+// address space layout randomization. This uses the process' PEB to extract
+// the base address. This should only be called on new, suspended processes.
+void* GetProcessBaseAddress(HANDLE process);
+
+// Calls GetTokenInformation with the desired |info_class| and returns a
+// |buffer| and the Win32 error code.
+DWORD GetTokenInformation(HANDLE token,
+ TOKEN_INFORMATION_CLASS info_class,
+ std::unique_ptr<BYTE[]>* buffer);
+
+} // namespace sandbox
+
+// Resolves a function name in NTDLL to a function pointer. The second parameter
+// is a pointer to the function pointer.
+void ResolveNTFunctionPtr(const char* name, void* ptr);
+
+#endif // SANDBOX_SRC_WIN_UTILS_H_
diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils_unittest.cc b/security/sandbox/chromium/sandbox/win/src/win_utils_unittest.cc
new file mode 100644
index 0000000000..36e7d4dd1e
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/win_utils_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/win_utils.h"
+
+#include <windows.h>
+
+#include <psapi.h>
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/path_service.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "sandbox/win/src/nt_internals.h"
+#include "sandbox/win/tests/common/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sandbox {
+
+namespace {
+
+class ScopedTerminateProcess {
+ public:
+ ScopedTerminateProcess(HANDLE process) : process_(process) {}
+
+ ~ScopedTerminateProcess() { ::TerminateProcess(process_, 0); }
+
+ private:
+ HANDLE process_;
+};
+
+bool GetModuleList(HANDLE process, std::vector<HMODULE>* result) {
+ std::vector<HMODULE> modules(256);
+ DWORD size_needed = 0;
+ if (EnumProcessModules(
+ process, &modules[0],
+ base::checked_cast<DWORD>(modules.size() * sizeof(HMODULE)),
+ &size_needed)) {
+ result->assign(modules.begin(),
+ modules.begin() + (size_needed / sizeof(HMODULE)));
+ return true;
+ }
+ modules.resize(size_needed / sizeof(HMODULE));
+ if (EnumProcessModules(
+ process, &modules[0],
+ base::checked_cast<DWORD>(modules.size() * sizeof(HMODULE)),
+ &size_needed)) {
+ result->assign(modules.begin(),
+ modules.begin() + (size_needed / sizeof(HMODULE)));
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
+TEST(WinUtils, IsReparsePoint) {
+ using sandbox::IsReparsePoint;
+
+ // Create a temp file because we need write access to it.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t my_folder[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, my_folder), 0u);
+
+ // Delete the file and create a directory instead.
+ ASSERT_TRUE(::DeleteFile(my_folder));
+ ASSERT_TRUE(::CreateDirectory(my_folder, nullptr));
+
+ EXPECT_EQ(static_cast<DWORD>(ERROR_NOT_A_REPARSE_POINT),
+ IsReparsePoint(my_folder));
+
+ std::wstring not_found = std::wstring(my_folder) + L"\\foo\\bar";
+ EXPECT_EQ(static_cast<DWORD>(ERROR_NOT_A_REPARSE_POINT),
+ IsReparsePoint(not_found));
+
+ std::wstring new_file = std::wstring(my_folder) + L"\\foo";
+ EXPECT_EQ(static_cast<DWORD>(ERROR_NOT_A_REPARSE_POINT),
+ IsReparsePoint(new_file));
+
+ // Replace the directory with a reparse point to %temp%.
+ HANDLE dir = ::CreateFile(my_folder, FILE_ALL_ACCESS,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ EXPECT_NE(INVALID_HANDLE_VALUE, dir);
+
+ std::wstring temp_dir_nt = std::wstring(L"\\??\\") + temp_directory;
+ EXPECT_TRUE(SetReparsePoint(dir, temp_dir_nt.c_str()));
+
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), IsReparsePoint(new_file));
+
+ EXPECT_TRUE(DeleteReparsePoint(dir));
+ EXPECT_TRUE(::CloseHandle(dir));
+ EXPECT_TRUE(::RemoveDirectory(my_folder));
+}
+
+TEST(WinUtils, SameObject) {
+ using sandbox::SameObject;
+
+ // Create a temp file because we need write access to it.
+ wchar_t temp_directory[MAX_PATH];
+ wchar_t my_folder[MAX_PATH];
+ ASSERT_NE(::GetTempPath(MAX_PATH, temp_directory), 0u);
+ ASSERT_NE(::GetTempFileName(temp_directory, L"test", 0, my_folder), 0u);
+
+ // Delete the file and create a directory instead.
+ ASSERT_TRUE(::DeleteFile(my_folder));
+ ASSERT_TRUE(::CreateDirectory(my_folder, nullptr));
+
+ std::wstring folder(my_folder);
+ std::wstring file_name = folder + L"\\foo.txt";
+ const ULONG kSharing = FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
+ base::win::ScopedHandle file(CreateFile(file_name.c_str(), GENERIC_WRITE,
+ kSharing, nullptr, CREATE_ALWAYS,
+ FILE_FLAG_DELETE_ON_CLOSE, nullptr));
+
+ EXPECT_TRUE(file.IsValid());
+ std::wstring file_name_nt1 = std::wstring(L"\\??\\") + file_name;
+ std::wstring file_name_nt2 = std::wstring(L"\\??\\") + folder + L"\\FOO.txT";
+ EXPECT_TRUE(SameObject(file.Get(), file_name_nt1.c_str()));
+ EXPECT_TRUE(SameObject(file.Get(), file_name_nt2.c_str()));
+
+ file.Close();
+ EXPECT_TRUE(::RemoveDirectory(my_folder));
+}
+
+TEST(WinUtils, IsPipe) {
+ using sandbox::IsPipe;
+
+ std::wstring pipe_name = L"\\??\\pipe\\mypipe";
+ EXPECT_TRUE(IsPipe(pipe_name));
+
+ pipe_name = L"\\??\\PiPe\\mypipe";
+ EXPECT_TRUE(IsPipe(pipe_name));
+
+ pipe_name = L"\\??\\pipe";
+ EXPECT_FALSE(IsPipe(pipe_name));
+
+ pipe_name = L"\\??\\_pipe_\\mypipe";
+ EXPECT_FALSE(IsPipe(pipe_name));
+
+ pipe_name = L"\\??\\ABCD\\mypipe";
+ EXPECT_FALSE(IsPipe(pipe_name));
+
+ // Written as two strings to prevent trigraph '?' '?' '/'.
+ pipe_name =
+ L"/?"
+ L"?/pipe/mypipe";
+ EXPECT_FALSE(IsPipe(pipe_name));
+
+ pipe_name = L"\\XX\\pipe\\mypipe";
+ EXPECT_FALSE(IsPipe(pipe_name));
+
+ pipe_name = L"\\Device\\NamedPipe\\mypipe";
+ EXPECT_FALSE(IsPipe(pipe_name));
+}
+
+TEST(WinUtils, NtStatusToWin32Error) {
+ using sandbox::GetLastErrorFromNtStatus;
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS),
+ GetLastErrorFromNtStatus(STATUS_SUCCESS));
+ EXPECT_EQ(static_cast<DWORD>(ERROR_NOT_SUPPORTED),
+ GetLastErrorFromNtStatus(STATUS_NOT_SUPPORTED));
+ EXPECT_EQ(static_cast<DWORD>(ERROR_ALREADY_EXISTS),
+ GetLastErrorFromNtStatus(STATUS_OBJECT_NAME_COLLISION));
+ EXPECT_EQ(static_cast<DWORD>(ERROR_ACCESS_DENIED),
+ GetLastErrorFromNtStatus(STATUS_ACCESS_DENIED));
+}
+
+TEST(WinUtils, GetProcessBaseAddress) {
+ using sandbox::GetProcessBaseAddress;
+ STARTUPINFO start_info = {};
+ PROCESS_INFORMATION proc_info = {};
+ WCHAR command_line[] = L"notepad";
+ start_info.cb = sizeof(start_info);
+ start_info.dwFlags = STARTF_USESHOWWINDOW;
+ start_info.wShowWindow = SW_HIDE;
+ ASSERT_TRUE(::CreateProcessW(nullptr, command_line, nullptr, nullptr, false,
+ CREATE_SUSPENDED, nullptr, nullptr, &start_info,
+ &proc_info));
+ base::win::ScopedProcessInformation scoped_proc_info(proc_info);
+ ScopedTerminateProcess process_terminate(scoped_proc_info.process_handle());
+ void* base_address = GetProcessBaseAddress(scoped_proc_info.process_handle());
+ ASSERT_NE(nullptr, base_address);
+ ASSERT_NE(static_cast<DWORD>(-1),
+ ::ResumeThread(scoped_proc_info.thread_handle()));
+ ::WaitForInputIdle(scoped_proc_info.process_handle(), 1000);
+ ASSERT_NE(static_cast<DWORD>(-1),
+ ::SuspendThread(scoped_proc_info.thread_handle()));
+
+ std::vector<HMODULE> modules;
+ // Compare against the loader's module list (which should now be initialized).
+ ASSERT_TRUE(GetModuleList(scoped_proc_info.process_handle(), &modules));
+ ASSERT_GT(modules.size(), 0U);
+ EXPECT_EQ(base_address, modules[0]);
+}
+
+// This test requires an elevated prompt to setup.
+TEST(WinUtils, ConvertToLongPath) {
+ // Test setup.
+ base::FilePath orig_path;
+ ASSERT_TRUE(base::PathService::Get(base::DIR_SYSTEM, &orig_path));
+ orig_path = orig_path.Append(L"calc.exe");
+
+ base::FilePath temp_path;
+ ASSERT_TRUE(base::PathService::Get(base::DIR_PROGRAM_FILES, &temp_path));
+ temp_path = temp_path.Append(L"test_calc.exe");
+
+ ASSERT_TRUE(base::CopyFile(orig_path, temp_path));
+ // No more asserts until cleanup.
+
+ // WIN32 long path: "c:\Program Files\test_calc.exe"
+ wchar_t short_path[MAX_PATH] = {};
+ DWORD size =
+ ::GetShortPathNameW(temp_path.value().c_str(), short_path, MAX_PATH);
+ EXPECT_TRUE(size > 0 && size < MAX_PATH);
+ // WIN32 short path: "C:\PROGRA~1\TEST_C~1.exe"
+
+ // Sanity check that we actually got a short path above! Small chance
+ // it was disabled in the filesystem setup.
+ EXPECT_NE(temp_path.value().length(), ::wcslen(short_path));
+
+ std::wstring short_form_native_path;
+ EXPECT_TRUE(sandbox::GetNtPathFromWin32Path(std::wstring(short_path),
+ &short_form_native_path));
+ // NT short path: "\Device\HarddiskVolume4\PROGRA~1\TEST_C~1.EXE"
+
+ // Test 1: convert win32 short path to long:
+ std::wstring test1(short_path);
+ EXPECT_TRUE(sandbox::ConvertToLongPath(&test1));
+ EXPECT_TRUE(::wcsicmp(temp_path.value().c_str(), test1.c_str()) == 0);
+ // Expected result: "c:\Program Files\test_calc.exe"
+
+ // Test 2: convert native short path to long:
+ std::wstring drive_letter = temp_path.value().substr(0, 3);
+ std::wstring test2(short_form_native_path);
+ EXPECT_TRUE(sandbox::ConvertToLongPath(&test2, &drive_letter));
+
+ size_t index = short_form_native_path.find_first_of(
+ L'\\', ::wcslen(L"\\Device\\HarddiskVolume"));
+ EXPECT_TRUE(index != std::wstring::npos);
+ std::wstring expected_result = short_form_native_path.substr(0, index + 1);
+ expected_result.append(temp_path.value().substr(3));
+ EXPECT_TRUE(::wcsicmp(expected_result.c_str(), test2.c_str()) == 0);
+ // Expected result: "\Device\HarddiskVolumeX\Program Files\test_calc.exe"
+
+ // clean up
+ EXPECT_TRUE(base::DeleteFileW(temp_path, false));
+
+ return;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/window.cc b/security/sandbox/chromium/sandbox/win/src/window.cc
new file mode 100644
index 0000000000..27645a9006
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/window.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sandbox/win/src/window.h"
+
+#include <aclapi.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/win/win_util.h"
+#include "sandbox/win/src/acl.h"
+#include "sandbox/win/src/sid.h"
+
+namespace {
+
+// Gets the security attributes of a window object referenced by |handle|. The
+// lpSecurityDescriptor member of the SECURITY_ATTRIBUTES parameter returned
+// must be freed using LocalFree by the caller.
+bool GetSecurityAttributes(HANDLE handle, SECURITY_ATTRIBUTES* attributes) {
+ attributes->bInheritHandle = false;
+ attributes->nLength = sizeof(SECURITY_ATTRIBUTES);
+
+ PACL dacl = nullptr;
+ DWORD result = ::GetSecurityInfo(
+ handle, SE_WINDOW_OBJECT, DACL_SECURITY_INFORMATION, nullptr, nullptr,
+ &dacl, nullptr, &attributes->lpSecurityDescriptor);
+ if (ERROR_SUCCESS == result)
+ return true;
+
+ return false;
+}
+
+} // namespace
+
+namespace sandbox {
+
+ResultCode CreateAltWindowStation(HWINSTA* winsta) {
+ // Get the security attributes from the current window station; we will
+ // use this as the base security attributes for the new window station.
+ HWINSTA current_winsta = ::GetProcessWindowStation();
+ if (!current_winsta)
+ return SBOX_ERROR_CANNOT_GET_WINSTATION;
+
+ SECURITY_ATTRIBUTES attributes = {0};
+ if (!GetSecurityAttributes(current_winsta, &attributes))
+ return SBOX_ERROR_CANNOT_QUERY_WINSTATION_SECURITY;
+
+ // Create the window station using nullptr for the name to ask the os to
+ // generate it.
+ *winsta = ::CreateWindowStationW(
+ nullptr, 0, GENERIC_READ | WINSTA_CREATEDESKTOP, &attributes);
+ if (!*winsta && ::GetLastError() == ERROR_ACCESS_DENIED) {
+ *winsta = ::CreateWindowStationW(
+ nullptr, 0, WINSTA_READATTRIBUTES | WINSTA_CREATEDESKTOP, &attributes);
+ }
+ LocalFree(attributes.lpSecurityDescriptor);
+
+ if (*winsta)
+ return SBOX_ALL_OK;
+
+ return SBOX_ERROR_CANNOT_CREATE_WINSTATION;
+}
+
+ResultCode CreateAltDesktop(HWINSTA winsta, HDESK* desktop) {
+ std::wstring desktop_name = L"sbox_alternate_desktop_";
+
+ if (!winsta) {
+ desktop_name += L"local_winstation_";
+ }
+
+ // Append the current PID to the desktop name.
+ wchar_t buffer[16];
+ _snwprintf_s(buffer, sizeof(buffer) / sizeof(wchar_t), L"0x%X",
+ ::GetCurrentProcessId());
+ desktop_name += buffer;
+
+ HDESK current_desktop = GetThreadDesktop(GetCurrentThreadId());
+
+ if (!current_desktop)
+ return SBOX_ERROR_CANNOT_GET_DESKTOP;
+
+ // Get the security attributes from the current desktop, we will use this as
+ // the base security attributes for the new desktop.
+ SECURITY_ATTRIBUTES attributes = {0};
+ if (!GetSecurityAttributes(current_desktop, &attributes))
+ return SBOX_ERROR_CANNOT_QUERY_DESKTOP_SECURITY;
+
+ // Back up the current window station, in case we need to switch it.
+ HWINSTA current_winsta = ::GetProcessWindowStation();
+
+ if (winsta) {
+ // We need to switch to the alternate window station before creating the
+ // desktop.
+ if (!::SetProcessWindowStation(winsta)) {
+ ::LocalFree(attributes.lpSecurityDescriptor);
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+ }
+ }
+
+ // Create the destkop.
+ *desktop = ::CreateDesktop(desktop_name.c_str(), nullptr, nullptr, 0,
+ DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS |
+ READ_CONTROL | WRITE_DAC | WRITE_OWNER,
+ &attributes);
+ ::LocalFree(attributes.lpSecurityDescriptor);
+
+ if (winsta) {
+ // Revert to the right window station.
+ if (!::SetProcessWindowStation(current_winsta)) {
+ return SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION;
+ }
+ }
+
+ if (*desktop) {
+ // Replace the DACL on the new Desktop with a reduced privilege version.
+ // We can soft fail on this for now, as it's just an extra mitigation.
+ static const ACCESS_MASK kDesktopDenyMask =
+ WRITE_DAC | WRITE_OWNER | DELETE | DESKTOP_CREATEMENU |
+ DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALPLAYBACK |
+ DESKTOP_JOURNALRECORD | DESKTOP_SWITCHDESKTOP;
+ AddKnownSidToObject(*desktop, SE_WINDOW_OBJECT, Sid(WinRestrictedCodeSid),
+ DENY_ACCESS, kDesktopDenyMask);
+ return SBOX_ALL_OK;
+ }
+
+ return SBOX_ERROR_CANNOT_CREATE_DESKTOP;
+}
+
+std::wstring GetFullDesktopName(HWINSTA winsta, HDESK desktop) {
+ if (!desktop) {
+ NOTREACHED();
+ return std::wstring();
+ }
+
+ std::wstring name;
+ if (winsta) {
+ name = base::win::GetWindowObjectName(winsta);
+ name += L'\\';
+ }
+
+ name += base::win::GetWindowObjectName(desktop);
+ return name;
+}
+
+} // namespace sandbox
diff --git a/security/sandbox/chromium/sandbox/win/src/window.h b/security/sandbox/chromium/sandbox/win/src/window.h
new file mode 100644
index 0000000000..1fe5b6cc72
--- /dev/null
+++ b/security/sandbox/chromium/sandbox/win/src/window.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SANDBOX_SRC_WINDOW_H_
+#define SANDBOX_SRC_WINDOW_H_
+
+#include <windows.h>
+
+#include <string>
+
+#include "sandbox/win/src/sandbox_types.h"
+
+namespace sandbox {
+
+// Creates a window station. The name is generated by the OS. The security
+// descriptor is based on the security descriptor of the current window
+// station.
+ResultCode CreateAltWindowStation(HWINSTA* winsta);
+
+// Creates a desktop. The name is a static string followed by the pid of the
+// current process. The security descriptor on the new desktop is based on the
+// security descriptor of the desktop associated with the current thread.
+// If a winsta is specified, the function will switch to it before creating
+// the desktop. If the functions fails the switch back to the current winsta,
+// the function will return SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION.
+ResultCode CreateAltDesktop(HWINSTA winsta, HDESK* desktop);
+
+// Returns the name of the desktop referenced by |desktop|. If a window
+// station is specified, the name is prepended with the window station name,
+// followed by a backslash. This name can be used as the lpDesktop parameter
+// to CreateProcess.
+std::wstring GetFullDesktopName(HWINSTA winsta, HDESK desktop);
+
+} // namespace sandbox
+
+#endif // SANDBOX_SRC_WINDOW_H_