xref: /aosp_15_r20/system/core/init/security.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker  *
4*00c7fec1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker  *
8*00c7fec1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker  *
10*00c7fec1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker  * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker  */
16*00c7fec1SAndroid Build Coastguard Worker 
17*00c7fec1SAndroid Build Coastguard Worker #include "security.h"
18*00c7fec1SAndroid Build Coastguard Worker #include "util.h"
19*00c7fec1SAndroid Build Coastguard Worker 
20*00c7fec1SAndroid Build Coastguard Worker #include <errno.h>
21*00c7fec1SAndroid Build Coastguard Worker #include <fcntl.h>
22*00c7fec1SAndroid Build Coastguard Worker #include <linux/perf_event.h>
23*00c7fec1SAndroid Build Coastguard Worker #include <math.h>
24*00c7fec1SAndroid Build Coastguard Worker #include <selinux/selinux.h>
25*00c7fec1SAndroid Build Coastguard Worker #include <sys/ioctl.h>
26*00c7fec1SAndroid Build Coastguard Worker #include <sys/syscall.h>
27*00c7fec1SAndroid Build Coastguard Worker #include <unistd.h>
28*00c7fec1SAndroid Build Coastguard Worker 
29*00c7fec1SAndroid Build Coastguard Worker #include <fstream>
30*00c7fec1SAndroid Build Coastguard Worker 
31*00c7fec1SAndroid Build Coastguard Worker #include <android-base/logging.h>
32*00c7fec1SAndroid Build Coastguard Worker #include <android-base/properties.h>
33*00c7fec1SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
34*00c7fec1SAndroid Build Coastguard Worker 
35*00c7fec1SAndroid Build Coastguard Worker using android::base::unique_fd;
36*00c7fec1SAndroid Build Coastguard Worker using android::base::SetProperty;
37*00c7fec1SAndroid Build Coastguard Worker 
38*00c7fec1SAndroid Build Coastguard Worker namespace android {
39*00c7fec1SAndroid Build Coastguard Worker namespace init {
40*00c7fec1SAndroid Build Coastguard Worker 
SetHighestAvailableOptionValue(const std::string & path,int min,int max)41*00c7fec1SAndroid Build Coastguard Worker static bool SetHighestAvailableOptionValue(const std::string& path, int min, int max) {
42*00c7fec1SAndroid Build Coastguard Worker     std::ifstream inf(path, std::fstream::in);
43*00c7fec1SAndroid Build Coastguard Worker     if (!inf) {
44*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "Cannot open for reading: " << path;
45*00c7fec1SAndroid Build Coastguard Worker         return false;
46*00c7fec1SAndroid Build Coastguard Worker     }
47*00c7fec1SAndroid Build Coastguard Worker 
48*00c7fec1SAndroid Build Coastguard Worker     int current = max;
49*00c7fec1SAndroid Build Coastguard Worker     while (current >= min) {
50*00c7fec1SAndroid Build Coastguard Worker         // try to write out new value
51*00c7fec1SAndroid Build Coastguard Worker         std::string str_val = std::to_string(current);
52*00c7fec1SAndroid Build Coastguard Worker         std::ofstream of(path, std::fstream::out);
53*00c7fec1SAndroid Build Coastguard Worker         if (!of) {
54*00c7fec1SAndroid Build Coastguard Worker             LOG(ERROR) << "Cannot open for writing: " << path;
55*00c7fec1SAndroid Build Coastguard Worker             return false;
56*00c7fec1SAndroid Build Coastguard Worker         }
57*00c7fec1SAndroid Build Coastguard Worker         of << str_val << std::endl;
58*00c7fec1SAndroid Build Coastguard Worker         of.close();
59*00c7fec1SAndroid Build Coastguard Worker 
60*00c7fec1SAndroid Build Coastguard Worker         // check to make sure it was recorded
61*00c7fec1SAndroid Build Coastguard Worker         inf.seekg(0);
62*00c7fec1SAndroid Build Coastguard Worker         std::string str_rec;
63*00c7fec1SAndroid Build Coastguard Worker         inf >> str_rec;
64*00c7fec1SAndroid Build Coastguard Worker         if (str_val.compare(str_rec) == 0) {
65*00c7fec1SAndroid Build Coastguard Worker             break;
66*00c7fec1SAndroid Build Coastguard Worker         }
67*00c7fec1SAndroid Build Coastguard Worker         current--;
68*00c7fec1SAndroid Build Coastguard Worker     }
69*00c7fec1SAndroid Build Coastguard Worker     inf.close();
70*00c7fec1SAndroid Build Coastguard Worker 
71*00c7fec1SAndroid Build Coastguard Worker     if (current < min) {
72*00c7fec1SAndroid Build Coastguard Worker         LOG(ERROR) << "Unable to set minimum option value " << min << " in " << path;
73*00c7fec1SAndroid Build Coastguard Worker         return false;
74*00c7fec1SAndroid Build Coastguard Worker     }
75*00c7fec1SAndroid Build Coastguard Worker     return true;
76*00c7fec1SAndroid Build Coastguard Worker }
77*00c7fec1SAndroid Build Coastguard Worker 
78*00c7fec1SAndroid Build Coastguard Worker #define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
79*00c7fec1SAndroid Build Coastguard Worker #define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
80*00c7fec1SAndroid Build Coastguard Worker 
SetMmapRndBitsMin(int start,int min,bool compat)81*00c7fec1SAndroid Build Coastguard Worker static bool SetMmapRndBitsMin(int start, int min, bool compat) {
82*00c7fec1SAndroid Build Coastguard Worker     std::string path;
83*00c7fec1SAndroid Build Coastguard Worker     if (compat) {
84*00c7fec1SAndroid Build Coastguard Worker         path = MMAP_RND_COMPAT_PATH;
85*00c7fec1SAndroid Build Coastguard Worker     } else {
86*00c7fec1SAndroid Build Coastguard Worker         path = MMAP_RND_PATH;
87*00c7fec1SAndroid Build Coastguard Worker     }
88*00c7fec1SAndroid Build Coastguard Worker 
89*00c7fec1SAndroid Build Coastguard Worker     return SetHighestAvailableOptionValue(path, min, start);
90*00c7fec1SAndroid Build Coastguard Worker }
91*00c7fec1SAndroid Build Coastguard Worker 
92*00c7fec1SAndroid Build Coastguard Worker // Set /proc/sys/vm/mmap_rnd_bits and potentially
93*00c7fec1SAndroid Build Coastguard Worker // /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
94*00c7fec1SAndroid Build Coastguard Worker // Returns an error if unable to set these to an acceptable value.
95*00c7fec1SAndroid Build Coastguard Worker //
96*00c7fec1SAndroid Build Coastguard Worker // To support this sysctl, the following upstream commits are needed:
97*00c7fec1SAndroid Build Coastguard Worker //
98*00c7fec1SAndroid Build Coastguard Worker // d07e22597d1d mm: mmap: add new /proc tunable for mmap_base ASLR
99*00c7fec1SAndroid Build Coastguard Worker // e0c25d958f78 arm: mm: support ARCH_MMAP_RND_BITS
100*00c7fec1SAndroid Build Coastguard Worker // 8f0d3aa9de57 arm64: mm: support ARCH_MMAP_RND_BITS
101*00c7fec1SAndroid Build Coastguard Worker // 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
102*00c7fec1SAndroid Build Coastguard Worker // ec9ee4acd97c drivers: char: random: add get_random_long()
103*00c7fec1SAndroid Build Coastguard Worker // 5ef11c35ce86 mm: ASLR: use get_random_long()
SetMmapRndBitsAction(const BuiltinArguments &)104*00c7fec1SAndroid Build Coastguard Worker Result<void> SetMmapRndBitsAction(const BuiltinArguments&) {
105*00c7fec1SAndroid Build Coastguard Worker // values are arch-dependent
106*00c7fec1SAndroid Build Coastguard Worker #if defined(USER_MODE_LINUX)
107*00c7fec1SAndroid Build Coastguard Worker     // uml does not support mmap_rnd_bits
108*00c7fec1SAndroid Build Coastguard Worker     return {};
109*00c7fec1SAndroid Build Coastguard Worker #elif defined(__aarch64__)
110*00c7fec1SAndroid Build Coastguard Worker     // arm64 supports 14 - 33 rnd bits depending on page size and ARM64_VA_BITS.
111*00c7fec1SAndroid Build Coastguard Worker     // The kernel (6.5) still defaults to 39 va bits for 4KiB pages, so shipping
112*00c7fec1SAndroid Build Coastguard Worker     // devices are only getting 24 bits of randomness in practice.
113*00c7fec1SAndroid Build Coastguard Worker     if (SetMmapRndBitsMin(33, 24, false) && (!Has32BitAbi() || SetMmapRndBitsMin(16, 16, true))) {
114*00c7fec1SAndroid Build Coastguard Worker         return {};
115*00c7fec1SAndroid Build Coastguard Worker     }
116*00c7fec1SAndroid Build Coastguard Worker #elif defined(__riscv)
117*00c7fec1SAndroid Build Coastguard Worker     // riscv64 supports 24 rnd bits with Sv39, and starting with the 6.9 kernel,
118*00c7fec1SAndroid Build Coastguard Worker     // 33 bits with Sv48 and Sv57.
119*00c7fec1SAndroid Build Coastguard Worker     if (SetMmapRndBitsMin(33, 24, false)) {
120*00c7fec1SAndroid Build Coastguard Worker         return {};
121*00c7fec1SAndroid Build Coastguard Worker     }
122*00c7fec1SAndroid Build Coastguard Worker #elif defined(__x86_64__)
123*00c7fec1SAndroid Build Coastguard Worker     // x86_64 supports 28 - 32 rnd bits, but Android wants to ensure that the
124*00c7fec1SAndroid Build Coastguard Worker     // theoretical maximum of 32 bits is always supported and used; except in
125*00c7fec1SAndroid Build Coastguard Worker     // the case of the x86 page size emulator which supports a maximum
126*00c7fec1SAndroid Build Coastguard Worker     // of 30 bits for 16k page size, or 28 bits for 64k page size.
127*00c7fec1SAndroid Build Coastguard Worker     int max_bits = 32 - (static_cast<int>(log2(getpagesize())) - 12);
128*00c7fec1SAndroid Build Coastguard Worker     if (SetMmapRndBitsMin(max_bits, max_bits, false) &&
129*00c7fec1SAndroid Build Coastguard Worker         (!Has32BitAbi() || SetMmapRndBitsMin(16, 16, true))) {
130*00c7fec1SAndroid Build Coastguard Worker         return {};
131*00c7fec1SAndroid Build Coastguard Worker     }
132*00c7fec1SAndroid Build Coastguard Worker #elif defined(__arm__) || defined(__i386__)
133*00c7fec1SAndroid Build Coastguard Worker     // check to see if we're running on 64-bit kernel
134*00c7fec1SAndroid Build Coastguard Worker     bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
135*00c7fec1SAndroid Build Coastguard Worker     // supported 32-bit architecture must have 16 bits set
136*00c7fec1SAndroid Build Coastguard Worker     if (SetMmapRndBitsMin(16, 16, h64)) {
137*00c7fec1SAndroid Build Coastguard Worker         return {};
138*00c7fec1SAndroid Build Coastguard Worker     }
139*00c7fec1SAndroid Build Coastguard Worker #else
140*00c7fec1SAndroid Build Coastguard Worker     LOG(ERROR) << "Unknown architecture";
141*00c7fec1SAndroid Build Coastguard Worker #endif
142*00c7fec1SAndroid Build Coastguard Worker 
143*00c7fec1SAndroid Build Coastguard Worker     LOG(FATAL) << "Unable to set adequate mmap entropy value!";
144*00c7fec1SAndroid Build Coastguard Worker     return Error();
145*00c7fec1SAndroid Build Coastguard Worker }
146*00c7fec1SAndroid Build Coastguard Worker 
147*00c7fec1SAndroid Build Coastguard Worker #define KPTR_RESTRICT_PATH "/proc/sys/kernel/kptr_restrict"
148*00c7fec1SAndroid Build Coastguard Worker #define KPTR_RESTRICT_MINVALUE 2
149*00c7fec1SAndroid Build Coastguard Worker #define KPTR_RESTRICT_MAXVALUE 4
150*00c7fec1SAndroid Build Coastguard Worker 
151*00c7fec1SAndroid Build Coastguard Worker // Set kptr_restrict to the highest available level.
152*00c7fec1SAndroid Build Coastguard Worker //
153*00c7fec1SAndroid Build Coastguard Worker // Aborts if unable to set this to an acceptable value.
SetKptrRestrictAction(const BuiltinArguments &)154*00c7fec1SAndroid Build Coastguard Worker Result<void> SetKptrRestrictAction(const BuiltinArguments&) {
155*00c7fec1SAndroid Build Coastguard Worker     std::string path = KPTR_RESTRICT_PATH;
156*00c7fec1SAndroid Build Coastguard Worker 
157*00c7fec1SAndroid Build Coastguard Worker     if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) {
158*00c7fec1SAndroid Build Coastguard Worker         LOG(FATAL) << "Unable to set adequate kptr_restrict value!";
159*00c7fec1SAndroid Build Coastguard Worker         return Error();
160*00c7fec1SAndroid Build Coastguard Worker     }
161*00c7fec1SAndroid Build Coastguard Worker     return {};
162*00c7fec1SAndroid Build Coastguard Worker }
163*00c7fec1SAndroid Build Coastguard Worker 
164*00c7fec1SAndroid Build Coastguard Worker // Test for whether the kernel has SELinux hooks for the perf_event_open()
165*00c7fec1SAndroid Build Coastguard Worker // syscall. If the hooks are present, we can stop using the other permission
166*00c7fec1SAndroid Build Coastguard Worker // mechanism (perf_event_paranoid sysctl), and use only the SELinux policy to
167*00c7fec1SAndroid Build Coastguard Worker // control access to the syscall. The hooks are expected on all Android R
168*00c7fec1SAndroid Build Coastguard Worker // release kernels, but might be absent on devices that upgrade while keeping an
169*00c7fec1SAndroid Build Coastguard Worker // older kernel.
170*00c7fec1SAndroid Build Coastguard Worker //
171*00c7fec1SAndroid Build Coastguard Worker // There is no direct/synchronous way of finding out that a syscall failed due
172*00c7fec1SAndroid Build Coastguard Worker // to SELinux. Therefore we test for a combination of a success and a failure
173*00c7fec1SAndroid Build Coastguard Worker // that are explained by the platform's SELinux policy for the "init" domain:
174*00c7fec1SAndroid Build Coastguard Worker // * cpu-scoped perf_event is allowed
175*00c7fec1SAndroid Build Coastguard Worker // * ioctl() on the event fd is disallowed with EACCES
176*00c7fec1SAndroid Build Coastguard Worker //
177*00c7fec1SAndroid Build Coastguard Worker // Since init has CAP_SYS_ADMIN, these tests are not affected by the system-wide
178*00c7fec1SAndroid Build Coastguard Worker // perf_event_paranoid sysctl.
179*00c7fec1SAndroid Build Coastguard Worker //
180*00c7fec1SAndroid Build Coastguard Worker // If the SELinux hooks are detected, a special sysprop
181*00c7fec1SAndroid Build Coastguard Worker // (sys.init.perf_lsm_hooks) is set, which translates to a modification of
182*00c7fec1SAndroid Build Coastguard Worker // perf_event_paranoid (through init.rc sysprop actions).
183*00c7fec1SAndroid Build Coastguard Worker //
184*00c7fec1SAndroid Build Coastguard Worker // TODO(b/137092007): this entire test can be removed once the platform stops
185*00c7fec1SAndroid Build Coastguard Worker // supporting kernels that precede the perf_event_open hooks (Android common
186*00c7fec1SAndroid Build Coastguard Worker // kernels 4.4 and 4.9).
TestPerfEventSelinuxAction(const BuiltinArguments &)187*00c7fec1SAndroid Build Coastguard Worker Result<void> TestPerfEventSelinuxAction(const BuiltinArguments&) {
188*00c7fec1SAndroid Build Coastguard Worker     // Special case: for *development devices* that boot with permissive
189*00c7fec1SAndroid Build Coastguard Worker     // SELinux, treat the LSM hooks as present for the effect of lowering the
190*00c7fec1SAndroid Build Coastguard Worker     // perf_event_paranoid sysctl. The sysprop is reused for pragmatic reasons,
191*00c7fec1SAndroid Build Coastguard Worker     // as there no existing way for init rules to check for permissive boot at
192*00c7fec1SAndroid Build Coastguard Worker     // the time of writing.
193*00c7fec1SAndroid Build Coastguard Worker     if (ALLOW_PERMISSIVE_SELINUX) {
194*00c7fec1SAndroid Build Coastguard Worker         if (!security_getenforce()) {
195*00c7fec1SAndroid Build Coastguard Worker             LOG(INFO) << "Permissive SELinux boot, forcing sys.init.perf_lsm_hooks to 1.";
196*00c7fec1SAndroid Build Coastguard Worker             SetProperty("sys.init.perf_lsm_hooks", "1");
197*00c7fec1SAndroid Build Coastguard Worker             return {};
198*00c7fec1SAndroid Build Coastguard Worker         }
199*00c7fec1SAndroid Build Coastguard Worker     }
200*00c7fec1SAndroid Build Coastguard Worker 
201*00c7fec1SAndroid Build Coastguard Worker     // Use a trivial event that will be configured, but not started.
202*00c7fec1SAndroid Build Coastguard Worker     struct perf_event_attr pe = {
203*00c7fec1SAndroid Build Coastguard Worker             .type = PERF_TYPE_SOFTWARE,
204*00c7fec1SAndroid Build Coastguard Worker             .size = sizeof(struct perf_event_attr),
205*00c7fec1SAndroid Build Coastguard Worker             .config = PERF_COUNT_SW_TASK_CLOCK,
206*00c7fec1SAndroid Build Coastguard Worker             .disabled = 1,
207*00c7fec1SAndroid Build Coastguard Worker             .exclude_kernel = 1,
208*00c7fec1SAndroid Build Coastguard Worker     };
209*00c7fec1SAndroid Build Coastguard Worker 
210*00c7fec1SAndroid Build Coastguard Worker     // Open the above event targeting cpu 0. (EINTR not possible.)
211*00c7fec1SAndroid Build Coastguard Worker     unique_fd fd(static_cast<int>(syscall(__NR_perf_event_open, &pe, /*pid=*/-1,
212*00c7fec1SAndroid Build Coastguard Worker                                           /*cpu=*/0,
213*00c7fec1SAndroid Build Coastguard Worker                                           /*group_fd=*/-1, /*flags=*/0)));
214*00c7fec1SAndroid Build Coastguard Worker     if (fd == -1) {
215*00c7fec1SAndroid Build Coastguard Worker         PLOG(ERROR) << "Unexpected perf_event_open error";
216*00c7fec1SAndroid Build Coastguard Worker         return {};
217*00c7fec1SAndroid Build Coastguard Worker     }
218*00c7fec1SAndroid Build Coastguard Worker 
219*00c7fec1SAndroid Build Coastguard Worker     int ioctl_ret = ioctl(fd.get(), PERF_EVENT_IOC_RESET);
220*00c7fec1SAndroid Build Coastguard Worker     if (ioctl_ret != -1) {
221*00c7fec1SAndroid Build Coastguard Worker         // Success implies that the kernel doesn't have the hooks.
222*00c7fec1SAndroid Build Coastguard Worker         return {};
223*00c7fec1SAndroid Build Coastguard Worker     } else if (errno != EACCES) {
224*00c7fec1SAndroid Build Coastguard Worker         PLOG(ERROR) << "Unexpected perf_event ioctl error";
225*00c7fec1SAndroid Build Coastguard Worker         return {};
226*00c7fec1SAndroid Build Coastguard Worker     }
227*00c7fec1SAndroid Build Coastguard Worker 
228*00c7fec1SAndroid Build Coastguard Worker     // Conclude that the SELinux hooks are present.
229*00c7fec1SAndroid Build Coastguard Worker     SetProperty("sys.init.perf_lsm_hooks", "1");
230*00c7fec1SAndroid Build Coastguard Worker     return {};
231*00c7fec1SAndroid Build Coastguard Worker }
232*00c7fec1SAndroid Build Coastguard Worker 
233*00c7fec1SAndroid Build Coastguard Worker }  // namespace init
234*00c7fec1SAndroid Build Coastguard Worker }  // namespace android
235