/src/abseil-cpp/absl/debugging/internal/address_is_readable.cc
Line  | Count  | Source  | 
1  |  | // Copyright 2017 The Abseil Authors.  | 
2  |  | //  | 
3  |  | // Licensed under the Apache License, Version 2.0 (the "License");  | 
4  |  | // you may not use this file except in compliance with the License.  | 
5  |  | // You may obtain a copy of the License at  | 
6  |  | //  | 
7  |  | //      https://www.apache.org/licenses/LICENSE-2.0  | 
8  |  | //  | 
9  |  | // Unless required by applicable law or agreed to in writing, software  | 
10  |  | // distributed under the License is distributed on an "AS IS" BASIS,  | 
11  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
12  |  | // See the License for the specific language governing permissions and  | 
13  |  | // limitations under the License.  | 
14  |  |  | 
15  |  | // base::AddressIsReadable() probes an address to see whether it is readable,  | 
16  |  | // without faulting.  | 
17  |  |  | 
18  |  | #include "absl/debugging/internal/address_is_readable.h"  | 
19  |  |  | 
20  |  | #if !defined(__linux__) || defined(__ANDROID__)  | 
21  |  |  | 
22  |  | namespace absl { | 
23  |  | ABSL_NAMESPACE_BEGIN  | 
24  |  | namespace debugging_internal { | 
25  |  |  | 
26  |  | // On platforms other than Linux, just return true.  | 
27  |  | bool AddressIsReadable(const void* /* addr */) { return true; } | 
28  |  |  | 
29  |  | }  // namespace debugging_internal  | 
30  |  | ABSL_NAMESPACE_END  | 
31  |  | }  // namespace absl  | 
32  |  |  | 
33  |  | #else  // __linux__ && !__ANDROID__  | 
34  |  |  | 
35  |  | #include <stdint.h>  | 
36  |  | #include <syscall.h>  | 
37  |  | #include <unistd.h>  | 
38  |  |  | 
39  |  | #include "absl/base/internal/errno_saver.h"  | 
40  |  | #include "absl/base/internal/raw_logging.h"  | 
41  |  |  | 
42  |  | namespace absl { | 
43  |  | ABSL_NAMESPACE_BEGIN  | 
44  |  | namespace debugging_internal { | 
45  |  |  | 
46  |  | // NOTE: be extra careful about adding any interposable function calls here  | 
47  |  | // (such as open(), read(), etc.). These symbols may be interposed and will get  | 
48  |  | // invoked in contexts they don't expect.  | 
49  |  | //  | 
50  |  | // NOTE: any new system calls here may also require sandbox reconfiguration.  | 
51  |  | //  | 
52  | 0  | bool AddressIsReadable(const void *addr) { | 
53  |  |   // rt_sigprocmask below checks 8 contiguous bytes. If addr resides in the  | 
54  |  |   // last 7 bytes of a page (unaligned), rt_sigprocmask would additionally  | 
55  |  |   // check the readability of the next page, which is not desired. Align  | 
56  |  |   // address on 8-byte boundary to check only the current page.  | 
57  | 0  |   const uintptr_t u_addr = reinterpret_cast<uintptr_t>(addr) & ~uintptr_t{7}; | 
58  | 0  |   addr = reinterpret_cast<const void *>(u_addr);  | 
59  |  |  | 
60  |  |   // rt_sigprocmask below will succeed for this input.  | 
61  | 0  |   if (addr == nullptr) return false;  | 
62  |  |  | 
63  | 0  |   absl::base_internal::ErrnoSaver errno_saver;  | 
64  |  |  | 
65  |  |   // Here we probe with some syscall which  | 
66  |  |   // - accepts an 8-byte region of user memory as input  | 
67  |  |   // - tests for EFAULT before other validation  | 
68  |  |   // - has no problematic side-effects  | 
69  |  |   //  | 
70  |  |   // rt_sigprocmask(2) works for this.  It copies sizeof(kernel_sigset_t)==8  | 
71  |  |   // bytes from the address into the kernel memory before any validation.  | 
72  |  |   //  | 
73  |  |   // The call can never succeed, since the `how` parameter is not one of  | 
74  |  |   // SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK.  | 
75  |  |   //  | 
76  |  |   // This strategy depends on Linux implementation details,  | 
77  |  |   // so we rely on the test to alert us if it stops working.  | 
78  |  |   //  | 
79  |  |   // Some discarded past approaches:  | 
80  |  |   // - msync() doesn't reject PROT_NONE regions  | 
81  |  |   // - write() on /dev/null doesn't return EFAULT  | 
82  |  |   // - write() on a pipe requires creating it and draining the writes  | 
83  |  |   // - connect() works but is problematic for sandboxes and needs a valid  | 
84  |  |   //   file descriptor  | 
85  |  |   //  | 
86  |  |   // This can never succeed (invalid first argument to sigprocmask).  | 
87  | 0  |   ABSL_RAW_CHECK(syscall(SYS_rt_sigprocmask, ~0, addr, nullptr,  | 
88  | 0  |                          /*sizeof(kernel_sigset_t)*/ 8) == -1,  | 
89  | 0  |                  "unexpected success");  | 
90  | 0  |   ABSL_RAW_CHECK(errno == EFAULT || errno == EINVAL, "unexpected errno");  | 
91  | 0  |   return errno != EFAULT;  | 
92  | 0  | }  | 
93  |  |  | 
94  |  | }  // namespace debugging_internal  | 
95  |  | ABSL_NAMESPACE_END  | 
96  |  | }  // namespace absl  | 
97  |  |  | 
98  |  | #endif  // __linux__ && !__ANDROID__  |