1 /*
2  * Copyright (C) 2014 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 
17 #include <ctype.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/mount.h>
24 #include <unistd.h>
25 
26 #include <algorithm>
27 #include <array>
28 #include <utility>
29 #include <vector>
30 
31 #include <android-base/file.h>
32 #include <android-base/parseint.h>
33 #include <android-base/stringprintf.h>
34 #include <android-base/strings.h>
35 #include <libgsi/libgsi.h>
36 
37 #include "fs_mgr_priv.h"
38 
39 using android::base::EndsWith;
40 using android::base::ParseByteCount;
41 using android::base::ParseInt;
42 using android::base::ReadFileToString;
43 using android::base::Split;
44 using android::base::StartsWith;
45 
46 namespace android {
47 namespace fs_mgr {
48 namespace {
49 
50 constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android";
51 
52 struct FlagList {
53     const char *name;
54     uint64_t flag;
55 };
56 
57 FlagList kMountFlagsList[] = {
58         {"noatime", MS_NOATIME},
59         {"noexec", MS_NOEXEC},
60         {"nosuid", MS_NOSUID},
61         {"nodev", MS_NODEV},
62         {"nodiratime", MS_NODIRATIME},
63         {"ro", MS_RDONLY},
64         {"rw", 0},
65         {"sync", MS_SYNCHRONOUS},
66         {"remount", MS_REMOUNT},
67         {"bind", MS_BIND},
68         {"rec", MS_REC},
69         {"unbindable", MS_UNBINDABLE},
70         {"private", MS_PRIVATE},
71         {"slave", MS_SLAVE},
72         {"shared", MS_SHARED},
73         {"defaults", 0},
74 };
75 
CalculateZramSize(int percentage)76 off64_t CalculateZramSize(int percentage) {
77     off64_t total;
78 
79     total  = sysconf(_SC_PHYS_PAGES);
80     total *= percentage;
81     total /= 100;
82 
83     total *= sysconf(_SC_PAGESIZE);
84 
85     return total;
86 }
87 
88 // Fills 'dt_value' with the underlying device tree value string without the trailing '\0'.
89 // Returns true if 'dt_value' has a valid string, 'false' otherwise.
ReadDtFile(const std::string & file_name,std::string * dt_value)90 bool ReadDtFile(const std::string& file_name, std::string* dt_value) {
91     if (android::base::ReadFileToString(file_name, dt_value)) {
92         if (!dt_value->empty()) {
93             // Trim the trailing '\0' out, otherwise the comparison will produce false-negatives.
94             dt_value->resize(dt_value->size() - 1);
95             return true;
96         }
97     }
98 
99     return false;
100 }
101 
102 const std::array<const char*, 3> kFileContentsEncryptionMode = {
103         "aes-256-xts",
104         "adiantum",
105         "ice",
106 };
107 
108 const std::array<const char*, 3> kFileNamesEncryptionMode = {
109         "aes-256-cts",
110         "aes-256-heh",
111         "adiantum",
112 };
113 
ParseFileEncryption(const std::string & arg,FstabEntry * entry)114 void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
115     // The fileencryption flag is followed by an = and 1 to 3 colon-separated fields:
116     //
117     // 1. Contents encryption mode
118     // 2. Filenames encryption mode (defaults to "aes-256-cts" or "adiantum"
119     //    depending on the contents encryption mode)
120     // 3. Encryption policy version (defaults to "v1". Use "v2" on new devices.)
121     entry->fs_mgr_flags.file_encryption = true;
122 
123     auto parts = Split(arg, ":");
124     if (parts.empty() || parts.size() > 3) {
125         LWARNING << "Warning: fileencryption= flag malformed: " << arg;
126         return;
127     }
128 
129     // Alias for backwards compatibility.
130     if (parts[0] == "software") {
131         parts[0] = "aes-256-xts";
132     }
133 
134     if (std::find(kFileContentsEncryptionMode.begin(), kFileContentsEncryptionMode.end(),
135                   parts[0]) == kFileContentsEncryptionMode.end()) {
136         LWARNING << "fileencryption= flag malformed, file contents encryption mode not found: "
137                  << arg;
138         return;
139     }
140 
141     entry->file_contents_mode = parts[0];
142 
143     if (parts.size() >= 2) {
144         if (std::find(kFileNamesEncryptionMode.begin(), kFileNamesEncryptionMode.end(), parts[1]) ==
145             kFileNamesEncryptionMode.end()) {
146             LWARNING << "fileencryption= flag malformed, file names encryption mode not found: "
147                      << arg;
148             return;
149         }
150 
151         entry->file_names_mode = parts[1];
152     } else if (entry->file_contents_mode == "adiantum") {
153         entry->file_names_mode = "adiantum";
154     } else {
155         entry->file_names_mode = "aes-256-cts";
156     }
157 
158     if (parts.size() >= 3) {
159         if (!android::base::StartsWith(parts[2], 'v') ||
160             !android::base::ParseInt(&parts[2][1], &entry->file_policy_version)) {
161             LWARNING << "fileencryption= flag malformed, unknown options: " << arg;
162             return;
163         }
164     } else {
165         entry->file_policy_version = 1;
166     }
167 }
168 
SetMountFlag(const std::string & flag,FstabEntry * entry)169 bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
170     for (const auto& [name, value] : kMountFlagsList) {
171         if (flag == name) {
172             entry->flags |= value;
173             return true;
174         }
175     }
176     return false;
177 }
178 
ParseMountFlags(const std::string & flags,FstabEntry * entry)179 void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
180     std::string fs_options;
181     for (const auto& flag : Split(flags, ",")) {
182         if (!SetMountFlag(flag, entry)) {
183             // Unknown flag, so it must be a filesystem specific option.
184             if (!fs_options.empty()) {
185                 fs_options.append(",");  // appends a comma if not the first
186             }
187             fs_options.append(flag);
188 
189             if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
190                 std::string arg;
191                 if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
192                     arg = flag.substr(equal_sign + 1);
193                 }
194                 if (!ParseInt(arg, &entry->reserved_size)) {
195                     LWARNING << "Warning: reserve_root= flag malformed: " << arg;
196                 } else {
197                     entry->reserved_size <<= 12;
198                 }
199             }
200         }
201     }
202     entry->fs_options = std::move(fs_options);
203 }
204 
ParseFsMgrFlags(const std::string & flags,FstabEntry * entry)205 void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
206     for (const auto& flag : Split(flags, ",")) {
207         if (flag.empty() || flag == "defaults") continue;
208         std::string arg;
209         if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
210             arg = flag.substr(equal_sign + 1);
211         }
212 
213         // First handle flags that simply set a boolean.
214 #define CheckFlag(flag_name, value)       \
215     if (flag == flag_name) {              \
216         entry->fs_mgr_flags.value = true; \
217         continue;                         \
218     }
219 
220         CheckFlag("wait", wait);
221         CheckFlag("check", check);
222         CheckFlag("nonremovable", nonremovable);
223         CheckFlag("recoveryonly", recovery_only);
224         CheckFlag("noemulatedsd", no_emulated_sd);
225         CheckFlag("notrim", no_trim);
226         CheckFlag("verify", verify);
227         CheckFlag("formattable", formattable);
228         CheckFlag("slotselect", slot_select);
229         CheckFlag("latemount", late_mount);
230         CheckFlag("nofail", no_fail);
231         CheckFlag("verifyatboot", verify_at_boot);
232         CheckFlag("quota", quota);
233         CheckFlag("avb", avb);
234         CheckFlag("logical", logical);
235         CheckFlag("checkpoint=block", checkpoint_blk);
236         CheckFlag("checkpoint=fs", checkpoint_fs);
237         CheckFlag("first_stage_mount", first_stage_mount);
238         CheckFlag("slotselect_other", slot_select_other);
239         CheckFlag("fsverity", fs_verity);
240 
241 #undef CheckFlag
242 
243         // Then handle flags that take an argument.
244         if (StartsWith(flag, "encryptable=")) {
245             // The encryptable flag is followed by an = and the  location of the keys.
246             entry->fs_mgr_flags.crypt = true;
247             entry->key_loc = arg;
248         } else if (StartsWith(flag, "voldmanaged=")) {
249             // The voldmanaged flag is followed by an = and the label, a colon and the partition
250             // number or the word "auto", e.g. voldmanaged=sdcard:3
251             entry->fs_mgr_flags.vold_managed = true;
252             auto parts = Split(arg, ":");
253             if (parts.size() != 2) {
254                 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
255                 continue;
256             }
257 
258             entry->label = std::move(parts[0]);
259             if (parts[1] == "auto") {
260                 entry->partnum = -1;
261             } else {
262                 if (!ParseInt(parts[1], &entry->partnum)) {
263                     entry->partnum = -1;
264                     LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
265                     continue;
266                 }
267             }
268         } else if (StartsWith(flag, "length=")) {
269             // The length flag is followed by an = and the size of the partition.
270             if (!ParseInt(arg, &entry->length)) {
271                 LWARNING << "Warning: length= flag malformed: " << arg;
272             }
273         } else if (StartsWith(flag, "swapprio=")) {
274             if (!ParseInt(arg, &entry->swap_prio)) {
275                 LWARNING << "Warning: length= flag malformed: " << arg;
276             }
277         } else if (StartsWith(flag, "zramsize=")) {
278             if (!arg.empty() && arg.back() == '%') {
279                 arg.pop_back();
280                 int val;
281                 if (ParseInt(arg, &val, 0, 100)) {
282                     entry->zram_size = CalculateZramSize(val);
283                 } else {
284                     LWARNING << "Warning: zramsize= flag malformed: " << arg;
285                 }
286             } else {
287                 if (!ParseInt(arg, &entry->zram_size)) {
288                     LWARNING << "Warning: zramsize= flag malformed: " << arg;
289                 }
290             }
291         } else if (StartsWith(flag, "forceencrypt=")) {
292             // The forceencrypt flag is followed by an = and the location of the keys.
293             entry->fs_mgr_flags.force_crypt = true;
294             entry->key_loc = arg;
295         } else if (StartsWith(flag, "fileencryption=")) {
296             ParseFileEncryption(arg, entry);
297         } else if (StartsWith(flag, "forcefdeorfbe=")) {
298             // The forcefdeorfbe flag is followed by an = and the location of the keys.  Get it and
299             // return it.
300             entry->fs_mgr_flags.force_fde_or_fbe = true;
301             entry->key_loc = arg;
302             entry->file_contents_mode = "aes-256-xts";
303             entry->file_names_mode = "aes-256-cts";
304             entry->file_policy_version = 1;
305         } else if (StartsWith(flag, "max_comp_streams=")) {
306             if (!ParseInt(arg, &entry->max_comp_streams)) {
307                 LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
308             }
309         } else if (StartsWith(flag, "reservedsize=")) {
310             // The reserved flag is followed by an = and the reserved size of the partition.
311             uint64_t size;
312             if (!ParseByteCount(arg, &size)) {
313                 LWARNING << "Warning: reservedsize= flag malformed: " << arg;
314             } else {
315                 entry->reserved_size = static_cast<off64_t>(size);
316             }
317         } else if (StartsWith(flag, "eraseblk=")) {
318             // The erase block size flag is followed by an = and the flash erase block size. Get it,
319             // check that it is a power of 2 and at least 4096, and return it.
320             off64_t val;
321             if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
322                 LWARNING << "Warning: eraseblk= flag malformed: " << arg;
323             } else {
324                 entry->erase_blk_size = val;
325             }
326         } else if (StartsWith(flag, "logicalblk=")) {
327             // The logical block size flag is followed by an = and the flash logical block size. Get
328             // it, check that it is a power of 2 and at least 4096, and return it.
329             off64_t val;
330             if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
331                 LWARNING << "Warning: logicalblk= flag malformed: " << arg;
332             } else {
333                 entry->logical_blk_size = val;
334             }
335         } else if (StartsWith(flag, "avb_keys=")) {  // must before the following "avb"
336             entry->avb_keys = arg;
337         } else if (StartsWith(flag, "avb")) {
338             entry->fs_mgr_flags.avb = true;
339             entry->vbmeta_partition = arg;
340         } else if (StartsWith(flag, "keydirectory=")) {
341             // The metadata flag is followed by an = and the directory for the keys.
342             entry->key_dir = arg;
343         } else if (StartsWith(flag, "sysfs_path=")) {
344             // The path to trigger device gc by idle-maint of vold.
345             entry->sysfs_path = arg;
346         } else if (StartsWith(flag, "zram_loopback_path=")) {
347             // The path to use loopback for zram.
348             entry->zram_loopback_path = arg;
349         } else if (StartsWith(flag, "zram_loopback_size=")) {
350             if (!ParseByteCount(arg, &entry->zram_loopback_size)) {
351                 LWARNING << "Warning: zram_loopback_size= flag malformed: " << arg;
352             }
353         } else if (StartsWith(flag, "zram_backing_dev_path=")) {
354             entry->zram_backing_dev_path = arg;
355         } else {
356             LWARNING << "Warning: unknown flag: " << flag;
357         }
358     }
359 }
360 
InitAndroidDtDir()361 std::string InitAndroidDtDir() {
362     std::string android_dt_dir;
363     // The platform may specify a custom Android DT path in kernel cmdline
364     if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
365         // Fall back to the standard procfs-based path
366         android_dt_dir = kDefaultAndroidDtDir;
367     }
368     return android_dt_dir;
369 }
370 
IsDtFstabCompatible()371 bool IsDtFstabCompatible() {
372     std::string dt_value;
373     std::string file_name = get_android_dt_dir() + "/fstab/compatible";
374 
375     if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") {
376         // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
377         std::string status_value;
378         std::string status_file_name = get_android_dt_dir() + "/fstab/status";
379         return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" ||
380                status_value == "okay";
381     }
382 
383     return false;
384 }
385 
ReadFstabFromDt()386 std::string ReadFstabFromDt() {
387     if (!is_dt_compatible() || !IsDtFstabCompatible()) {
388         return {};
389     }
390 
391     std::string fstabdir_name = get_android_dt_dir() + "/fstab";
392     std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
393     if (!fstabdir) return {};
394 
395     dirent* dp;
396     // Each element in fstab_dt_entries is <mount point, the line format in fstab file>.
397     std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
398     while ((dp = readdir(fstabdir.get())) != NULL) {
399         // skip over name, compatible and .
400         if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
401 
402         // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
403         std::vector<std::string> fstab_entry;
404         std::string file_name;
405         std::string value;
406         // skip a partition entry if the status property is present and not set to ok
407         file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
408         if (ReadDtFile(file_name, &value)) {
409             if (value != "okay" && value != "ok") {
410                 LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
411                 continue;
412             }
413         }
414 
415         file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
416         if (!ReadDtFile(file_name, &value)) {
417             LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
418             return {};
419         }
420         fstab_entry.push_back(value);
421 
422         std::string mount_point;
423         file_name =
424             android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
425         if (ReadDtFile(file_name, &value)) {
426             LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
427             mount_point = value;
428         } else {
429             mount_point = android::base::StringPrintf("/%s", dp->d_name);
430         }
431         fstab_entry.push_back(mount_point);
432 
433         file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
434         if (!ReadDtFile(file_name, &value)) {
435             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
436             return {};
437         }
438         fstab_entry.push_back(value);
439 
440         file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
441         if (!ReadDtFile(file_name, &value)) {
442             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
443             return {};
444         }
445         fstab_entry.push_back(value);
446 
447         file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
448         if (!ReadDtFile(file_name, &value)) {
449             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
450             return {};
451         }
452         fstab_entry.push_back(value);
453         // Adds a fstab_entry to fstab_dt_entries, to be sorted by mount_point later.
454         fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
455     }
456 
457     // Sort fstab_dt entries, to ensure /vendor is mounted before /vendor/abc is attempted.
458     std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
459               [](const auto& a, const auto& b) { return a.first < b.first; });
460 
461     std::string fstab_result;
462     for (const auto& [_, dt_entry] : fstab_dt_entries) {
463         fstab_result += dt_entry + "\n";
464     }
465     return fstab_result;
466 }
467 
468 // Identify path to fstab file. Lookup is based on pattern fstab.<hardware>,
469 // fstab.<hardware.platform> in folders /odm/etc, vendor/etc, or /.
GetFstabPath()470 std::string GetFstabPath() {
471     for (const char* prop : {"hardware", "hardware.platform"}) {
472         std::string hw;
473 
474         if (!fs_mgr_get_boot_config(prop, &hw)) continue;
475 
476         for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
477             std::string fstab_path = prefix + hw;
478             if (access(fstab_path.c_str(), F_OK) == 0) {
479                 return fstab_path;
480             }
481         }
482     }
483 
484     return "";
485 }
486 
ReadFstabFile(FILE * fstab_file,bool proc_mounts,Fstab * fstab_out)487 bool ReadFstabFile(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
488     ssize_t len;
489     size_t alloc_len = 0;
490     char *line = NULL;
491     const char *delim = " \t";
492     char *save_ptr, *p;
493     Fstab fstab;
494 
495     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
496         /* if the last character is a newline, shorten the string by 1 byte */
497         if (line[len - 1] == '\n') {
498             line[len - 1] = '\0';
499         }
500 
501         /* Skip any leading whitespace */
502         p = line;
503         while (isspace(*p)) {
504             p++;
505         }
506         /* ignore comments or empty lines */
507         if (*p == '#' || *p == '\0')
508             continue;
509 
510         FstabEntry entry;
511 
512         if (!(p = strtok_r(line, delim, &save_ptr))) {
513             LERROR << "Error parsing mount source";
514             goto err;
515         }
516         entry.blk_device = p;
517 
518         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
519             LERROR << "Error parsing mount_point";
520             goto err;
521         }
522         entry.mount_point = p;
523 
524         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
525             LERROR << "Error parsing fs_type";
526             goto err;
527         }
528         entry.fs_type = p;
529 
530         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
531             LERROR << "Error parsing mount_flags";
532             goto err;
533         }
534 
535         ParseMountFlags(p, &entry);
536 
537         // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
538         if (proc_mounts) {
539             p += strlen(p);
540         } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
541             LERROR << "Error parsing fs_mgr_options";
542             goto err;
543         }
544 
545         ParseFsMgrFlags(p, &entry);
546 
547         if (entry.fs_mgr_flags.logical) {
548             entry.logical_partition_name = entry.blk_device;
549         }
550 
551         fstab.emplace_back(std::move(entry));
552     }
553 
554     if (fstab.empty()) {
555         LERROR << "No entries found in fstab";
556         goto err;
557     }
558 
559     /* If an A/B partition, modify block device to be the real block device */
560     if (!fs_mgr_update_for_slotselect(&fstab)) {
561         LERROR << "Error updating for slotselect";
562         goto err;
563     }
564     free(line);
565     *fstab_out = std::move(fstab);
566     return true;
567 
568 err:
569     free(line);
570     return false;
571 }
572 
573 /* Extracts <device>s from the by-name symlinks specified in a fstab:
574  *   /dev/block/<type>/<device>/by-name/<partition>
575  *
576  * <type> can be: platform, pci or vbd.
577  *
578  * For example, given the following entries in the input fstab:
579  *   /dev/block/platform/soc/1da4000.ufshc/by-name/system
580  *   /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
581  * it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
582  */
ExtraBootDevices(const Fstab & fstab)583 std::set<std::string> ExtraBootDevices(const Fstab& fstab) {
584     std::set<std::string> boot_devices;
585 
586     for (const auto& entry : fstab) {
587         std::string blk_device = entry.blk_device;
588         // Skips blk_device that doesn't conform to the format.
589         if (!android::base::StartsWith(blk_device, "/dev/block") ||
590             android::base::StartsWith(blk_device, "/dev/block/by-name") ||
591             android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) {
592             continue;
593         }
594         // Skips non-by_name blk_device.
595         // /dev/block/<type>/<device>/by-name/<partition>
596         //                           ^ slash_by_name
597         auto slash_by_name = blk_device.find("/by-name");
598         if (slash_by_name == std::string::npos) continue;
599         blk_device.erase(slash_by_name);  // erases /by-name/<partition>
600 
601         // Erases /dev/block/, now we have <type>/<device>
602         blk_device.erase(0, std::string("/dev/block/").size());
603 
604         // <type>/<device>
605         //       ^ first_slash
606         auto first_slash = blk_device.find('/');
607         if (first_slash == std::string::npos) continue;
608 
609         auto boot_device = blk_device.substr(first_slash + 1);
610         if (!boot_device.empty()) boot_devices.insert(std::move(boot_device));
611     }
612 
613     return boot_devices;
614 }
615 
BuildDsuUserdataFstabEntry()616 FstabEntry BuildDsuUserdataFstabEntry() {
617     constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV;
618 
619     FstabEntry userdata = {
620             .blk_device = "userdata_gsi",
621             .mount_point = "/data",
622             .fs_type = "ext4",
623             .flags = kFlags,
624             .reserved_size = 128 * 1024 * 1024,
625     };
626     userdata.fs_mgr_flags.wait = true;
627     userdata.fs_mgr_flags.check = true;
628     userdata.fs_mgr_flags.logical = true;
629     userdata.fs_mgr_flags.quota = true;
630     userdata.fs_mgr_flags.late_mount = true;
631     userdata.fs_mgr_flags.formattable = true;
632     return userdata;
633 }
634 
EraseFstabEntry(Fstab * fstab,const std::string & mount_point)635 bool EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
636     auto iter = std::remove_if(fstab->begin(), fstab->end(),
637                                [&](const auto& entry) { return entry.mount_point == mount_point; });
638     if (iter != fstab->end()) {
639         fstab->erase(iter, fstab->end());
640         return true;
641     }
642     return false;
643 }
644 
645 }  // namespace
646 
TransformFstabForDsu(Fstab * fstab,const std::vector<std::string> & dsu_partitions)647 void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
648     static constexpr char kGsiKeys[] =
649             "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey";
650     // Convert userdata
651     // Inherit fstab properties for userdata.
652     FstabEntry userdata;
653     if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) {
654         userdata = *entry;
655         userdata.blk_device = "userdata_gsi";
656         userdata.fs_mgr_flags.logical = true;
657         userdata.fs_mgr_flags.formattable = true;
658         if (!userdata.key_dir.empty()) {
659             userdata.key_dir += "/gsi";
660         }
661     } else {
662         userdata = BuildDsuUserdataFstabEntry();
663     }
664 
665     if (EraseFstabEntry(fstab, "/data")) {
666         fstab->emplace_back(userdata);
667     }
668 
669     // Convert others
670     for (auto&& partition : dsu_partitions) {
671         if (!EndsWith(partition, gsi::kDsuPostfix)) {
672             continue;
673         }
674         // userdata has been handled
675         if (StartsWith(partition, "user")) {
676             continue;
677         }
678         // dsu_partition_name = corresponding_partition_name + kDsuPostfix
679         // e.g.
680         //    system_gsi for system
681         //    product_gsi for product
682         //    vendor_gsi for vendor
683         std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
684         std::string mount_point = "/" + lp_name;
685         std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point);
686         if (entries.empty()) {
687             FstabEntry entry = {
688                     .blk_device = partition,
689                     // .logical_partition_name is required to look up AVB Hashtree descriptors.
690                     .logical_partition_name = "system",
691                     .mount_point = mount_point,
692                     .fs_type = "ext4",
693                     .flags = MS_RDONLY,
694                     .fs_options = "barrier=1",
695                     .avb_keys = kGsiKeys,
696             };
697             entry.fs_mgr_flags.wait = true;
698             entry.fs_mgr_flags.logical = true;
699             entry.fs_mgr_flags.first_stage_mount = true;
700             // Use the system key which may be in the vbmeta or vbmeta_system
701             // TODO: b/141284191
702             entry.vbmeta_partition = "vbmeta";
703             fstab->emplace_back(entry);
704             entry.vbmeta_partition = "vbmeta_system";
705             fstab->emplace_back(entry);
706         } else {
707             // If the corresponding partition exists, transform all its Fstab
708             // by pointing .blk_device to the DSU partition.
709             for (auto&& entry : entries) {
710                 entry->blk_device = partition;
711                 if (entry->avb_keys.size() > 0) {
712                     entry->avb_keys += ":";
713                 }
714                 // If the DSU is signed by OEM, the original Fstab already has the information
715                 // required by avb, otherwise the DSU is GSI and will need the avb_keys as listed
716                 // below.
717                 entry->avb_keys += kGsiKeys;
718             }
719             // Make sure the ext4 is included to support GSI.
720             auto partition_ext4 =
721                     std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) {
722                         return entry.mount_point == mount_point && entry.fs_type == "ext4";
723                     });
724             if (partition_ext4 == fstab->end()) {
725                 auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
726                 new_entry.fs_type = "ext4";
727                 fstab->emplace_back(new_entry);
728             }
729         }
730     }
731 }
732 
ReadFstabFromFile(const std::string & path,Fstab * fstab)733 bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
734     auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
735     if (!fstab_file) {
736         PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
737         return false;
738     }
739 
740     bool is_proc_mounts = path == "/proc/mounts";
741 
742     if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, fstab)) {
743         LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
744         return false;
745     }
746     if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
747         std::string lp_names;
748         ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
749         TransformFstabForDsu(fstab, Split(lp_names, ","));
750     }
751 
752     SkipMountingPartitions(fstab);
753 
754     return true;
755 }
756 
757 // Returns fstab entries parsed from the device tree if they exist
ReadFstabFromDt(Fstab * fstab,bool log)758 bool ReadFstabFromDt(Fstab* fstab, bool log) {
759     std::string fstab_buf = ReadFstabFromDt();
760     if (fstab_buf.empty()) {
761         if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
762         return false;
763     }
764 
765     std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
766         fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
767                  fstab_buf.length(), "r"), fclose);
768     if (!fstab_file) {
769         if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
770         return false;
771     }
772 
773     if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
774         if (log) {
775             LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
776                    << fstab_buf;
777         }
778         return false;
779     }
780 
781     SkipMountingPartitions(fstab);
782 
783     return true;
784 }
785 
786 // For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
787 // between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
788 // device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
789 // only common files for all targets can be put into system partition. It is under
790 // /system/system_ext because GSI is a single system.img that includes the contents of system_ext
791 // partition and product partition under /system/system_ext and /system/product, respectively.
SkipMountingPartitions(Fstab * fstab)792 bool SkipMountingPartitions(Fstab* fstab) {
793     constexpr const char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
794 
795     std::string skip_config;
796     auto save_errno = errno;
797     if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
798         errno = save_errno;  // missing file is expected
799         return true;
800     }
801 
802     for (const auto& skip_mount_point : Split(skip_config, "\n")) {
803         if (skip_mount_point.empty()) {
804             continue;
805         }
806         auto it = std::remove_if(fstab->begin(), fstab->end(),
807                                  [&skip_mount_point](const auto& entry) {
808                                      return entry.mount_point == skip_mount_point;
809                                  });
810         if (it == fstab->end()) continue;
811         fstab->erase(it, fstab->end());
812         LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
813     }
814 
815     return true;
816 }
817 
818 // Loads the fstab file and combines with fstab entries passed in from device tree.
ReadDefaultFstab(Fstab * fstab)819 bool ReadDefaultFstab(Fstab* fstab) {
820     Fstab dt_fstab;
821     ReadFstabFromDt(&dt_fstab, false);
822 
823     *fstab = std::move(dt_fstab);
824 
825     std::string default_fstab_path;
826     // Use different fstab paths for normal boot and recovery boot, respectively
827     if (access("/system/bin/recovery", F_OK) == 0) {
828         default_fstab_path = "/etc/recovery.fstab";
829     } else {  // normal boot
830         default_fstab_path = GetFstabPath();
831     }
832 
833     Fstab default_fstab;
834     if (!default_fstab_path.empty()) {
835         ReadFstabFromFile(default_fstab_path, &default_fstab);
836     } else {
837         LINFO << __FUNCTION__ << "(): failed to find device default fstab";
838     }
839 
840     for (auto&& entry : default_fstab) {
841         fstab->emplace_back(std::move(entry));
842     }
843 
844     return !fstab->empty();
845 }
846 
GetEntryForMountPoint(Fstab * fstab,const std::string & path)847 FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
848     if (fstab == nullptr) {
849         return nullptr;
850     }
851 
852     for (auto& entry : *fstab) {
853         if (entry.mount_point == path) {
854             return &entry;
855         }
856     }
857 
858     return nullptr;
859 }
860 
GetEntriesForMountPoint(Fstab * fstab,const std::string & path)861 std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) {
862     std::vector<FstabEntry*> entries;
863     if (fstab == nullptr) {
864         return entries;
865     }
866 
867     for (auto& entry : *fstab) {
868         if (entry.mount_point == path) {
869             entries.emplace_back(&entry);
870         }
871     }
872 
873     return entries;
874 }
875 
GetBootDevices()876 std::set<std::string> GetBootDevices() {
877     // First check the kernel commandline, then try the device tree otherwise
878     std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
879     std::string value;
880     if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
881         ReadDtFile(dt_file_name, &value)) {
882         auto boot_devices = Split(value, ",");
883         return std::set<std::string>(boot_devices.begin(), boot_devices.end());
884     }
885 
886     // Fallback to extract boot devices from fstab.
887     Fstab fstab;
888     if (!ReadDefaultFstab(&fstab)) {
889         return {};
890     }
891 
892     return ExtraBootDevices(fstab);
893 }
894 
GetVerityDeviceName(const FstabEntry & entry)895 std::string GetVerityDeviceName(const FstabEntry& entry) {
896     std::string base_device;
897     if (entry.mount_point == "/") {
898         // When using system-as-root, the device name is fixed as "vroot".
899         if (entry.fs_mgr_flags.avb) {
900             return "vroot";
901         }
902         base_device = "system";
903     } else {
904         base_device = android::base::Basename(entry.mount_point);
905     }
906     return base_device + "-verity";
907 }
908 
909 }  // namespace fs_mgr
910 }  // namespace android
911 
912 // FIXME: The same logic is duplicated in system/core/init/
get_android_dt_dir()913 const std::string& get_android_dt_dir() {
914     // Set once and saves time for subsequent calls to this function
915     static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
916     return kAndroidDtDir;
917 }
918 
is_dt_compatible()919 bool is_dt_compatible() {
920     std::string file_name = get_android_dt_dir() + "/compatible";
921     std::string dt_value;
922     if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
923         if (dt_value == "android,firmware") {
924             return true;
925         }
926     }
927 
928     return false;
929 }
930