Merge "Mount /vendor and /odm early"

This commit is contained in:
Treehugger Robot 2016-08-18 05:01:13 +00:00 committed by Gerrit Code Review
commit 35569e9d68
7 changed files with 244 additions and 48 deletions

View File

@ -905,3 +905,22 @@ int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_dev
return 0;
}
int fs_mgr_early_setup_verity(struct fstab_rec *fstab_rec)
{
if ((fstab_rec->fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
int rc = fs_mgr_setup_verity(fstab_rec);
if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
INFO("Verity disabled");
return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
} else if (rc == FS_MGR_SETUP_VERITY_SUCCESS) {
return FS_MGR_EARLY_SETUP_VERITY_SUCCESS;
} else {
return FS_MGR_EARLY_SETUP_VERITY_FAIL;
}
} else if (device_is_secure()) {
ERROR("Verity must be enabled for early mounted partitions on secured devices.\n");
return FS_MGR_EARLY_SETUP_VERITY_FAIL;
}
return FS_MGR_EARLY_SETUP_VERITY_NO_VERITY;
}

View File

@ -210,9 +210,8 @@ static int parse_flags(char *flags, struct flag_list *fl,
return f;
}
struct fstab *fs_mgr_read_fstab(const char *fstab_path)
struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
{
FILE *fstab_file;
int cnt, entries;
ssize_t len;
size_t alloc_len = 0;
@ -224,12 +223,6 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
#define FS_OPTIONS_LEN 1024
char tmp_fs_options[FS_OPTIONS_LEN];
fstab_file = fopen(fstab_path, "r");
if (!fstab_file) {
ERROR("Cannot open file %s\n", fstab_path);
return 0;
}
entries = 0;
while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
/* if the last character is a newline, shorten the string by 1 byte */
@ -255,7 +248,6 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
/* Allocate and init the fstab structure */
fstab = calloc(1, sizeof(struct fstab));
fstab->num_entries = entries;
fstab->fstab_filename = strdup(fstab_path);
fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
fseek(fstab_file, 0, SEEK_SET);
@ -338,18 +330,34 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path)
ERROR("Error updating for slotselect\n");
goto err;
}
fclose(fstab_file);
free(line);
return fstab;
err:
fclose(fstab_file);
free(line);
if (fstab)
fs_mgr_free_fstab(fstab);
return NULL;
}
struct fstab *fs_mgr_read_fstab(const char *fstab_path)
{
FILE *fstab_file;
struct fstab *fstab;
fstab_file = fopen(fstab_path, "r");
if (!fstab_file) {
ERROR("Cannot open file %s\n", fstab_path);
return NULL;
}
fstab = fs_mgr_read_fstab_file(fstab_file);
if (fstab) {
fstab->fstab_filename = strdup(fstab_path);
}
fclose(fstab_file);
return fstab;
}
void fs_mgr_free_fstab(struct fstab *fstab)
{
int i;

View File

@ -341,17 +341,6 @@ static int resume_verity_table(struct dm_ioctl *io, char *name, int fd)
return 0;
}
static int test_access(char *device) {
int tries = 25;
while (tries--) {
if (!access(device, F_OK) || errno != ENOENT) {
return 0;
}
usleep(40 * 1000);
}
return -1;
}
static int check_verity_restart(const char *fname)
{
char buffer[VERITY_KMSG_BUFSIZE + 1];
@ -1031,11 +1020,6 @@ loaded:
fstab->blk_device = verity_blk_name;
verity_blk_name = 0;
// make sure we've set everything up properly
if (test_access(fstab->blk_device) < 0) {
goto out;
}
retval = FS_MGR_SETUP_VERITY_SUCCESS;
out:

View File

@ -17,6 +17,7 @@
#ifndef __CORE_FS_MGR_H
#define __CORE_FS_MGR_H
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <linux/dm-ioctl.h>
@ -72,6 +73,7 @@ struct fstab_rec {
typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
const char *mount_point, int mode, int status);
struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file);
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
@ -111,6 +113,11 @@ int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
#define FS_MGR_EARLY_SETUP_VERITY_NO_VERITY -2
#define FS_MGR_EARLY_SETUP_VERITY_FAIL -1
#define FS_MGR_EARLY_SETUP_VERITY_SUCCESS 0
int fs_mgr_early_setup_verity(struct fstab_rec *fstab);
#ifdef __cplusplus
}
#endif

View File

@ -44,6 +44,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/list.h>
#include <cutils/uevent.h>
@ -601,14 +602,17 @@ static const char *parse_device_name(struct uevent *uevent, unsigned int len)
return name;
}
#define DEVPATH_LEN 96
#define MAX_DEV_NAME 64
static void handle_block_device_event(struct uevent *uevent)
{
const char *base = "/dev/block/";
const char *name;
char devpath[96];
char devpath[DEVPATH_LEN];
char **links = NULL;
name = parse_device_name(uevent, 64);
name = parse_device_name(uevent, MAX_DEV_NAME);
if (!name)
return;
@ -622,8 +626,6 @@ static void handle_block_device_event(struct uevent *uevent)
uevent->major, uevent->minor, links);
}
#define DEVPATH_LEN 96
static bool assemble_devpath(char *devpath, const char *dirname,
const char *devname)
{
@ -657,7 +659,7 @@ static void handle_generic_device_event(struct uevent *uevent)
char devpath[DEVPATH_LEN] = {0};
char **links = NULL;
name = parse_device_name(uevent, 64);
name = parse_device_name(uevent, MAX_DEV_NAME);
if (!name)
return;
@ -900,7 +902,8 @@ static void handle_firmware_event(struct uevent *uevent)
}
#define UEVENT_MSG_LEN 2048
void handle_device_fd()
static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
{
char msg[UEVENT_MSG_LEN+2];
int n;
@ -913,21 +916,28 @@ void handle_device_fd()
struct uevent uevent;
parse_event(msg, &uevent);
if (selinux_status_updated() > 0) {
struct selabel_handle *sehandle2;
sehandle2 = selinux_android_file_context_handle();
if (sehandle2) {
selabel_close(sehandle);
sehandle = sehandle2;
}
}
handle_device_event(&uevent);
handle_firmware_event(&uevent);
handle_uevent(&uevent);
}
}
void handle_device_fd()
{
handle_device_fd_with(
[](struct uevent *uevent) {
if (selinux_status_updated() > 0) {
struct selabel_handle *sehandle2;
sehandle2 = selinux_android_file_context_handle();
if (sehandle2) {
selabel_close(sehandle);
sehandle = sehandle2;
}
}
handle_device_event(uevent);
handle_firmware_event(uevent);
});
}
/* Coldboot walks parts of the /sys tree and pokes the uevent files
** to cause the kernel to regenerate device add events that happened
** before init's device manager was started
@ -979,6 +989,65 @@ static void coldboot(const char *path)
}
}
static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
{
const char *name;
char devpath[DEVPATH_LEN];
if (is_block && strncmp(uevent->subsystem, "block", 5))
return;
name = parse_device_name(uevent, MAX_DEV_NAME);
if (!name) {
LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
<< " " << uevent->partition_name << " " << uevent->partition_num
<< " " << uevent->major << ":" << uevent->minor;
return;
}
snprintf(devpath, sizeof(devpath), "%s%s", base, name);
make_dir(base, 0755);
dev_t dev = makedev(uevent->major, uevent->minor);
mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
mknod(devpath, mode, dev);
}
void early_create_dev(const std::string& syspath, early_device_type dev_type)
{
android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
if (dfd < 0) {
LOG(ERROR) << "Failed to open " << syspath;
return;
}
android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
if (fd < 0) {
LOG(ERROR) << "Failed to open " << syspath << "/uevent";
return;
}
fcntl(device_fd, F_SETFL, O_NONBLOCK);
write(fd, "add\n", 4);
handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
[](struct uevent *uevent) {
early_uevent_handler(uevent, "/dev/block/", true);
} :
[](struct uevent *uevent) {
early_uevent_handler(uevent, "/dev/", false);
});
}
int early_device_socket_open() {
device_fd = uevent_open_socket(256*1024, true);
return device_fd < 0;
}
void early_device_socket_close() {
close(device_fd);
}
void device_init() {
sehandle = selinux_android_file_context_handle();
selinux_status_open(true);

View File

@ -21,6 +21,13 @@
extern void handle_device_fd();
extern void device_init(void);
enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
extern int early_device_socket_open();
extern void early_device_socket_close();
extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
extern int add_dev_perms(const char *name, const char *attr,
mode_t perm, unsigned int uid,
unsigned int gid, unsigned short prefix,

View File

@ -54,6 +54,7 @@
#include "action.h"
#include "bootchart.h"
#include "devices.h"
#include "fs_mgr.h"
#include "import_parser.h"
#include "init.h"
#include "init_parser.h"
@ -342,9 +343,6 @@ static void process_kernel_dt() {
}
static void process_kernel_cmdline() {
// Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);
// The first pass does the common stuff, and finds if we are in qemu.
// The second pass is only necessary for qemu to export all kernel params
// as properties.
@ -461,6 +459,104 @@ static void set_usb_controller() {
}
}
/* Returns a new path consisting of base_path and the file name in reference_path. */
static std::string get_path(const std::string& base_path, const std::string& reference_path) {
std::string::size_type pos = reference_path.rfind('/');
if (pos == std::string::npos) {
return base_path + '/' + reference_path;
} else {
return base_path + reference_path.substr(pos);
}
}
/* Imports the fstab info from cmdline. */
static std::string import_cmdline_fstab() {
std::string prefix, fstab, fstab_full;
import_kernel_cmdline(false,
[&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
if (key == "android.early.prefix") {
prefix = value;
} else if (key == "android.early.fstab") {
fstab = value;
}
});
if (!fstab.empty()) {
// Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
std::replace(fstab.begin(), fstab.end(), '+', ' ');
for (const auto& entry : android::base::Split(fstab, "\n")) {
fstab_full += prefix + entry + '\n';
}
}
return fstab_full;
}
/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
static void early_mount() {
std::string fstab_string = import_cmdline_fstab();
if (fstab_string.empty()) {
LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
return;
}
FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
if (!fstab_file) {
PLOG(ERROR) << "Failed to open fstab string as FILE";
return;
}
std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
fclose(fstab_file);
if (!fstab) {
LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
return;
}
LOG(INFO) << "Loaded vendor fstab from cmdline";
if (early_device_socket_open()) {
LOG(ERROR) << "Failed to open device uevent socket";
return;
}
/* Create /dev/device-mapper for dm-verity */
early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
for (int i = 0; i < fstab->num_entries; ++i) {
struct fstab_rec *rec = &fstab->recs[i];
std::string mount_point = rec->mount_point;
std::string syspath = rec->blk_device;
if (mount_point != "/vendor" && mount_point != "/odm")
continue;
/* Create mount target under /dev/block/ from sysfs via uevent */
LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
char *devpath = strdup(get_path("/dev/block", syspath).c_str());
if (!devpath) {
PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
continue;
}
rec->blk_device = devpath;
early_create_dev(syspath, EARLY_BLOCK_DEV);
int rc = fs_mgr_early_setup_verity(rec);
if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
/* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
} else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
continue;
} else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
}
mkdir(mount_point.c_str(), 0755);
rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
if (rc) {
PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
}
}
early_device_socket_close();
}
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
@ -477,6 +573,9 @@ int main(int argc, char** argv) {
bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
// Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
if (is_first_stage) {
@ -489,6 +588,7 @@ int main(int argc, char** argv) {
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
early_mount();
}
// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
@ -541,6 +641,8 @@ int main(int argc, char** argv) {
restorecon("/dev/__properties__");
restorecon("/property_contexts");
restorecon_recursive("/sys");
restorecon_recursive("/dev/block");
restorecon("/dev/device-mapper");
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {