Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Tom Cherry | 7bfea3d | 2018-11-06 14:12:05 -0800 | [diff] [blame] | 17 | #include "first_stage_init.h" |
| 18 | |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 19 | #include <dirent.h> |
| 20 | #include <fcntl.h> |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 21 | #include <paths.h> |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 22 | #include <stdlib.h> |
| 23 | #include <sys/mount.h> |
| 24 | #include <sys/stat.h> |
| 25 | #include <sys/sysmacros.h> |
| 26 | #include <sys/types.h> |
Steve Muckle | d6d38c3 | 2020-05-29 16:31:19 -0700 | [diff] [blame] | 27 | #include <sys/utsname.h> |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 28 | #include <unistd.h> |
| 29 | |
Kelvin Zhang | 22929da | 2022-03-17 15:18:36 -0700 | [diff] [blame] | 30 | #include <chrono> |
Bowgo Tsai | 30afda7 | 2019-04-11 23:57:24 +0800 | [diff] [blame] | 31 | #include <filesystem> |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 32 | #include <string> |
| 33 | #include <vector> |
| 34 | |
| 35 | #include <android-base/chrono_utils.h> |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 36 | #include <android-base/file.h> |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 37 | #include <android-base/logging.h> |
Steve Muckle | 18b981e | 2019-04-15 17:43:02 -0700 | [diff] [blame] | 38 | #include <modprobe/modprobe.h> |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 39 | #include <private/android_filesystem_config.h> |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 40 | |
Bowgo Tsai | 30afda7 | 2019-04-11 23:57:24 +0800 | [diff] [blame] | 41 | #include "debug_ramdisk.h" |
Steve Muckle | a4bf2ce | 2019-11-01 13:58:02 -0700 | [diff] [blame] | 42 | #include "first_stage_console.h" |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 43 | #include "first_stage_mount.h" |
| 44 | #include "reboot_utils.h" |
Yifan Hong | a68ee76 | 2020-10-06 16:58:19 -0700 | [diff] [blame] | 45 | #include "second_stage_resources.h" |
David Anderson | 491e4da | 2020-12-08 00:21:20 -0800 | [diff] [blame] | 46 | #include "snapuserd_transition.h" |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 47 | #include "switch_root.h" |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 48 | #include "util.h" |
| 49 | |
| 50 | using android::base::boot_clock; |
| 51 | |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 52 | using namespace std::literals; |
| 53 | |
Bowgo Tsai | 30afda7 | 2019-04-11 23:57:24 +0800 | [diff] [blame] | 54 | namespace fs = std::filesystem; |
| 55 | |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 56 | namespace android { |
| 57 | namespace init { |
| 58 | |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 59 | namespace { |
| 60 | |
| 61 | void FreeRamdisk(DIR* dir, dev_t dev) { |
| 62 | int dfd = dirfd(dir); |
| 63 | |
| 64 | dirent* de; |
| 65 | while ((de = readdir(dir)) != nullptr) { |
| 66 | if (de->d_name == "."s || de->d_name == ".."s) { |
| 67 | continue; |
| 68 | } |
| 69 | |
| 70 | bool is_dir = false; |
| 71 | |
| 72 | if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) { |
| 73 | struct stat info; |
| 74 | if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) { |
| 75 | continue; |
| 76 | } |
| 77 | |
| 78 | if (info.st_dev != dev) { |
| 79 | continue; |
| 80 | } |
| 81 | |
| 82 | if (S_ISDIR(info.st_mode)) { |
| 83 | is_dir = true; |
Tom Cherry | 247ffbf | 2019-07-08 15:09:36 -0700 | [diff] [blame] | 84 | auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC); |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 85 | if (fd >= 0) { |
| 86 | auto subdir = |
| 87 | std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir}; |
| 88 | if (subdir) { |
| 89 | FreeRamdisk(subdir.get(), dev); |
| 90 | } else { |
| 91 | close(fd); |
| 92 | } |
| 93 | } |
| 94 | } |
David Anderson | 491e4da | 2020-12-08 00:21:20 -0800 | [diff] [blame] | 95 | } else if (de->d_type == DT_REG) { |
| 96 | // Do not free snapuserd if we will need the ramdisk copy during the |
| 97 | // selinux transition. |
| 98 | if (de->d_name == "snapuserd"s && IsFirstStageSnapuserdRunning()) { |
| 99 | continue; |
| 100 | } |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 101 | } |
| 102 | unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0); |
| 103 | } |
| 104 | } |
| 105 | |
Devin Moore | 7905848 | 2021-03-03 13:57:43 -0800 | [diff] [blame] | 106 | bool ForceNormalBoot(const std::string& cmdline, const std::string& bootconfig) { |
| 107 | return bootconfig.find("androidboot.force_normal_boot = \"1\"") != std::string::npos || |
| 108 | cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 109 | } |
| 110 | |
Kelvin Zhang | 22929da | 2022-03-17 15:18:36 -0700 | [diff] [blame] | 111 | static void Copy(const char* src, const char* dst) { |
| 112 | if (link(src, dst) == 0) { |
| 113 | LOG(INFO) << "hard linking " << src << " to " << dst << " succeeded"; |
| 114 | return; |
| 115 | } |
Kelvin Zhang | f887e74 | 2022-04-06 14:02:13 -0700 | [diff] [blame] | 116 | PLOG(FATAL) << "hard linking " << src << " to " << dst << " failed"; |
Kelvin Zhang | 22929da | 2022-03-17 15:18:36 -0700 | [diff] [blame] | 117 | } |
| 118 | |
Kelvin Zhang | f887e74 | 2022-04-06 14:02:13 -0700 | [diff] [blame] | 119 | // Move snapuserd before switching root, so that it is available at the same path |
Kelvin Zhang | 22929da | 2022-03-17 15:18:36 -0700 | [diff] [blame] | 120 | // after switching root. |
| 121 | void PrepareSwitchRoot() { |
| 122 | constexpr const char* src = "/system/bin/snapuserd"; |
| 123 | constexpr const char* dst = "/first_stage_ramdisk/system/bin/snapuserd"; |
| 124 | |
| 125 | if (access(dst, X_OK) == 0) { |
| 126 | LOG(INFO) << dst << " already exists and it can be executed"; |
| 127 | return; |
| 128 | } |
| 129 | |
| 130 | if (access(src, F_OK) != 0) { |
| 131 | PLOG(INFO) << "Not moving " << src << " because it cannot be accessed"; |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | auto dst_dir = android::base::Dirname(dst); |
| 136 | std::error_code ec; |
| 137 | if (access(dst_dir.c_str(), F_OK) != 0) { |
| 138 | if (!fs::create_directories(dst_dir, ec)) { |
| 139 | LOG(FATAL) << "Cannot create " << dst_dir << ": " << ec.message(); |
| 140 | } |
| 141 | } |
| 142 | Copy(src, dst); |
| 143 | } |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 144 | } // namespace |
| 145 | |
Steve Muckle | d6d38c3 | 2020-05-29 16:31:19 -0700 | [diff] [blame] | 146 | std::string GetModuleLoadList(bool recovery, const std::string& dir_path) { |
| 147 | auto module_load_file = "modules.load"; |
| 148 | if (recovery) { |
| 149 | struct stat fileStat; |
| 150 | std::string recovery_load_path = dir_path + "/modules.load.recovery"; |
| 151 | if (!stat(recovery_load_path.c_str(), &fileStat)) { |
| 152 | module_load_file = "modules.load.recovery"; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | return module_load_file; |
| 157 | } |
| 158 | |
| 159 | #define MODULE_BASE_DIR "/lib/modules" |
Chungkai | c60300a | 2021-02-03 20:30:07 -0800 | [diff] [blame] | 160 | bool LoadKernelModules(bool recovery, bool want_console, bool want_parallel, int& modules_loaded) { |
Steve Muckle | d6d38c3 | 2020-05-29 16:31:19 -0700 | [diff] [blame] | 161 | struct utsname uts; |
| 162 | if (uname(&uts)) { |
| 163 | LOG(FATAL) << "Failed to get kernel version."; |
| 164 | } |
| 165 | int major, minor; |
| 166 | if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) { |
| 167 | LOG(FATAL) << "Failed to parse kernel version " << uts.release; |
| 168 | } |
| 169 | |
| 170 | std::unique_ptr<DIR, decltype(&closedir)> base_dir(opendir(MODULE_BASE_DIR), closedir); |
| 171 | if (!base_dir) { |
| 172 | LOG(INFO) << "Unable to open /lib/modules, skipping module loading."; |
| 173 | return true; |
| 174 | } |
| 175 | dirent* entry; |
| 176 | std::vector<std::string> module_dirs; |
| 177 | while ((entry = readdir(base_dir.get()))) { |
| 178 | if (entry->d_type != DT_DIR) { |
| 179 | continue; |
| 180 | } |
| 181 | int dir_major, dir_minor; |
| 182 | if (sscanf(entry->d_name, "%d.%d", &dir_major, &dir_minor) != 2 || dir_major != major || |
| 183 | dir_minor != minor) { |
| 184 | continue; |
| 185 | } |
| 186 | module_dirs.emplace_back(entry->d_name); |
| 187 | } |
| 188 | |
| 189 | // Sort the directories so they are iterated over during module loading |
| 190 | // in a consistent order. Alphabetical sorting is fine here because the |
| 191 | // kernel version at the beginning of the directory name must match the |
| 192 | // current kernel version, so the sort only applies to a label that |
| 193 | // follows the kernel version, for example /lib/modules/5.4 vs. |
| 194 | // /lib/modules/5.4-gki. |
| 195 | std::sort(module_dirs.begin(), module_dirs.end()); |
| 196 | |
| 197 | for (const auto& module_dir : module_dirs) { |
| 198 | std::string dir_path = MODULE_BASE_DIR "/"; |
| 199 | dir_path.append(module_dir); |
| 200 | Modprobe m({dir_path}, GetModuleLoadList(recovery, dir_path)); |
| 201 | bool retval = m.LoadListedModules(!want_console); |
Lisa Liu | 08c862f | 2021-02-03 18:22:21 +0800 | [diff] [blame] | 202 | modules_loaded = m.GetModuleCount(); |
Steve Muckle | d6d38c3 | 2020-05-29 16:31:19 -0700 | [diff] [blame] | 203 | if (modules_loaded > 0) { |
| 204 | return retval; |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | Modprobe m({MODULE_BASE_DIR}, GetModuleLoadList(recovery, MODULE_BASE_DIR)); |
Chungkai | c60300a | 2021-02-03 20:30:07 -0800 | [diff] [blame] | 209 | bool retval = (want_parallel) ? m.LoadModulesParallel(std::thread::hardware_concurrency()) |
| 210 | : m.LoadListedModules(!want_console); |
Lisa Liu | 08c862f | 2021-02-03 18:22:21 +0800 | [diff] [blame] | 211 | modules_loaded = m.GetModuleCount(); |
Steve Muckle | d6d38c3 | 2020-05-29 16:31:19 -0700 | [diff] [blame] | 212 | if (modules_loaded > 0) { |
| 213 | return retval; |
| 214 | } |
| 215 | return true; |
| 216 | } |
| 217 | |
Tom Cherry | 7bfea3d | 2018-11-06 14:12:05 -0800 | [diff] [blame] | 218 | int FirstStageMain(int argc, char** argv) { |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 219 | if (REBOOT_BOOTLOADER_ON_PANIC) { |
| 220 | InstallRebootSignalHandlers(); |
| 221 | } |
| 222 | |
| 223 | boot_clock::time_point start_time = boot_clock::now(); |
| 224 | |
| 225 | std::vector<std::pair<std::string, int>> errors; |
| 226 | #define CHECKCALL(x) \ |
Tom Cherry | 247ffbf | 2019-07-08 15:09:36 -0700 | [diff] [blame] | 227 | if ((x) != 0) errors.emplace_back(#x " failed", errno); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 228 | |
| 229 | // Clear the umask. |
| 230 | umask(0); |
| 231 | |
| 232 | CHECKCALL(clearenv()); |
| 233 | CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1)); |
| 234 | // Get the basic filesystem setup we need put together in the initramdisk |
| 235 | // on / and then we'll let the rc file figure out the rest. |
| 236 | CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755")); |
| 237 | CHECKCALL(mkdir("/dev/pts", 0755)); |
| 238 | CHECKCALL(mkdir("/dev/socket", 0755)); |
David Anderson | 1ff7581 | 2020-11-13 00:31:47 -0800 | [diff] [blame] | 239 | CHECKCALL(mkdir("/dev/dm-user", 0755)); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 240 | CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL)); |
| 241 | #define MAKE_STR(x) __STRING(x) |
| 242 | CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC))); |
| 243 | #undef MAKE_STR |
| 244 | // Don't expose the raw commandline to unprivileged processes. |
| 245 | CHECKCALL(chmod("/proc/cmdline", 0440)); |
Steve Muckle | d75f30a | 2019-05-21 15:50:39 -0700 | [diff] [blame] | 246 | std::string cmdline; |
| 247 | android::base::ReadFileToString("/proc/cmdline", &cmdline); |
Devin Moore | a4ef15b | 2020-12-15 16:14:37 -0800 | [diff] [blame] | 248 | // Don't expose the raw bootconfig to unprivileged processes. |
| 249 | chmod("/proc/bootconfig", 0440); |
Devin Moore | 7905848 | 2021-03-03 13:57:43 -0800 | [diff] [blame] | 250 | std::string bootconfig; |
| 251 | android::base::ReadFileToString("/proc/bootconfig", &bootconfig); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 252 | gid_t groups[] = {AID_READPROC}; |
| 253 | CHECKCALL(setgroups(arraysize(groups), groups)); |
| 254 | CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); |
| 255 | CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL)); |
| 256 | |
| 257 | CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11))); |
| 258 | |
| 259 | if constexpr (WORLD_WRITABLE_KMSG) { |
| 260 | CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11))); |
| 261 | } |
| 262 | |
| 263 | CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8))); |
| 264 | CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9))); |
| 265 | |
| 266 | // This is needed for log wrapper, which gets called before ueventd runs. |
| 267 | CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2))); |
| 268 | CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3))); |
| 269 | |
Tom Cherry | 21824dd | 2018-10-02 10:07:05 -0700 | [diff] [blame] | 270 | // These below mounts are done in first stage init so that first stage mount can mount |
| 271 | // subdirectories of /mnt/{vendor,product}/. Other mounts, not required by first stage mount, |
| 272 | // should be done in rc files. |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 273 | // Mount staging areas for devices managed by vold |
| 274 | // See storage config details at http://source.android.com/devices/storage/ |
| 275 | CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, |
| 276 | "mode=0755,uid=0,gid=1000")); |
| 277 | // /mnt/vendor is used to mount vendor-specific partitions that can not be |
| 278 | // part of the vendor partition, e.g. because they are mounted read-write. |
| 279 | CHECKCALL(mkdir("/mnt/vendor", 0755)); |
| 280 | // /mnt/product is used to mount product-specific partitions that can not be |
| 281 | // part of the product partition, e.g. because they are mounted read-write. |
| 282 | CHECKCALL(mkdir("/mnt/product", 0755)); |
| 283 | |
Bowgo Tsai | 30afda7 | 2019-04-11 23:57:24 +0800 | [diff] [blame] | 284 | // /debug_ramdisk is used to preserve additional files from the debug ramdisk |
| 285 | CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, |
| 286 | "mode=0755,uid=0,gid=0")); |
Yifan Hong | a68ee76 | 2020-10-06 16:58:19 -0700 | [diff] [blame] | 287 | |
| 288 | // /second_stage_resources is used to preserve files from first to second |
| 289 | // stage init |
| 290 | CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, |
| 291 | "mode=0755,uid=0,gid=0")) |
Jeffrey Vander Stoep | baeece6 | 2022-02-08 12:42:33 +0000 | [diff] [blame] | 292 | |
| 293 | // First stage init stores Mainline sepolicy here. |
| 294 | CHECKCALL(mkdir("/dev/selinux", 0744)); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 295 | #undef CHECKCALL |
| 296 | |
Tom Cherry | 59656fb | 2019-05-28 10:19:44 -0700 | [diff] [blame] | 297 | SetStdioToDevNull(argv); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 298 | // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually |
| 299 | // talk to the outside world... |
Tom Cherry | 59656fb | 2019-05-28 10:19:44 -0700 | [diff] [blame] | 300 | InitKernelLogging(argv); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 301 | |
| 302 | if (!errors.empty()) { |
| 303 | for (const auto& [error_string, error_errno] : errors) { |
| 304 | LOG(ERROR) << error_string << " " << strerror(error_errno); |
| 305 | } |
| 306 | LOG(FATAL) << "Init encountered errors starting first stage, aborting"; |
| 307 | } |
| 308 | |
| 309 | LOG(INFO) << "init first stage started!"; |
| 310 | |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 311 | auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir}; |
| 312 | if (!old_root_dir) { |
| 313 | PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk"; |
| 314 | } |
| 315 | |
| 316 | struct stat old_root_info; |
| 317 | if (stat("/", &old_root_info) != 0) { |
| 318 | PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; |
| 319 | old_root_dir.reset(); |
| 320 | } |
| 321 | |
Devin Moore | 7905848 | 2021-03-03 13:57:43 -0800 | [diff] [blame] | 322 | auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0; |
Chungkai | c60300a | 2021-02-03 20:30:07 -0800 | [diff] [blame] | 323 | auto want_parallel = |
| 324 | bootconfig.find("androidboot.load_modules_parallel = \"true\"") != std::string::npos; |
Steve Muckle | d6d38c3 | 2020-05-29 16:31:19 -0700 | [diff] [blame] | 325 | |
Lisa Liu | 08c862f | 2021-02-03 18:22:21 +0800 | [diff] [blame] | 326 | boot_clock::time_point module_start_time = boot_clock::now(); |
| 327 | int module_count = 0; |
Devin Moore | 7905848 | 2021-03-03 13:57:43 -0800 | [diff] [blame] | 328 | if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), want_console, |
Chungkai | c60300a | 2021-02-03 20:30:07 -0800 | [diff] [blame] | 329 | want_parallel, module_count)) { |
Will McVicker | c890742 | 2020-05-01 16:47:12 -0700 | [diff] [blame] | 330 | if (want_console != FirstStageConsoleParam::DISABLED) { |
Mark Salyzyn | a7144f7 | 2019-10-31 08:02:10 -0700 | [diff] [blame] | 331 | LOG(ERROR) << "Failed to load kernel modules, starting console"; |
| 332 | } else { |
| 333 | LOG(FATAL) << "Failed to load kernel modules"; |
| 334 | } |
Steve Muckle | 18b981e | 2019-04-15 17:43:02 -0700 | [diff] [blame] | 335 | } |
Lisa Liu | 08c862f | 2021-02-03 18:22:21 +0800 | [diff] [blame] | 336 | if (module_count > 0) { |
| 337 | auto module_elapse_time = std::chrono::duration_cast<std::chrono::milliseconds>( |
| 338 | boot_clock::now() - module_start_time); |
| 339 | setenv(kEnvInitModuleDurationMs, std::to_string(module_elapse_time.count()).c_str(), 1); |
| 340 | LOG(INFO) << "Loaded " << module_count << " kernel modules took " |
| 341 | << module_elapse_time.count() << " ms"; |
| 342 | } |
Steve Muckle | 18b981e | 2019-04-15 17:43:02 -0700 | [diff] [blame] | 343 | |
Elliot Berman | d96d0f7 | 2021-01-25 09:53:36 -0800 | [diff] [blame] | 344 | bool created_devices = false; |
Will McVicker | c890742 | 2020-05-01 16:47:12 -0700 | [diff] [blame] | 345 | if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) { |
Elliot Berman | d96d0f7 | 2021-01-25 09:53:36 -0800 | [diff] [blame] | 346 | if (!IsRecoveryMode()) { |
| 347 | created_devices = DoCreateDevices(); |
Kelvin Zhang | 22929da | 2022-03-17 15:18:36 -0700 | [diff] [blame] | 348 | if (!created_devices) { |
Elliot Berman | d96d0f7 | 2021-01-25 09:53:36 -0800 | [diff] [blame] | 349 | LOG(ERROR) << "Failed to create device nodes early"; |
| 350 | } |
| 351 | } |
Steve Muckle | cc3410e | 2020-11-02 15:31:19 -0800 | [diff] [blame] | 352 | StartConsole(cmdline); |
Steve Muckle | d75f30a | 2019-05-21 15:50:39 -0700 | [diff] [blame] | 353 | } |
| 354 | |
Yifan Hong | a68ee76 | 2020-10-06 16:58:19 -0700 | [diff] [blame] | 355 | if (access(kBootImageRamdiskProp, F_OK) == 0) { |
| 356 | std::string dest = GetRamdiskPropForSecondStage(); |
| 357 | std::string dir = android::base::Dirname(dest); |
| 358 | std::error_code ec; |
Yifan Hong | 7e7f881 | 2020-11-19 12:12:11 -0800 | [diff] [blame] | 359 | if (!fs::create_directories(dir, ec) && !!ec) { |
Yifan Hong | a68ee76 | 2020-10-06 16:58:19 -0700 | [diff] [blame] | 360 | LOG(FATAL) << "Can't mkdir " << dir << ": " << ec.message(); |
| 361 | } |
| 362 | if (!fs::copy_file(kBootImageRamdiskProp, dest, ec)) { |
| 363 | LOG(FATAL) << "Can't copy " << kBootImageRamdiskProp << " to " << dest << ": " |
| 364 | << ec.message(); |
| 365 | } |
| 366 | LOG(INFO) << "Copied ramdisk prop to " << dest; |
| 367 | } |
| 368 | |
Bowgo Tsai | 64e92f9 | 2021-04-23 11:16:58 +0800 | [diff] [blame] | 369 | // If "/force_debuggable" is present, the second-stage init will use a userdebug |
| 370 | // sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked. |
| 371 | if (access("/force_debuggable", F_OK) == 0) { |
Yi-Yo Chiang | bb77c54 | 2021-09-23 14:14:16 +0000 | [diff] [blame] | 372 | constexpr const char adb_debug_prop_src[] = "/adb_debug.prop"; |
| 373 | constexpr const char userdebug_plat_sepolicy_cil_src[] = "/userdebug_plat_sepolicy.cil"; |
Bowgo Tsai | 64e92f9 | 2021-04-23 11:16:58 +0800 | [diff] [blame] | 374 | std::error_code ec; // to invoke the overloaded copy_file() that won't throw. |
Yi-Yo Chiang | bb77c54 | 2021-09-23 14:14:16 +0000 | [diff] [blame] | 375 | if (access(adb_debug_prop_src, F_OK) == 0 && |
| 376 | !fs::copy_file(adb_debug_prop_src, kDebugRamdiskProp, ec)) { |
| 377 | LOG(WARNING) << "Can't copy " << adb_debug_prop_src << " to " << kDebugRamdiskProp |
| 378 | << ": " << ec.message(); |
Bowgo Tsai | 64e92f9 | 2021-04-23 11:16:58 +0800 | [diff] [blame] | 379 | } |
Yi-Yo Chiang | bb77c54 | 2021-09-23 14:14:16 +0000 | [diff] [blame] | 380 | if (access(userdebug_plat_sepolicy_cil_src, F_OK) == 0 && |
| 381 | !fs::copy_file(userdebug_plat_sepolicy_cil_src, kDebugRamdiskSEPolicy, ec)) { |
| 382 | LOG(WARNING) << "Can't copy " << userdebug_plat_sepolicy_cil_src << " to " |
| 383 | << kDebugRamdiskSEPolicy << ": " << ec.message(); |
| 384 | } |
| 385 | // setenv for second-stage init to read above kDebugRamdisk* files. |
| 386 | setenv("INIT_FORCE_DEBUGGABLE", "true", 1); |
Bowgo Tsai | 64e92f9 | 2021-04-23 11:16:58 +0800 | [diff] [blame] | 387 | } |
| 388 | |
Devin Moore | 7905848 | 2021-03-03 13:57:43 -0800 | [diff] [blame] | 389 | if (ForceNormalBoot(cmdline, bootconfig)) { |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 390 | mkdir("/first_stage_ramdisk", 0755); |
Kelvin Zhang | 22929da | 2022-03-17 15:18:36 -0700 | [diff] [blame] | 391 | PrepareSwitchRoot(); |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 392 | // SwitchRoot() must be called with a mount point as the target, so we bind mount the |
| 393 | // target directory to itself here. |
| 394 | if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) { |
Kelvin Zhang | 22929da | 2022-03-17 15:18:36 -0700 | [diff] [blame] | 395 | PLOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself"; |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 396 | } |
| 397 | SwitchRoot("/first_stage_ramdisk"); |
| 398 | } |
| 399 | |
Elliot Berman | d96d0f7 | 2021-01-25 09:53:36 -0800 | [diff] [blame] | 400 | if (!DoFirstStageMount(!created_devices)) { |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 401 | LOG(FATAL) << "Failed to mount required partitions early ..."; |
| 402 | } |
| 403 | |
Tom Cherry | 866c08c | 2018-11-06 10:32:53 -0800 | [diff] [blame] | 404 | struct stat new_root_info; |
| 405 | if (stat("/", &new_root_info) != 0) { |
| 406 | PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk"; |
| 407 | old_root_dir.reset(); |
| 408 | } |
| 409 | |
| 410 | if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) { |
| 411 | FreeRamdisk(old_root_dir.get(), old_root_info.st_dev); |
| 412 | } |
| 413 | |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 414 | SetInitAvbVersionInRecovery(); |
| 415 | |
Mark Salyzyn | 44505ec | 2019-05-08 12:44:50 -0700 | [diff] [blame] | 416 | setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), |
Mark Salyzyn | 10377df | 2019-03-27 08:10:41 -0700 | [diff] [blame] | 417 | 1); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 418 | |
Tom Cherry | 3143848 | 2018-07-20 14:57:00 -0700 | [diff] [blame] | 419 | const char* path = "/system/bin/init"; |
Tom Cherry | 7bfea3d | 2018-11-06 14:12:05 -0800 | [diff] [blame] | 420 | const char* args[] = {path, "selinux_setup", nullptr}; |
Mark Salyzyn | beb6abe | 2019-07-29 09:35:18 -0700 | [diff] [blame] | 421 | auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC); |
| 422 | dup2(fd, STDOUT_FILENO); |
| 423 | dup2(fd, STDERR_FILENO); |
| 424 | close(fd); |
Tom Cherry | 44aceed | 2018-08-03 13:36:18 -0700 | [diff] [blame] | 425 | execv(path, const_cast<char**>(args)); |
| 426 | |
| 427 | // execv() only returns if an error happened, in which case we |
| 428 | // panic and never fall through this conditional. |
| 429 | PLOG(FATAL) << "execv(\"" << path << "\") failed"; |
| 430 | |
| 431 | return 1; |
| 432 | } |
| 433 | |
| 434 | } // namespace init |
| 435 | } // namespace android |