Fix keyname generation issue am: 5744dfe3cc
am: be03a5aad0
Change-Id: I790abd1988f266cf9a7df6be6f8d294a941d78e0
diff --git a/Android.mk b/Android.mk
index d0b199d..49d58c2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -18,11 +18,12 @@
Ext4Crypt.cpp \
VoldUtil.c \
cryptfs.cpp \
- Disk.cpp \
- VolumeBase.cpp \
- PublicVolume.cpp \
- PrivateVolume.cpp \
- EmulatedVolume.cpp \
+ model/Disk.cpp \
+ model/VolumeBase.cpp \
+ model/PublicVolume.cpp \
+ model/PrivateVolume.cpp \
+ model/EmulatedVolume.cpp \
+ model/ObbVolume.cpp \
Utils.cpp \
MoveTask.cpp \
Benchmark.cpp \
@@ -35,6 +36,8 @@
secontext.cpp \
EncryptInplace.cpp \
MetadataCrypt.cpp \
+ binder/android/os/IVold.aidl \
+ VoldNativeService.cpp \
common_c_includes := \
system/extras/f2fs_utils \
@@ -77,6 +80,7 @@
# TODO: include "cert-err34-c" once we move to Binder
# TODO: include "cert-err58-cpp" once 36656327 is fixed
+common_local_tidy_enabled := true
common_local_tidy_flags := -warnings-as-errors=clang-analyzer-security*,cert-*
common_local_tidy_checks := -*,clang-analyzer-security*,cert-*,-cert-err34-c,-cert-err58-cpp
@@ -85,14 +89,7 @@
required_modules :=
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
- ifeq ($(TARGET_USES_MKE2FS), true)
- vold_cflags += -DTARGET_USES_MKE2FS
- required_modules += mke2fs
- else
- # Adoptable storage has fully moved to mke2fs, so we need both tools
- required_modules += mke2fs
- required_modules += make_ext4fs
- endif
+ required_modules += mke2fs
endif
include $(CLEAR_VARS)
@@ -100,7 +97,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := libvold
LOCAL_CLANG := true
-LOCAL_TIDY := true
+LOCAL_TIDY := $(common_local_tidy_enabled)
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES := $(common_src_files)
@@ -119,7 +116,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := vold
LOCAL_CLANG := true
-LOCAL_TIDY := true
+LOCAL_TIDY := $(common_local_tidy_enabled)
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES := \
@@ -136,13 +133,15 @@
LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
LOCAL_REQUIRED_MODULES := $(required_modules)
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/binder
+
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
-LOCAL_TIDY := true
+LOCAL_TIDY := $(common_local_tidy_enabled)
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES := vdc.cpp
@@ -158,7 +157,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
-LOCAL_TIDY := true
+LOCAL_TIDY := $(common_local_tidy_enabled)
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES:= \
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 8da3f69..60c0898 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -44,7 +44,7 @@
#include "CommandListener.h"
#include "VolumeManager.h"
-#include "VolumeBase.h"
+#include "model/VolumeBase.h"
#include "ResponseCode.h"
#include "Process.h"
#include "Loop.h"
@@ -53,7 +53,6 @@
#include "TrimTask.h"
#define DUMP_ARGS 0
-#define DEBUG_APPFUSE 0
using android::base::unique_fd;
@@ -617,157 +616,6 @@
return sendGenericOkFail(cli, 0);
}
-static size_t kAppFuseMaxMountPointName = 32;
-
-static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
- if (name.size() > kAppFuseMaxMountPointName) {
- LOG(ERROR) << "AppFuse mount name is too long.";
- return -EINVAL;
- }
- for (size_t i = 0; i < name.size(); i++) {
- if (!isalnum(name[i])) {
- LOG(ERROR) << "AppFuse mount name contains invalid character.";
- return -EINVAL;
- }
- }
- *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
- return android::OK;
-}
-
-static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
- // Remove existing mount.
- android::vold::ForceUnmount(path);
-
- const auto opts = android::base::StringPrintf(
- "fd=%i,"
- "rootmode=40000,"
- "default_permissions,"
- "allow_other,"
- "user_id=%d,group_id=%d,"
- "context=\"u:object_r:app_fuse_file:s0\","
- "fscontext=u:object_r:app_fusefs:s0",
- device_fd,
- uid,
- uid);
-
- const int result = TEMP_FAILURE_RETRY(mount(
- "/dev/fuse", path.c_str(), "fuse",
- MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
- if (result != 0) {
- PLOG(ERROR) << "Failed to mount " << path;
- return -errno;
- }
-
- return android::OK;
-}
-
-static android::status_t runCommandInNamespace(const std::string& command,
- uid_t uid,
- pid_t pid,
- const std::string& path,
- int device_fd) {
- if (DEBUG_APPFUSE) {
- LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
- << " in namespace " << uid;
- }
-
- unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (dir.get() == -1) {
- PLOG(ERROR) << "Failed to open /proc";
- return -errno;
- }
-
- // Obtains process file descriptor.
- const std::string pid_str = android::base::StringPrintf("%d", pid);
- const unique_fd pid_fd(
- openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (pid_fd.get() == -1) {
- PLOG(ERROR) << "Failed to open /proc/" << pid;
- return -errno;
- }
-
- // Check UID of process.
- {
- struct stat sb;
- const int result = fstat(pid_fd.get(), &sb);
- if (result == -1) {
- PLOG(ERROR) << "Failed to stat /proc/" << pid;
- return -errno;
- }
- if (sb.st_uid != AID_SYSTEM) {
- LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
- << ", actual=" << sb.st_uid;
- return -EPERM;
- }
- }
-
- // Matches so far, but refuse to touch if in root namespace
- {
- char rootName[PATH_MAX];
- char pidName[PATH_MAX];
- const int root_result =
- android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
- const int pid_result =
- android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
- if (root_result == -1) {
- LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
- return -EPERM;
- }
- if (pid_result == -1) {
- LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
- return -EPERM;
- }
- if (!strcmp(rootName, pidName)) {
- LOG(ERROR) << "Don't mount appfuse in root namespace";
- return -EPERM;
- }
- }
-
- // We purposefully leave the namespace open across the fork
- unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
- if (ns_fd.get() < 0) {
- PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
- return -errno;
- }
-
- int child = fork();
- if (child == 0) {
- if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
- PLOG(ERROR) << "Failed to setns";
- _exit(-errno);
- }
-
- if (command == "mount") {
- _exit(mountInNamespace(uid, device_fd, path));
- } else if (command == "unmount") {
- // If it's just after all FD opened on mount point are closed, umount2 can fail with
- // EBUSY. To avoid the case, specify MNT_DETACH.
- if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
- errno != EINVAL && errno != ENOENT) {
- PLOG(ERROR) << "Failed to unmount directory.";
- _exit(-errno);
- }
- if (rmdir(path.c_str()) != 0) {
- PLOG(ERROR) << "Failed to remove the mount directory.";
- _exit(-errno);
- }
- _exit(android::OK);
- } else {
- LOG(ERROR) << "Unknown appfuse command " << command;
- _exit(-EPERM);
- }
- }
-
- if (child == -1) {
- PLOG(ERROR) << "Failed to folk child process";
- return -errno;
- }
-
- android::status_t status;
- TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
-
- return status;
-}
CommandListener::AppFuseCmd::AppFuseCmd() : VoldCommand("appfuse") {}
@@ -777,66 +625,32 @@
return 0;
}
- const std::string command(argv[1]);
+ VolumeManager *vm = VolumeManager::Instance();
+ std::lock_guard<std::mutex> lock(vm->getLock());
+ const std::string command(argv[1]);
if (command == "mount" && argc == 5) {
const uid_t uid = atoi(argv[2]);
const pid_t pid = atoi(argv[3]);
- const std::string name(argv[4]);
+ const int mountId = atoi(argv[4]);
- // Check mount point name.
- std::string path;
- if (getMountPath(uid, name, &path) != android::OK) {
- return cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid mount point name.",
- false);
+ unique_fd device_fd;
+ int result = vm->mountAppFuse(uid, pid, mountId, &device_fd);
+ if (result != 0) {
+ return sendGenericOkFail(cli, result);
+ } else {
+ return sendFd(cli, device_fd.get());
}
-
- // Create directories.
- {
- const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
- if (result != android::OK) {
- PLOG(ERROR) << "Failed to prepare directory " << path;
- return sendGenericOkFail(cli, result);
- }
- }
-
- // Open device FD.
- unique_fd device_fd(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
- if (device_fd.get() == -1) {
- PLOG(ERROR) << "Failed to open /dev/fuse";
- return sendGenericOkFail(cli, -errno);
- }
-
- // Mount.
- {
- const android::status_t result =
- runCommandInNamespace(command, uid, pid, path, device_fd.get());
- if (result != android::OK) {
- return sendGenericOkFail(cli, result);
- }
- }
-
- return sendFd(cli, device_fd.get());
} else if (command == "unmount" && argc == 5) {
const uid_t uid = atoi(argv[2]);
const uid_t pid = atoi(argv[3]);
- const std::string name(argv[4]);
+ const int mountId = atoi(argv[4]);
- // Check mount point name.
- std::string path;
- if (getMountPath(uid, name, &path) != android::OK) {
- return cli->sendMsg(ResponseCode::CommandParameterError,
- "Invalid mount point name.",
- false);
- }
-
- const android::status_t result =
- runCommandInNamespace(command, uid, pid, path, -1 /* device_fd */);
+ int result = vm->unmountAppFuse(uid, pid, mountId);
return sendGenericOkFail(cli, result);
}
- return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false);
+ return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false);
}
android::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) {
diff --git a/Devmapper.cpp b/Devmapper.cpp
index 4b6942d..c945e9f 100644
--- a/Devmapper.cpp
+++ b/Devmapper.cpp
@@ -32,12 +32,18 @@
#include <cutils/log.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <sysutils/SocketClient.h>
#include "Devmapper.h"
#define DEVMAPPER_BUFFER_SIZE 4096
+using android::base::StringPrintf;
+
+static const char* kVoldPrefix = "vold:";
+
int Devmapper::dumpState(SocketClient *c) {
char *buffer = (char *) malloc(1024 * 64);
@@ -130,7 +136,10 @@
}
}
-int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
+int Devmapper::lookupActive(const char *name_raw, char *ubuffer, size_t len) {
+ auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+ const char* name = name_string.c_str();
+
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
if (!buffer) {
SLOGE("Error allocating memory (%s)", strerror(errno));
@@ -163,8 +172,11 @@
return 0;
}
-int Devmapper::create(const char *name, const char *loopFile, const char *key,
+int Devmapper::create(const char *name_raw, const char *loopFile, const char *key,
unsigned long numSectors, char *ubuffer, size_t len) {
+ auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+ const char* name = name_string.c_str();
+
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
if (!buffer) {
SLOGE("Error allocating memory (%s)", strerror(errno));
@@ -261,7 +273,10 @@
return 0;
}
-int Devmapper::destroy(const char *name) {
+int Devmapper::destroy(const char *name_raw) {
+ auto name_string = StringPrintf("%s%s", kVoldPrefix, name_raw);
+ const char* name = name_string.c_str();
+
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
if (!buffer) {
SLOGE("Error allocating memory (%s)", strerror(errno));
@@ -294,6 +309,74 @@
return 0;
}
+int Devmapper::destroyAll() {
+ char *buffer = (char *) malloc(1024 * 64);
+ if (!buffer) {
+ SLOGE("Error allocating memory (%s)", strerror(errno));
+ return -1;
+ }
+ memset(buffer, 0, (1024 * 64));
+
+ char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
+ if (!buffer2) {
+ SLOGE("Error allocating memory (%s)", strerror(errno));
+ free(buffer);
+ return -1;
+ }
+
+ int fd;
+ if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
+ SLOGE("Error opening devmapper (%s)", strerror(errno));
+ free(buffer);
+ free(buffer2);
+ return -1;
+ }
+
+ struct dm_ioctl *io = (struct dm_ioctl *) buffer;
+ ioctlInit(io, (1024 * 64), NULL, 0);
+
+ if (ioctl(fd, DM_LIST_DEVICES, io)) {
+ SLOGE("DM_LIST_DEVICES ioctl failed (%s)", strerror(errno));
+ free(buffer);
+ free(buffer2);
+ close(fd);
+ return -1;
+ }
+
+ struct dm_name_list *n = (struct dm_name_list *) (((char *) buffer) + io->data_start);
+ if (!n->dev) {
+ free(buffer);
+ free(buffer2);
+ close(fd);
+ return 0;
+ }
+
+ unsigned nxt = 0;
+ do {
+ n = (struct dm_name_list *) (((char *) n) + nxt);
+ if (strncmp(n->name, kVoldPrefix, strlen(kVoldPrefix)) == 0) {
+ LOG(DEBUG) << "Tearing down stale dm device named " << n->name;
+
+ memset(buffer2, 0, DEVMAPPER_BUFFER_SIZE);
+ struct dm_ioctl *io2 = (struct dm_ioctl *) buffer2;
+ ioctlInit(io2, DEVMAPPER_BUFFER_SIZE, n->name, 0);
+ if (ioctl(fd, DM_DEV_REMOVE, io2)) {
+ if (errno != ENXIO) {
+ PLOG(WARNING) << "Failed to destroy dm device named " << n->name;
+ }
+ }
+ } else {
+ LOG(VERBOSE) << "Found unmanaged dm device named " << n->name;
+ }
+ nxt = n->next;
+ } while (nxt);
+
+ free(buffer);
+ free(buffer2);
+ close(fd);
+ return 0;
+}
+
void *Devmapper::_align(void *ptr, unsigned int a)
{
unsigned long agn = --a;
diff --git a/Devmapper.h b/Devmapper.h
index 5b65b53..dcc39d8 100644
--- a/Devmapper.h
+++ b/Devmapper.h
@@ -27,6 +27,7 @@
static int create(const char *name, const char *loopFile, const char *key,
unsigned long numSectors, char *buffer, size_t len);
static int destroy(const char *name);
+ static int destroyAll();
static int lookupActive(const char *name, char *buffer, size_t len);
static int dumpState(SocketClient *c);
diff --git a/EncryptInplace.cpp b/EncryptInplace.cpp
index 9aa2a21..4ffb8cd 100644
--- a/EncryptInplace.cpp
+++ b/EncryptInplace.cpp
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <stdint.h>
-#include <stdbool.h>
#include <inttypes.h>
#include <time.h>
#include <sys/types.h>
diff --git a/Loop.cpp b/Loop.cpp
index 6ec5e6d..325b0d3 100644
--- a/Loop.cpp
+++ b/Loop.cpp
@@ -45,6 +45,8 @@
using android::base::StringPrintf;
using android::base::unique_fd;
+static const char* kVoldPrefix = "vold:";
+
int Loop::dumpState(SocketClient *c) {
int i;
int fd;
@@ -87,7 +89,10 @@
return 0;
}
-int Loop::lookupActive(const char *id, char *buffer, size_t len) {
+int Loop::lookupActive(const char *id_raw, char *buffer, size_t len) {
+ auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw);
+ const char* id = id_string.c_str();
+
int i;
int fd;
char filename[256];
@@ -134,7 +139,10 @@
return 0;
}
-int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len) {
+int Loop::create(const char *id_raw, const char *loopFile, char *loopDeviceBuffer, size_t len) {
+ auto id_string = StringPrintf("%s%s", kVoldPrefix, id_raw);
+ const char* id = id_string.c_str();
+
int i;
int fd;
char filename[256];
@@ -267,6 +275,14 @@
return -errno;
}
+ struct loop_info64 li;
+ memset(&li, 0, sizeof(li));
+ strlcpy((char*) li.lo_crypt_name, kVoldPrefix, LO_NAME_SIZE);
+ if (ioctl(device_fd.get(), LOOP_SET_STATUS64, &li) == -1) {
+ PLOG(ERROR) << "Failed to LOOP_SET_STATUS64";
+ return -errno;
+ }
+
return 0;
}
@@ -289,9 +305,36 @@
return 0;
}
-int Loop::destroyByFile(const char * /*loopFile*/) {
- errno = ENOSYS;
- return -1;
+int Loop::destroyAll() {
+ for (int i = 0; i < LOOP_MAX; i++) {
+ auto path = StringPrintf("/dev/block/loop%d", i);
+
+ unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC));
+ if (fd.get() == -1) {
+ if (errno != ENOENT) {
+ PLOG(WARNING) << "Failed to open " << path;
+ }
+ continue;
+ }
+
+ struct loop_info64 li;
+ if (ioctl(fd.get(), LOOP_GET_STATUS64, &li) < 0) {
+ PLOG(WARNING) << "Failed to LOOP_GET_STATUS64 " << path;
+ continue;
+ }
+
+ char* id = (char*) li.lo_crypt_name;
+ if (strncmp(id, kVoldPrefix, strlen(kVoldPrefix)) == 0) {
+ LOG(DEBUG) << "Tearing down stale loop device at " << path << " named " << id;
+
+ if (ioctl(fd.get(), LOOP_CLR_FD, 0) < 0) {
+ PLOG(WARNING) << "Failed to LOOP_CLR_FD " << path;
+ }
+ } else {
+ LOG(VERBOSE) << "Found unmanaged loop device at " << path << " named " << id;
+ }
+ }
+ return 0;
}
int Loop::createImageFile(const char *file, unsigned long numSectors) {
diff --git a/Loop.h b/Loop.h
index 5d8f427..e3ad239 100644
--- a/Loop.h
+++ b/Loop.h
@@ -32,7 +32,7 @@
static int create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len);
static int create(const std::string& file, std::string& out_device);
static int destroyByDevice(const char *loopDevice);
- static int destroyByFile(const char *loopFile);
+ static int destroyAll();
static int createImageFile(const char *file, unsigned long numSectors);
static int resizeImageFile(const char *file, unsigned long numSectors);
diff --git a/MoveTask.h b/MoveTask.h
index b1777c0..cb184c3 100644
--- a/MoveTask.h
+++ b/MoveTask.h
@@ -18,7 +18,7 @@
#define ANDROID_VOLD_MOVE_TASK_H
#include "Utils.h"
-#include "VolumeBase.h"
+#include "model/VolumeBase.h"
#include <thread>
diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp
new file mode 100644
index 0000000..374cb4c
--- /dev/null
+++ b/VoldNativeService.cpp
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VoldNativeService.h"
+#include "VolumeManager.h"
+#include "MoveTask.h"
+#include "Process.h"
+#include "TrimTask.h"
+
+#include "cryptfs.h"
+#include "Ext4Crypt.h"
+#include "MetadataCrypt.h"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <fs_mgr.h>
+#include <private/android_filesystem_config.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "vold"
+#endif
+
+using android::base::StringPrintf;
+using std::endl;
+
+namespace android {
+namespace vold {
+
+namespace {
+
+constexpr const char* kDump = "android.permission.DUMP";
+
+static binder::Status ok() {
+ return binder::Status::ok();
+}
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+ return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
+}
+
+static binder::Status error(const std::string& msg) {
+ PLOG(ERROR) << msg;
+ return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
+}
+
+static binder::Status translate(int status) {
+ if (status == 0) {
+ return binder::Status::ok();
+ } else {
+ return binder::Status::fromServiceSpecificError(status);
+ }
+}
+
+static binder::Status translateBool(bool status) {
+ if (status) {
+ return binder::Status::ok();
+ } else {
+ return binder::Status::fromServiceSpecificError(status);
+ }
+}
+
+binder::Status checkPermission(const char* permission) {
+ pid_t pid;
+ uid_t uid;
+
+ if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid),
+ reinterpret_cast<int32_t*>(&uid))) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
+ }
+}
+
+binder::Status checkUid(uid_t expectedUid) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid == expectedUid || uid == AID_ROOT) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
+ }
+}
+
+binder::Status checkArgumentId(const std::string& id) {
+ if (id.empty()) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing ID");
+ }
+ for (const char& c : id) {
+ if (!std::isalnum(c) && c != ':' && c != ',') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("ID %s is malformed", id.c_str()));
+ }
+ }
+ return ok();
+}
+
+binder::Status checkArgumentPath(const std::string& path) {
+ if (path.empty()) {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing path");
+ }
+ if (path[0] != '/') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Path %s is relative", path.c_str()));
+ }
+ for (const char& c : path) {
+ if (c == '\0' || c == '\n') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Path %s is malformed", path.c_str()));
+ }
+ }
+ return ok();
+}
+
+binder::Status checkArgumentHex(const std::string& hex) {
+ // Empty hex strings are allowed
+ for (const char& c : hex) {
+ if (!std::isxdigit(c) && c != ':' && c != '-') {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Hex %s is malformed", hex.c_str()));
+ }
+ }
+ return ok();
+}
+
+#define ENFORCE_UID(uid) { \
+ binder::Status status = checkUid((uid)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_ID(id) { \
+ binder::Status status = checkArgumentId((id)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_PATH(path) { \
+ binder::Status status = checkArgumentPath((path)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_HEX(hex) { \
+ binder::Status status = checkArgumentHex((hex)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define ACQUIRE_LOCK \
+ std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
+
+#define ACQUIRE_CRYPT_LOCK \
+ std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getCryptLock());
+
+} // namespace
+
+status_t VoldNativeService::start() {
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+ status_t ret = BinderService<VoldNativeService>::publish();
+ if (ret != android::OK) {
+ return ret;
+ }
+ sp<ProcessState> ps(ProcessState::self());
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+ return android::OK;
+}
+
+status_t VoldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+ auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
+ const binder::Status dump_permission = checkPermission(kDump);
+ if (!dump_permission.isOk()) {
+ out << dump_permission.toString8() << endl;
+ return PERMISSION_DENIED;
+ }
+
+ ACQUIRE_LOCK;
+ out << "vold is happy!" << endl;
+ out.flush();
+ return NO_ERROR;
+}
+
+binder::Status VoldNativeService::reset() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->reset());
+}
+
+binder::Status VoldNativeService::shutdown() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->shutdown());
+}
+
+binder::Status VoldNativeService::mountAll() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ struct fstab* fstab = fs_mgr_read_fstab_default();
+ int res = fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
+ fs_mgr_free_fstab(fstab);
+ return translate(res);
+}
+
+binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserAdded(userId, userSerial));
+}
+
+binder::Status VoldNativeService::onUserRemoved(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserRemoved(userId));
+}
+
+binder::Status VoldNativeService::onUserStarted(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserStarted(userId));
+}
+
+binder::Status VoldNativeService::onUserStopped(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->onUserStopped(userId));
+}
+
+binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType,
+ int32_t ratio) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(diskId);
+ ACQUIRE_LOCK;
+
+ auto disk = VolumeManager::Instance()->findDisk(diskId);
+ if (disk == nullptr) {
+ return error("Failed to find disk " + diskId);
+ }
+ switch (partitionType) {
+ case PARTITION_TYPE_PUBLIC: return translate(disk->partitionPublic());
+ case PARTITION_TYPE_PRIVATE: return translate(disk->partitionPrivate());
+ case PARTITION_TYPE_MIXED: return translate(disk->partitionMixed(ratio));
+ default: return error("Unknown type " + std::to_string(partitionType));
+ }
+}
+
+binder::Status VoldNativeService::forgetPartition(const std::string& partGuid) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_HEX(partGuid);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->forgetPartition(partGuid));
+}
+
+binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags,
+ int32_t mountUserId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ auto vol = VolumeManager::Instance()->findVolume(volId);
+ if (vol == nullptr) {
+ return error("Failed to find volume " + volId);
+ }
+
+ vol->setMountFlags(mountFlags);
+ vol->setMountUserId(mountUserId);
+
+ int res = vol->mount();
+ if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) {
+ VolumeManager::Instance()->setPrimary(vol);
+ }
+ return translate(res);
+}
+
+binder::Status VoldNativeService::unmount(const std::string& volId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ auto vol = VolumeManager::Instance()->findVolume(volId);
+ if (vol == nullptr) {
+ return error("Failed to find volume " + volId);
+ }
+ return translate(vol->unmount());
+}
+
+binder::Status VoldNativeService::format(const std::string& volId, const std::string& fsType) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ auto vol = VolumeManager::Instance()->findVolume(volId);
+ if (vol == nullptr) {
+ return error("Failed to find volume " + volId);
+ }
+ return translate(vol->format(fsType));
+}
+
+binder::Status VoldNativeService::benchmark(const std::string& volId, int64_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ *_aidl_return = VolumeManager::Instance()->benchmarkPrivate(volId);
+ return ok();
+}
+
+binder::Status VoldNativeService::moveStorage(const std::string& fromVolId,
+ const std::string& toVolId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(fromVolId);
+ CHECK_ARGUMENT_ID(toVolId);
+ ACQUIRE_LOCK;
+
+ auto fromVol = VolumeManager::Instance()->findVolume(fromVolId);
+ auto toVol = VolumeManager::Instance()->findVolume(toVolId);
+ if (fromVol == nullptr) {
+ return error("Failed to find volume " + fromVolId);
+ } else if (toVol == nullptr) {
+ return error("Failed to find volume " + toVolId);
+ }
+ (new android::vold::MoveTask(fromVol, toVol))->start();
+ return ok();
+}
+
+binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ std::string tmp;
+ switch (remountMode) {
+ case REMOUNT_MODE_NONE: tmp = "none"; break;
+ case REMOUNT_MODE_DEFAULT: tmp = "default"; break;
+ case REMOUNT_MODE_READ: tmp = "read"; break;
+ case REMOUNT_MODE_WRITE: tmp = "write"; break;
+ default: return error("Unknown mode " + std::to_string(remountMode));
+ }
+ return translate(VolumeManager::Instance()->remountUid(uid, tmp));
+}
+
+binder::Status VoldNativeService::mkdirs(const std::string& path) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PATH(path);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->mkdirs(path.c_str()));
+}
+
+binder::Status VoldNativeService::createObb(const std::string& sourcePath,
+ const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PATH(sourcePath);
+ CHECK_ARGUMENT_HEX(sourceKey);
+ ACQUIRE_LOCK;
+
+ return translate(
+ VolumeManager::Instance()->createObb(sourcePath, sourceKey, ownerGid, _aidl_return));
+}
+
+binder::Status VoldNativeService::destroyObb(const std::string& volId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_ID(volId);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->destroyObb(volId));
+}
+
+binder::Status VoldNativeService::fstrim(int32_t fstrimFlags) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ (new android::vold::TrimTask(fstrimFlags))->start();
+ return ok();
+}
+
+binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+ android::base::unique_fd* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->mountAppFuse(uid, pid, mountId, _aidl_return));
+}
+
+binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId));
+}
+
+binder::Status VoldNativeService::fdeCheckPassword(const std::string& password) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_check_passwd(password.c_str()));
+}
+
+binder::Status VoldNativeService::fdeRestart() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ // Spawn as thread so init can issue commands back to vold without
+ // causing deadlock, usually as a result of prep_data_fs.
+ std::thread(&cryptfs_restart).detach();
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeComplete(int32_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ *_aidl_return = cryptfs_crypto_complete();
+ return ok();
+}
+
+static int fdeEnableInternal(int32_t passwordType, const std::string& password,
+ int32_t encryptionFlags) {
+ bool noUi = (encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_NO_UI) != 0;
+
+ std::string how;
+ if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_IN_PLACE) != 0) {
+ how = "inplace";
+ } else if ((encryptionFlags & VoldNativeService::ENCRYPTION_FLAG_WIPE) != 0) {
+ how = "wipe";
+ } else {
+ LOG(ERROR) << "Missing encryption flag";
+ return -1;
+ }
+
+ for (int tries = 0; tries < 2; ++tries) {
+ int rc;
+ if (passwordType == VoldNativeService::PASSWORD_TYPE_DEFAULT) {
+ rc = cryptfs_enable_default(how.c_str(), noUi);
+ } else {
+ rc = cryptfs_enable(how.c_str(), passwordType, password.c_str(), noUi);
+ }
+
+ if (rc == 0) {
+ return 0;
+ } else if (tries == 0) {
+ Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
+ }
+ }
+
+ return -1;
+}
+
+binder::Status VoldNativeService::fdeEnable(int32_t passwordType,
+ const std::string& password, int32_t encryptionFlags) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ if (e4crypt_is_native()) {
+ if (passwordType != PASSWORD_TYPE_DEFAULT) {
+ return error("Unexpected password type");
+ }
+ if (encryptionFlags != (ENCRYPTION_FLAG_IN_PLACE | ENCRYPTION_FLAG_NO_UI)) {
+ return error("Unexpected flags");
+ }
+ return translateBool(e4crypt_enable_crypto());
+ }
+
+ // Spawn as thread so init can issue commands back to vold without
+ // causing deadlock, usually as a result of prep_data_fs.
+ std::thread(&fdeEnableInternal, passwordType, password, encryptionFlags).detach();
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeChangePassword(int32_t passwordType,
+ const std::string& password) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_changepw(passwordType, password.c_str()));
+}
+
+binder::Status VoldNativeService::fdeVerifyPassword(const std::string& password) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_verify_passwd(password.c_str()));
+}
+
+binder::Status VoldNativeService::fdeGetField(const std::string& key,
+ std::string* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ char buf[PROPERTY_VALUE_MAX];
+ if (cryptfs_getfield(key.c_str(), buf, sizeof(buf)) != CRYPTO_GETFIELD_OK) {
+ return error(StringPrintf("Failed to read field %s", key.c_str()));
+ } else {
+ *_aidl_return = buf;
+ return ok();
+ }
+}
+
+binder::Status VoldNativeService::fdeSetField(const std::string& key,
+ const std::string& value) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translate(cryptfs_setfield(key.c_str(), value.c_str()));
+}
+
+binder::Status VoldNativeService::fdeGetPasswordType(int32_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ *_aidl_return = cryptfs_get_password_type();
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ const char* res = cryptfs_get_password();
+ if (res != nullptr) {
+ *_aidl_return = res;
+ }
+ return ok();
+}
+
+binder::Status VoldNativeService::fdeClearPassword() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ cryptfs_clear_password();
+ return ok();
+}
+
+binder::Status VoldNativeService::fbeEnable() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_initialize_global_de());
+}
+
+binder::Status VoldNativeService::mountDefaultEncrypted() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ if (e4crypt_is_native()) {
+ return translateBool(e4crypt_mount_metadata_encrypted());
+ } else {
+ // Spawn as thread so init can issue commands back to vold without
+ // causing deadlock, usually as a result of prep_data_fs.
+ std::thread(&cryptfs_mount_default_encrypted).detach();
+ return ok();
+ }
+}
+
+binder::Status VoldNativeService::initUser0() {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_init_user0());
+}
+
+binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ *_aidl_return = cryptfs_isConvertibleToFBE() != 0;
+ return ok();
+}
+
+binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial,
+ bool ephemeral) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_vold_create_user_key(userId, userSerial, ephemeral));
+}
+
+binder::Status VoldNativeService::destroyUserKey(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_destroy_user_key(userId));
+}
+
+binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_add_user_key_auth(userId, userSerial, token.c_str(), secret.c_str()));
+}
+
+binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_fixate_newest_user_key_auth(userId));
+}
+
+binder::Status VoldNativeService::unlockUserKey(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_unlock_user_key(userId, userSerial, token.c_str(), secret.c_str()));
+}
+
+binder::Status VoldNativeService::lockUserKey(int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_lock_user_key(userId));
+}
+
+binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t userSerial, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ return translateBool(e4crypt_prepare_user_storage(uuid_, userId, userSerial, flags));
+}
+
+binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ return translateBool(e4crypt_destroy_user_storage(uuid_, userId, flags));
+}
+
+binder::Status VoldNativeService::secdiscard(const std::string& path) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_CRYPT_LOCK;
+
+ return translateBool(e4crypt_secdiscard(path.c_str()));
+}
+
+} // namespace vold
+} // namespace android
diff --git a/VoldNativeService.h b/VoldNativeService.h
new file mode 100644
index 0000000..50244d2
--- /dev/null
+++ b/VoldNativeService.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _VOLD_NATIVE_SERVICE_H_
+#define _VOLD_NATIVE_SERVICE_H_
+
+#include <android-base/unique_fd.h>
+#include <binder/BinderService.h>
+
+#include "android/os/BnVold.h"
+
+namespace android {
+namespace vold {
+
+class VoldNativeService : public BinderService<VoldNativeService>, public os::BnVold {
+public:
+ static status_t start();
+ static char const* getServiceName() { return "vold"; }
+ virtual status_t dump(int fd, const Vector<String16> &args) override;
+
+ binder::Status reset();
+ binder::Status shutdown();
+ binder::Status mountAll();
+
+ binder::Status onUserAdded(int32_t userId, int32_t userSerial);
+ binder::Status onUserRemoved(int32_t userId);
+ binder::Status onUserStarted(int32_t userId);
+ binder::Status onUserStopped(int32_t userId);
+
+ binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio);
+ binder::Status forgetPartition(const std::string& partGuid);
+
+ binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId);
+ binder::Status unmount(const std::string& volId);
+ binder::Status format(const std::string& volId, const std::string& fsType);
+ binder::Status benchmark(const std::string& volId, int64_t* _aidl_return);
+
+ binder::Status moveStorage(const std::string& fromVolId, const std::string& toVolId);
+
+ binder::Status remountUid(int32_t uid, int32_t remountMode);
+
+ binder::Status mkdirs(const std::string& path);
+
+ binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey,
+ int32_t ownerGid, std::string* _aidl_return);
+ binder::Status destroyObb(const std::string& volId);
+
+ binder::Status fstrim(int32_t fstrimFlags);
+
+ binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+ android::base::unique_fd* _aidl_return);
+ binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId);
+
+ binder::Status fdeCheckPassword(const std::string& password);
+ binder::Status fdeRestart();
+ binder::Status fdeComplete(int32_t* _aidl_return);
+ binder::Status fdeEnable(int32_t passwordType,
+ const std::string& password, int32_t encryptionFlags);
+ binder::Status fdeChangePassword(int32_t passwordType,
+ const std::string& password);
+ binder::Status fdeVerifyPassword(const std::string& password);
+ binder::Status fdeGetField(const std::string& key, std::string* _aidl_return);
+ binder::Status fdeSetField(const std::string& key, const std::string& value);
+ binder::Status fdeGetPasswordType(int32_t* _aidl_return);
+ binder::Status fdeGetPassword(std::string* _aidl_return);
+ binder::Status fdeClearPassword();
+
+ binder::Status fbeEnable();
+
+ binder::Status mountDefaultEncrypted();
+ binder::Status initUser0();
+ binder::Status isConvertibleToFbe(bool* _aidl_return);
+
+ binder::Status createUserKey(int32_t userId, int32_t userSerial, bool ephemeral);
+ binder::Status destroyUserKey(int32_t userId);
+
+ binder::Status addUserKeyAuth(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret);
+ binder::Status fixateNewestUserKeyAuth(int32_t userId);
+
+ binder::Status unlockUserKey(int32_t userId, int32_t userSerial,
+ const std::string& token, const std::string& secret);
+ binder::Status lockUserKey(int32_t userId);
+
+ binder::Status prepareUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t userSerial, int32_t flags);
+ binder::Status destroyUserStorage(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags);
+
+ binder::Status secdiscard(const std::string& path);
+};
+
+} // namespace vold
+} // namespace android
+
+#endif // _VOLD_NATIVE_SERVICE_H_
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 13a943f..022caff 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -48,7 +48,8 @@
#include <private/android_filesystem_config.h>
#include "Benchmark.h"
-#include "EmulatedVolume.h"
+#include "model/EmulatedVolume.h"
+#include "model/ObbVolume.h"
#include "VolumeManager.h"
#include "NetlinkManager.h"
#include "ResponseCode.h"
@@ -68,6 +69,7 @@
+ ((number) & (~((1U << (po2)) - 1))))
using android::base::StringPrintf;
+using android::base::unique_fd;
/*
* Path to external storage where *only* root can access ASEC image files
@@ -220,6 +222,7 @@
mSavedDirtyRatio = -1;
// set dirty ratio to 0 when UMS is active
mUmsDirtyRatio = 0;
+ mNextObbId = 0;
}
VolumeManager::~VolumeManager() {
@@ -317,6 +320,9 @@
// directories that we own, in case we crashed.
unmountAll();
+ Devmapper::destroyAll();
+ Loop::destroyAll();
+
// Assume that we always have an emulated volume on internal
// storage; the framework will decide if it should be mounted.
CHECK(mInternalEmulated == nullptr);
@@ -437,6 +443,11 @@
return vol;
}
}
+ for (const auto& vol : mObbVolumes) {
+ if (vol->getId() == id) {
+ return vol;
+ }
+ }
return nullptr;
}
@@ -754,7 +765,7 @@
endmntent(fp);
for (const auto& path : toUnmount) {
- SLOGW("Tearing down stale mount %s", path.c_str());
+ LOG(DEBUG) << "Tearing down stale mount " << path;
android::vold::ForceUnmount(path);
}
@@ -1952,7 +1963,7 @@
return found_mp;
}
-int VolumeManager::mkdirs(char* path) {
+int VolumeManager::mkdirs(const char* path) {
// Only offer to create directories for paths managed by vold
if (strncmp(path, "/storage/", 9) == 0) {
// fs_mkdirs() does symlink checking and relative path enforcement
@@ -1962,3 +1973,223 @@
return -EINVAL;
}
}
+
+static size_t kAppFuseMaxMountPointName = 32;
+
+static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
+ if (name.size() > kAppFuseMaxMountPointName) {
+ LOG(ERROR) << "AppFuse mount name is too long.";
+ return -EINVAL;
+ }
+ for (size_t i = 0; i < name.size(); i++) {
+ if (!isalnum(name[i])) {
+ LOG(ERROR) << "AppFuse mount name contains invalid character.";
+ return -EINVAL;
+ }
+ }
+ *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
+ return android::OK;
+}
+
+static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
+ // Remove existing mount.
+ android::vold::ForceUnmount(path);
+
+ const auto opts = android::base::StringPrintf(
+ "fd=%i,"
+ "rootmode=40000,"
+ "default_permissions,"
+ "allow_other,"
+ "user_id=%d,group_id=%d,"
+ "context=\"u:object_r:app_fuse_file:s0\","
+ "fscontext=u:object_r:app_fusefs:s0",
+ device_fd,
+ uid,
+ uid);
+
+ const int result = TEMP_FAILURE_RETRY(mount(
+ "/dev/fuse", path.c_str(), "fuse",
+ MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
+ if (result != 0) {
+ PLOG(ERROR) << "Failed to mount " << path;
+ return -errno;
+ }
+
+ return android::OK;
+}
+
+static android::status_t runCommandInNamespace(const std::string& command,
+ uid_t uid,
+ pid_t pid,
+ const std::string& path,
+ int device_fd) {
+ if (DEBUG_APPFUSE) {
+ LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
+ << " in namespace " << uid;
+ }
+
+ unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (dir.get() == -1) {
+ PLOG(ERROR) << "Failed to open /proc";
+ return -errno;
+ }
+
+ // Obtains process file descriptor.
+ const std::string pid_str = android::base::StringPrintf("%d", pid);
+ const unique_fd pid_fd(
+ openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (pid_fd.get() == -1) {
+ PLOG(ERROR) << "Failed to open /proc/" << pid;
+ return -errno;
+ }
+
+ // Check UID of process.
+ {
+ struct stat sb;
+ const int result = fstat(pid_fd.get(), &sb);
+ if (result == -1) {
+ PLOG(ERROR) << "Failed to stat /proc/" << pid;
+ return -errno;
+ }
+ if (sb.st_uid != AID_SYSTEM) {
+ LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
+ << ", actual=" << sb.st_uid;
+ return -EPERM;
+ }
+ }
+
+ // Matches so far, but refuse to touch if in root namespace
+ {
+ char rootName[PATH_MAX];
+ char pidName[PATH_MAX];
+ const int root_result =
+ android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
+ const int pid_result =
+ android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
+ if (root_result == -1) {
+ LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
+ return -EPERM;
+ }
+ if (pid_result == -1) {
+ LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
+ return -EPERM;
+ }
+ if (!strcmp(rootName, pidName)) {
+ LOG(ERROR) << "Don't mount appfuse in root namespace";
+ return -EPERM;
+ }
+ }
+
+ // We purposefully leave the namespace open across the fork
+ unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
+ if (ns_fd.get() < 0) {
+ PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
+ return -errno;
+ }
+
+ int child = fork();
+ if (child == 0) {
+ if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
+ PLOG(ERROR) << "Failed to setns";
+ _exit(-errno);
+ }
+
+ if (command == "mount") {
+ _exit(mountInNamespace(uid, device_fd, path));
+ } else if (command == "unmount") {
+ // If it's just after all FD opened on mount point are closed, umount2 can fail with
+ // EBUSY. To avoid the case, specify MNT_DETACH.
+ if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
+ errno != EINVAL && errno != ENOENT) {
+ PLOG(ERROR) << "Failed to unmount directory.";
+ _exit(-errno);
+ }
+ if (rmdir(path.c_str()) != 0) {
+ PLOG(ERROR) << "Failed to remove the mount directory.";
+ _exit(-errno);
+ }
+ _exit(android::OK);
+ } else {
+ LOG(ERROR) << "Unknown appfuse command " << command;
+ _exit(-EPERM);
+ }
+ }
+
+ if (child == -1) {
+ PLOG(ERROR) << "Failed to folk child process";
+ return -errno;
+ }
+
+ android::status_t status;
+ TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
+
+ return status;
+}
+
+int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
+ int32_t ownerGid, std::string* outVolId) {
+ int id = mNextObbId++;
+
+ auto vol = std::shared_ptr<android::vold::VolumeBase>(
+ new android::vold::ObbVolume(id, sourcePath, sourceKey, ownerGid));
+ vol->create();
+
+ mObbVolumes.push_back(vol);
+ *outVolId = vol->getId();
+ return android::OK;
+}
+
+int VolumeManager::destroyObb(const std::string& volId) {
+ auto i = mObbVolumes.begin();
+ while (i != mObbVolumes.end()) {
+ if ((*i)->getId() == volId) {
+ (*i)->destroy();
+ i = mObbVolumes.erase(i);
+ } else {
+ ++i;
+ }
+ }
+ return android::OK;
+}
+
+int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId,
+ android::base::unique_fd* device_fd) {
+ std::string name = std::to_string(mountId);
+
+ // Check mount point name.
+ std::string path;
+ if (getMountPath(uid, name, &path) != android::OK) {
+ LOG(ERROR) << "Invalid mount point name";
+ return -1;
+ }
+
+ // Create directories.
+ const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
+ if (result != android::OK) {
+ PLOG(ERROR) << "Failed to prepare directory " << path;
+ return -1;
+ }
+
+ // Open device FD.
+ device_fd->reset(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
+ if (device_fd->get() == -1) {
+ PLOG(ERROR) << "Failed to open /dev/fuse";
+ return -1;
+ }
+
+ // Mount.
+ return runCommandInNamespace("mount", uid, pid, path, device_fd->get());
+}
+
+int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) {
+ std::string name = std::to_string(mountId);
+
+ // Check mount point name.
+ std::string path;
+ if (getMountPath(uid, name, &path) != android::OK) {
+ LOG(ERROR) << "Invalid mount point name";
+ return -1;
+ }
+
+ return runCommandInNamespace("unmount", uid, pid, path, -1 /* device_fd */);
+}
diff --git a/VolumeManager.h b/VolumeManager.h
index 537aebe..7dc69f3 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -29,18 +29,21 @@
#include <unordered_map>
#include <unordered_set>
+#include <android-base/unique_fd.h>
#include <cutils/multiuser.h>
#include <utils/List.h>
#include <utils/Timers.h>
#include <sysutils/SocketListener.h>
#include <sysutils/NetlinkEvent.h>
-#include "Disk.h"
-#include "VolumeBase.h"
+#include "model/Disk.h"
+#include "model/VolumeBase.h"
/* The length of an MD5 hash when encoded into ASCII hex characters */
#define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1)
+#define DEBUG_APPFUSE 0
+
typedef enum { ASEC, OBB } container_type_t;
class ContainerData {
@@ -91,6 +94,7 @@
// TODO: pipe all requests through VM to avoid exposing this lock
std::mutex& getLock() { return mLock; }
+ std::mutex& getCryptLock() { return mCryptLock; }
int start();
int stop();
@@ -196,7 +200,14 @@
* is treated as filename and ignored, unless the path ends with "/". Also
* ensures that path belongs to a volume managed by vold.
*/
- int mkdirs(char* path);
+ int mkdirs(const char* path);
+
+ int createObb(const std::string& path, const std::string& key, int32_t ownerGid,
+ std::string* outVolId);
+ int destroyObb(const std::string& volId);
+
+ int mountAppFuse(uid_t uid, pid_t pid, int mountId, android::base::unique_fd* device_fd);
+ int unmountAppFuse(uid_t uid, pid_t pid, int mountId);
private:
VolumeManager();
@@ -208,9 +219,11 @@
int linkPrimary(userid_t userId);
std::mutex mLock;
+ std::mutex mCryptLock;
std::list<std::shared_ptr<DiskSource>> mDiskSources;
std::list<std::shared_ptr<android::vold::Disk>> mDisks;
+ std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
std::unordered_map<userid_t, int> mAddedUsers;
std::unordered_set<userid_t> mStartedUsers;
@@ -219,6 +232,8 @@
std::shared_ptr<android::vold::Disk> mVirtualDisk;
std::shared_ptr<android::vold::VolumeBase> mInternalEmulated;
std::shared_ptr<android::vold::VolumeBase> mPrimary;
+
+ int mNextObbId;
};
extern "C" {
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
new file mode 100644
index 0000000..e8a8f2a
--- /dev/null
+++ b/binder/android/os/IVold.aidl
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IVold {
+ void reset();
+ void shutdown();
+ void mountAll();
+
+ void onUserAdded(int userId, int userSerial);
+ void onUserRemoved(int userId);
+ void onUserStarted(int userId);
+ void onUserStopped(int userId);
+
+ void partition(@utf8InCpp String diskId, int partitionType, int ratio);
+ void forgetPartition(@utf8InCpp String partGuid);
+
+ void mount(@utf8InCpp String volId, int mountFlags, int mountUserId);
+ void unmount(@utf8InCpp String volId);
+ void format(@utf8InCpp String volId, @utf8InCpp String fsType);
+ long benchmark(@utf8InCpp String volId);
+
+ void moveStorage(@utf8InCpp String fromVolId, @utf8InCpp String toVolId);
+
+ void remountUid(int uid, int remountMode);
+
+ void mkdirs(@utf8InCpp String path);
+
+ @utf8InCpp String createObb(@utf8InCpp String sourcePath,
+ @utf8InCpp String sourceKey, int ownerGid);
+ void destroyObb(@utf8InCpp String volId);
+
+ void fstrim(int fstrimFlags);
+
+ FileDescriptor mountAppFuse(int uid, int pid, int mountId);
+ void unmountAppFuse(int uid, int pid, int mountId);
+
+ void fdeCheckPassword(@utf8InCpp String password);
+ void fdeRestart();
+ int fdeComplete();
+ void fdeEnable(int passwordType, @utf8InCpp String password, int encryptionFlags);
+ void fdeChangePassword(int passwordType, @utf8InCpp String password);
+ void fdeVerifyPassword(@utf8InCpp String password);
+ @utf8InCpp String fdeGetField(@utf8InCpp String key);
+ void fdeSetField(@utf8InCpp String key, @utf8InCpp String value);
+ int fdeGetPasswordType();
+ @utf8InCpp String fdeGetPassword();
+ void fdeClearPassword();
+
+ void fbeEnable();
+
+ void mountDefaultEncrypted();
+ void initUser0();
+ boolean isConvertibleToFbe();
+
+ void createUserKey(int userId, int userSerial, boolean ephemeral);
+ void destroyUserKey(int userId);
+
+ void addUserKeyAuth(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret);
+ void fixateNewestUserKeyAuth(int userId);
+
+ void unlockUserKey(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret);
+ void lockUserKey(int userId);
+
+ void prepareUserStorage(@nullable @utf8InCpp String uuid, int userId, int userSerial, int storageFlags);
+ void destroyUserStorage(@nullable @utf8InCpp String uuid, int userId, int storageFlags);
+
+ void secdiscard(@utf8InCpp String path);
+
+ const int ENCRYPTION_FLAG_WIPE = 1;
+ const int ENCRYPTION_FLAG_IN_PLACE = 2;
+ const int ENCRYPTION_FLAG_NO_UI = 4;
+
+ const int ENCRYPTION_STATE_NONE = 1;
+ const int ENCRYPTION_STATE_OK = 0;
+ const int ENCRYPTION_STATE_ERROR_UNKNOWN = -1;
+ const int ENCRYPTION_STATE_ERROR_INCOMPLETE = -2;
+ const int ENCRYPTION_STATE_ERROR_INCONSISTENT = -3;
+ const int ENCRYPTION_STATE_ERROR_CORRUPT = -4;
+
+ const int FSTRIM_FLAG_DEEP_TRIM = 1;
+ const int FSTRIM_FLAG_BENCHMARK_AFTER = 2;
+
+ const int MOUNT_FLAG_PRIMARY = 1;
+ const int MOUNT_FLAG_VISIBLE = 2;
+
+ const int PARTITION_TYPE_PUBLIC = 0;
+ const int PARTITION_TYPE_PRIVATE = 1;
+ const int PARTITION_TYPE_MIXED = 2;
+
+ const int PASSWORD_TYPE_PASSWORD = 0;
+ const int PASSWORD_TYPE_DEFAULT = 1;
+ const int PASSWORD_TYPE_PIN = 2;
+ const int PASSWORD_TYPE_PATTERN = 3;
+
+ const int STORAGE_FLAG_DE = 1;
+ const int STORAGE_FLAG_CE = 2;
+
+ const int REMOUNT_MODE_NONE = 0;
+ const int REMOUNT_MODE_DEFAULT = 1;
+ const int REMOUNT_MODE_READ = 2;
+ const int REMOUNT_MODE_WRITE = 3;
+
+ const int STATE_UNMOUNTED = 0;
+ const int STATE_CHECKING = 1;
+ const int STATE_MOUNTED = 2;
+ const int STATE_MOUNTED_READ_ONLY = 3;
+ const int STATE_FORMATTING = 4;
+ const int STATE_EJECTING = 5;
+ const int STATE_UNMOUNTABLE = 6;
+ const int STATE_REMOVED = 7;
+ const int STATE_BAD_REMOVAL = 8;
+
+ const int TYPE_PUBLIC = 0;
+ const int TYPE_PRIVATE = 1;
+ const int TYPE_EMULATED = 2;
+ const int TYPE_ASEC = 3;
+ const int TYPE_OBB = 4;
+}
diff --git a/cryptfs.cpp b/cryptfs.cpp
index a79909a..adfb284 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -38,7 +38,6 @@
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <errno.h>
-#include <ext4_utils/ext4.h>
#include <ext4_utils/ext4_utils.h>
#include <linux/kdev_t.h>
#include <fs_mgr.h>
@@ -1814,7 +1813,7 @@
return rc;
}
-int cryptfs_verify_passwd(char *passwd)
+int cryptfs_verify_passwd(const char *passwd)
{
struct crypt_mnt_ftr crypt_ftr;
/* Allocate enough space for a 256 bit key, but we may use less */
@@ -1913,7 +1912,6 @@
int rc = -1;
if (type == EXT4_FS) {
-#ifdef TARGET_USES_MKE2FS
args[0] = "/system/bin/mke2fs";
args[1] = "-M";
args[2] = "/data";
@@ -1925,16 +1923,6 @@
snprintf(size_str, sizeof(size_str), "%" PRId64, size / (4096 / 512));
args[8] = size_str;
num_args = 9;
-#else
- args[0] = "/system/bin/make_ext4fs";
- args[1] = "-a";
- args[2] = "/data";
- args[3] = "-l";
- snprintf(size_str, sizeof(size_str), "%" PRId64, size * 512);
- args[4] = size_str;
- args[5] = crypto_blkdev;
- num_args = 6;
-#endif
SLOGI("Making empty filesystem with command %s %s %s %s %s %s\n",
args[0], args[1], args[2], args[3], args[4], args[5]);
} else if (type == F2FS_FS) {
@@ -2070,7 +2058,7 @@
return rc;
}
-int cryptfs_enable_internal(char *howarg, int crypt_type, const char *passwd,
+int cryptfs_enable_internal(const char *howarg, int crypt_type, const char *passwd,
int no_ui)
{
int how = 0;
@@ -2429,12 +2417,12 @@
return -1;
}
-int cryptfs_enable(char *howarg, int type, char *passwd, int no_ui)
+int cryptfs_enable(const char *howarg, int type, const char *passwd, int no_ui)
{
return cryptfs_enable_internal(howarg, type, passwd, no_ui);
}
-int cryptfs_enable_default(char *howarg, int no_ui)
+int cryptfs_enable_default(const char *howarg, int no_ui)
{
return cryptfs_enable_internal(howarg, CRYPT_TYPE_DEFAULT,
DEFAULT_PASSWORD, no_ui);
diff --git a/cryptfs.h b/cryptfs.h
index d20d96d..a7b650f 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -229,11 +229,11 @@
int cryptfs_crypto_complete(void);
int cryptfs_check_passwd(const char *pw);
- int cryptfs_verify_passwd(char *newpw);
+ int cryptfs_verify_passwd(const char *pw);
int cryptfs_restart(void);
- int cryptfs_enable(char *flag, int type, char *passwd, int no_ui);
+ int cryptfs_enable(const char *flag, int type, const char *passwd, int no_ui);
int cryptfs_changepw(int type, const char *newpw);
- int cryptfs_enable_default(char *flag, int no_ui);
+ int cryptfs_enable_default(const char *flag, int no_ui);
int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev,
const unsigned char* key, int keysize, char* out_crypto_blkdev);
int cryptfs_revert_ext_volume(const char* label);
diff --git a/main.cpp b/main.cpp
index 30c839e..8175dc5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-#include "Disk.h"
+#include "model/Disk.h"
#include "VolumeManager.h"
#include "CommandListener.h"
#include "CryptCommandListener.h"
#include "NetlinkManager.h"
+#include "VoldNativeService.h"
#include "cryptfs.h"
#include "sehandle.h"
@@ -106,6 +107,11 @@
exit(1);
}
+ if (android::vold::VoldNativeService::start() != android::OK) {
+ LOG(ERROR) << "Unable to start VoldNativeService";
+ exit(1);
+ }
+
bool has_adoptable;
bool has_quota;
diff --git a/Disk.cpp b/model/Disk.cpp
similarity index 100%
rename from Disk.cpp
rename to model/Disk.cpp
diff --git a/Disk.h b/model/Disk.h
similarity index 100%
rename from Disk.h
rename to model/Disk.h
diff --git a/EmulatedVolume.cpp b/model/EmulatedVolume.cpp
similarity index 100%
rename from EmulatedVolume.cpp
rename to model/EmulatedVolume.cpp
diff --git a/EmulatedVolume.h b/model/EmulatedVolume.h
similarity index 100%
rename from EmulatedVolume.h
rename to model/EmulatedVolume.h
diff --git a/model/ObbVolume.cpp b/model/ObbVolume.cpp
new file mode 100644
index 0000000..709c7a3
--- /dev/null
+++ b/model/ObbVolume.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fs/Vfat.h"
+#include "Devmapper.h"
+#include "Loop.h"
+#include "ObbVolume.h"
+#include "Utils.h"
+#include "VoldUtil.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <cutils/fs.h>
+#include <private/android_filesystem_config.h>
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/wait.h>
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+namespace android {
+namespace vold {
+
+ObbVolume::ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
+ gid_t ownerGid) : VolumeBase(Type::kObb) {
+ setId(StringPrintf("obb:%d", id));
+ mSourcePath = sourcePath;
+ mSourceKey = sourceKey;
+ mOwnerGid = ownerGid;
+}
+
+ObbVolume::~ObbVolume() {
+}
+
+status_t ObbVolume::doCreate() {
+ if (Loop::create(mSourcePath, mLoopPath)) {
+ PLOG(ERROR) << getId() << " failed to create loop";
+ return -1;
+ }
+
+ if (!mSourceKey.empty()) {
+ unsigned long nr_sec = 0;
+ {
+ unique_fd loop_fd(open(mLoopPath.c_str(), O_RDWR | O_CLOEXEC));
+ if (loop_fd.get() == -1) {
+ PLOG(ERROR) << getId() << " failed to open loop";
+ return -1;
+ }
+
+ get_blkdev_size(loop_fd.get(), &nr_sec);
+ if (nr_sec == 0) {
+ PLOG(ERROR) << getId() << " failed to get loop size";
+ return -1;
+ }
+ }
+
+ char tmp[PATH_MAX];
+ if (Devmapper::create(getId().c_str(), mLoopPath.c_str(), mSourceKey.c_str(), nr_sec,
+ tmp, PATH_MAX)) {
+ PLOG(ERROR) << getId() << " failed to create dm";
+ return -1;
+ }
+ mDmPath = tmp;
+ mMountPath = mDmPath;
+ } else {
+ mMountPath = mLoopPath;
+ }
+ return OK;
+}
+
+status_t ObbVolume::doDestroy() {
+ if (!mDmPath.empty() && Devmapper::destroy(getId().c_str())) {
+ PLOG(WARNING) << getId() << " failed to destroy dm";
+ }
+ if (!mLoopPath.empty() && Loop::destroyByDevice(mLoopPath.c_str())) {
+ PLOG(WARNING) << getId() << " failed to destroy loop";
+ }
+ mDmPath.clear();
+ mLoopPath.clear();
+ return OK;
+}
+
+status_t ObbVolume::doMount() {
+ auto path = StringPrintf("/mnt/obb/%s", getId().c_str());
+ setPath(path);
+
+ if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT)) {
+ PLOG(ERROR) << getId() << " failed to create mount point";
+ return -1;
+ }
+ if (android::vold::vfat::Mount(mMountPath, path,
+ true, false, true, 0, mOwnerGid, 0227, false)) {
+ PLOG(ERROR) << getId() << " failed to mount";
+ return -1;
+ }
+ return OK;
+}
+
+status_t ObbVolume::doUnmount() {
+ auto path = getPath();
+
+ KillProcessesUsingPath(path);
+ ForceUnmount(path);
+ rmdir(path.c_str());
+
+ return OK;
+}
+
+} // namespace vold
+} // namespace android
diff --git a/model/ObbVolume.h b/model/ObbVolume.h
new file mode 100644
index 0000000..5ec0cde
--- /dev/null
+++ b/model/ObbVolume.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_VOLD_OBB_VOLUME_H
+#define ANDROID_VOLD_OBB_VOLUME_H
+
+#include "VolumeBase.h"
+
+#include <cutils/multiuser.h>
+
+namespace android {
+namespace vold {
+
+/*
+ * OBB container.
+ */
+class ObbVolume : public VolumeBase {
+public:
+ ObbVolume(int id, const std::string& sourcePath, const std::string& sourceKey,
+ gid_t ownerGid);
+ virtual ~ObbVolume();
+
+protected:
+ status_t doCreate() override;
+ status_t doDestroy() override;
+ status_t doMount() override;
+ status_t doUnmount() override;
+
+private:
+ std::string mSourcePath;
+ std::string mSourceKey;
+ gid_t mOwnerGid;
+
+ std::string mLoopPath;
+ std::string mDmPath;
+ std::string mMountPath;
+
+ DISALLOW_COPY_AND_ASSIGN(ObbVolume);
+};
+
+} // namespace vold
+} // namespace android
+
+#endif
diff --git a/PrivateVolume.cpp b/model/PrivateVolume.cpp
similarity index 100%
rename from PrivateVolume.cpp
rename to model/PrivateVolume.cpp
diff --git a/PrivateVolume.h b/model/PrivateVolume.h
similarity index 100%
rename from PrivateVolume.h
rename to model/PrivateVolume.h
diff --git a/PublicVolume.cpp b/model/PublicVolume.cpp
similarity index 100%
rename from PublicVolume.cpp
rename to model/PublicVolume.cpp
diff --git a/PublicVolume.h b/model/PublicVolume.h
similarity index 100%
rename from PublicVolume.h
rename to model/PublicVolume.h
diff --git a/VolumeBase.cpp b/model/VolumeBase.cpp
similarity index 100%
rename from VolumeBase.cpp
rename to model/VolumeBase.cpp
diff --git a/VolumeBase.h b/model/VolumeBase.h
similarity index 100%
rename from VolumeBase.h
rename to model/VolumeBase.h
diff --git a/tests/Android.mk b/tests/Android.mk
index 4b6573e..9cebd1a 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -5,9 +5,10 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_C_INCLUDES := \
- system/core/fs_mgr/include
+ system/core/fs_mgr/include \
+ system/vold/
-LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto
+LOCAL_STATIC_LIBRARIES := libbase libselinux libvold liblog libcrypto
LOCAL_SRC_FILES := VolumeManager_test.cpp
LOCAL_MODULE := vold_tests