Merge "Merge Android Pie into master"

This commit is contained in:
Xin Li 2018-08-07 16:51:28 +00:00 committed by Gerrit Code Review
commit 7fcaa13d4c
86 changed files with 5123 additions and 6029 deletions

11
.clang-format Normal file
View file

@ -0,0 +1,11 @@
BasedOnStyle: Google
AccessModifierOffset: -2
AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IndentWidth: 4
PointerAlignment: Left
TabWidth: 4
UseTab: Never
PenaltyExcessCharacter: 32

249
Android.bp Normal file
View file

@ -0,0 +1,249 @@
cc_defaults {
name: "vold_default_flags",
cflags: [
"-Wall",
"-Werror",
"-Wextra",
"-Wno-missing-field-initializers",
"-Wno-unused-parameter",
"-Wno-unused-variable",
],
clang: true,
tidy: true,
tidy_checks: [
"-*",
"cert-*",
"clang-analyzer-security*",
],
tidy_flags: [
"-warnings-as-errors=clang-analyzer-security*,cert-*",
],
}
cc_defaults {
name: "vold_default_libs",
static_libs: [
"libavb",
"libbootloader_message",
"libfec",
"libfec_rs",
"libfs_mgr",
"libscrypt_static",
"libsquashfs_utils",
"libvold_binder",
],
shared_libs: [
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
"libbase",
"libbinder",
"libcrypto",
"libcrypto_utils",
"libcutils",
"libdiskconfig",
"libext4_utils",
"libf2fs_sparseblock",
"libhardware",
"libhardware_legacy",
"libhidlbase",
"libhwbinder",
"libkeymaster4support",
"libkeyutils",
"liblog",
"liblogwrap",
"libselinux",
"libsysutils",
"libutils",
],
}
cc_library_static {
name: "libvold_binder",
defaults: ["vold_default_flags"],
srcs: [
":vold_aidl",
],
shared_libs: [
"libbinder",
"libutils",
],
aidl: {
local_include_dirs: ["binder"],
include_dirs: ["frameworks/native/aidl/binder"],
export_aidl_headers: true,
},
}
cc_library_headers {
name: "libvold_headers",
export_include_dirs: ["."],
}
// Static library factored out to support testing
cc_library_static {
name: "libvold",
defaults: [
"vold_default_flags",
"vold_default_libs",
],
srcs: [
"Benchmark.cpp",
"CheckEncryption.cpp",
"Devmapper.cpp",
"EncryptInplace.cpp",
"Ext4Crypt.cpp",
"FileDeviceUtils.cpp",
"IdleMaint.cpp",
"KeyBuffer.cpp",
"KeyStorage.cpp",
"KeyUtil.cpp",
"Keymaster.cpp",
"Loop.cpp",
"MetadataCrypt.cpp",
"MoveStorage.cpp",
"NetlinkHandler.cpp",
"NetlinkManager.cpp",
"Process.cpp",
"ScryptParameters.cpp",
"Utils.cpp",
"VoldNativeService.cpp",
"VoldUtil.cpp",
"VolumeManager.cpp",
"cryptfs.cpp",
"fs/Exfat.cpp",
"fs/Ext4.cpp",
"fs/F2fs.cpp",
"fs/Vfat.cpp",
"model/Disk.cpp",
"model/EmulatedVolume.cpp",
"model/ObbVolume.cpp",
"model/PrivateVolume.cpp",
"model/PublicVolume.cpp",
"model/VolumeBase.cpp",
"secontext.cpp",
],
product_variables: {
arc: {
exclude_srcs: [
"model/ObbVolume.cpp",
],
static_libs: [
"arc_services_aidl",
"libarcobbvolume",
],
},
},
}
cc_binary {
name: "vold",
defaults: [
"vold_default_flags",
"vold_default_libs",
],
srcs: ["main.cpp"],
static_libs: ["libvold"],
product_variables: {
arc: {
static_libs: [
"arc_services_aidl",
"libarcobbvolume",
],
},
},
init_rc: [
"vold.rc",
"wait_for_keymaster.rc",
],
required: [
"mke2fs",
"vold_prepare_subdirs",
"wait_for_keymaster",
],
}
cc_binary {
name: "vdc",
defaults: ["vold_default_flags"],
srcs: ["vdc.cpp"],
shared_libs: [
"libbase",
"libbinder",
"libcutils",
"libutils",
],
static_libs: [
"libvold_binder",
],
init_rc: ["vdc.rc"],
}
cc_binary {
name: "wait_for_keymaster",
defaults: ["vold_default_flags"],
srcs: [
"wait_for_keymaster.cpp",
"Keymaster.cpp",
],
shared_libs: [
"libbase",
"libbinder",
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
"libhardware",
"libhardware_legacy",
"libhidlbase",
"libhwbinder",
"libkeymaster4support",
],
}
cc_binary {
name: "secdiscard",
defaults: ["vold_default_flags"],
srcs: [
"FileDeviceUtils.cpp",
"secdiscard.cpp",
],
shared_libs: ["libbase"],
}
cc_binary {
name: "vold_prepare_subdirs",
defaults: ["vold_default_flags"],
srcs: ["vold_prepare_subdirs.cpp", "Utils.cpp"],
shared_libs: [
"libbase",
"libcutils",
"liblogwrap",
"libselinux",
"libutils",
],
static_libs: [
"libvold_binder",
],
}
filegroup {
name: "vold_aidl",
srcs: [
"binder/android/os/IVold.aidl",
"binder/android/os/IVoldListener.aidl",
"binder/android/os/IVoldTaskListener.aidl",
],
}
subdirs = ["tests"]

View file

@ -1,173 +0,0 @@
LOCAL_PATH:= $(call my-dir)
common_src_files := \
VolumeManager.cpp \
CommandListener.cpp \
CryptCommandListener.cpp \
VoldCommand.cpp \
NetlinkManager.cpp \
NetlinkHandler.cpp \
Process.cpp \
fs/Ext4.cpp \
fs/F2fs.cpp \
fs/Vfat.cpp \
Loop.cpp \
Devmapper.cpp \
ResponseCode.cpp \
Ext4Crypt.cpp \
VoldUtil.c \
cryptfs.cpp \
Disk.cpp \
VolumeBase.cpp \
PublicVolume.cpp \
PrivateVolume.cpp \
EmulatedVolume.cpp \
Utils.cpp \
MoveTask.cpp \
Benchmark.cpp \
TrimTask.cpp \
KeyBuffer.cpp \
Keymaster.cpp \
KeyStorage.cpp \
KeyUtil.cpp \
ScryptParameters.cpp \
secontext.cpp \
EncryptInplace.cpp \
MetadataCrypt.cpp \
common_c_includes := \
system/extras/f2fs_utils \
external/scrypt/lib/crypto \
external/f2fs-tools/include \
frameworks/native/include \
system/security/keystore \
common_shared_libraries := \
libsysutils \
libbinder \
libcutils \
libkeyutils \
liblog \
libdiskconfig \
libhardware_legacy \
liblogwrap \
libext4_utils \
libf2fs_sparseblock \
libcrypto_utils \
libcrypto \
libselinux \
libutils \
libhardware \
libbase \
libhwbinder \
libhidlbase \
android.hardware.keymaster@3.0 \
libkeystore_binder
common_static_libraries := \
libbootloader_message \
libfs_mgr \
libfec \
libfec_rs \
libsquashfs_utils \
libscrypt_static \
libavb \
# TODO: include "cert-err34-c" once we move to Binder
# TODO: include "cert-err58-cpp" once 36656327 is fixed
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
vold_conlyflags := -std=c11
vold_cflags := -Werror -Wall -Wno-missing-field-initializers -Wno-unused-variable -Wno-unused-parameter
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
endif
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := libvold
LOCAL_CLANG := true
LOCAL_TIDY := true
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES := $(common_src_files)
LOCAL_C_INCLUDES := $(common_c_includes)
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
LOCAL_MODULE_TAGS := eng tests
LOCAL_CFLAGS := $(vold_cflags)
LOCAL_CONLYFLAGS := $(vold_conlyflags)
LOCAL_REQUIRED_MODULES := $(required_modules)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := vold
LOCAL_CLANG := true
LOCAL_TIDY := true
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES := \
main.cpp \
$(common_src_files)
LOCAL_INIT_RC := vold.rc
LOCAL_C_INCLUDES := $(common_c_includes)
LOCAL_CFLAGS := $(vold_cflags)
LOCAL_CONLYFLAGS := $(vold_conlyflags)
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
LOCAL_REQUIRED_MODULES := $(required_modules)
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
LOCAL_TIDY := true
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES := vdc.cpp
LOCAL_MODULE := vdc
LOCAL_SHARED_LIBRARIES := libcutils libbase
LOCAL_CFLAGS := $(vold_cflags)
LOCAL_CONLYFLAGS := $(vold_conlyflags)
LOCAL_INIT_RC := vdc.rc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
LOCAL_TIDY := true
LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
LOCAL_SRC_FILES:= \
FileDeviceUtils.cpp \
secdiscard.cpp \
LOCAL_MODULE:= secdiscard
LOCAL_SHARED_LIBRARIES := libbase
LOCAL_CFLAGS := $(vold_cflags)
LOCAL_CONLYFLAGS := $(vold_conlyflags)
include $(BUILD_EXECUTABLE)
include $(LOCAL_PATH)/tests/Android.mk

43
Asec.h
View file

@ -1,43 +0,0 @@
/*
* Copyright (C) 2008 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 _ASEC_H
#define _ASEC_H
struct asec_superblock {
#define ASEC_SB_MAGIC 0xc0def00d
unsigned int magic;
#define ASEC_SB_VER 1
unsigned char ver;
#define ASEC_SB_C_CIPHER_NONE 0
#define ASEC_SB_C_CIPHER_TWOFISH 1
#define ASEC_SB_C_CIPHER_AES 2
unsigned char c_cipher;
#define ASEC_SB_C_CHAIN_NONE 0
unsigned char c_chain;
#define ASEC_SB_C_OPTS_NONE 0
#define ASEC_SB_C_OPTS_EXT4 1
unsigned char c_opts;
#define ASEC_SB_C_MODE_NONE 0
unsigned char c_mode;
} __attribute__((packed));
#endif

View file

@ -17,57 +17,91 @@
#include "Benchmark.h"
#include "BenchmarkGen.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <cutils/iosched_policy.h>
#include <hardware_legacy/power.h>
#include <private/android_filesystem_config.h>
#include <thread>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#define ENABLE_DROP_CACHES 1
using android::base::ReadFileToString;
using android::base::WriteStringToFile;
namespace android {
namespace vold {
static void notifyResult(const std::string& path, int64_t create_d,
int64_t drop_d, int64_t run_d, int64_t destroy_d) {
std::string res(path +
+ " " + BenchmarkIdent()
+ " " + std::to_string(create_d)
+ " " + std::to_string(drop_d)
+ " " + std::to_string(run_d)
+ " " + std::to_string(destroy_d));
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::BenchmarkResult, res.c_str(), false);
}
// Benchmark currently uses chdir(), which means we can only
// safely run one at a time.
static std::mutex kBenchmarkLock;
static nsecs_t benchmark(const std::string& path) {
static const char* kWakeLock = "Benchmark";
// Reasonable cards are able to complete the create/run stages
// in under 20 seconds.
constexpr auto kTimeout = 20s;
// RAII class for boosting device performance during benchmarks.
class PerformanceBoost {
private:
int orig_prio;
int orig_ioprio;
IoSchedClass orig_clazz;
public:
PerformanceBoost() {
errno = 0;
int orig_prio = getpriority(PRIO_PROCESS, 0);
orig_prio = getpriority(PRIO_PROCESS, 0);
if (errno != 0) {
PLOG(ERROR) << "Failed to getpriority";
return -1;
PLOG(WARNING) << "Failed to getpriority";
orig_prio = 0;
}
if (setpriority(PRIO_PROCESS, 0, -10) != 0) {
PLOG(ERROR) << "Failed to setpriority";
return -1;
PLOG(WARNING) << "Failed to setpriority";
}
IoSchedClass orig_clazz = IoSchedClass_NONE;
int orig_ioprio = 0;
if (android_get_ioprio(0, &orig_clazz, &orig_ioprio)) {
PLOG(ERROR) << "Failed to android_get_ioprio";
return -1;
PLOG(WARNING) << "Failed to android_get_ioprio";
orig_ioprio = 0;
orig_clazz = IoSchedClass_NONE;
}
if (android_set_ioprio(0, IoSchedClass_RT, 0)) {
PLOG(ERROR) << "Failed to android_set_ioprio";
PLOG(WARNING) << "Failed to android_set_ioprio";
}
}
~PerformanceBoost() {
if (android_set_ioprio(0, orig_clazz, orig_ioprio)) {
PLOG(WARNING) << "Failed to android_set_ioprio";
}
if (setpriority(PRIO_PROCESS, 0, orig_prio) != 0) {
PLOG(WARNING) << "Failed to setpriority";
}
}
};
static status_t benchmarkInternal(const std::string& rootPath,
const android::sp<android::os::IVoldTaskListener>& listener,
android::os::PersistableBundle* extras) {
status_t res = 0;
auto path = rootPath;
path += "/misc";
if (android::vold::PrepareDir(path, 01771, AID_SYSTEM, AID_MISC)) {
return -1;
}
path += "/vold";
if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
path += "/bench";
if (android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
@ -83,70 +117,81 @@ static nsecs_t benchmark(const std::string& path) {
sync();
LOG(INFO) << "Benchmarking " << path;
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
extras->putString(String16("path"), String16(path.c_str()));
extras->putString(String16("ident"), String16(BenchmarkIdent().c_str()));
BenchmarkCreate();
// Always create
{
android::base::Timer timer;
LOG(INFO) << "Creating " << path;
res |= BenchmarkCreate([&](int progress) -> bool {
if (listener) {
listener->onStatus(progress, *extras);
}
return (timer.duration() < kTimeout);
});
sync();
nsecs_t create = systemTime(SYSTEM_TIME_BOOTTIME);
if (res == OK) extras->putLong(String16("create"), timer.duration().count());
}
#if ENABLE_DROP_CACHES
// Only drop when we haven't aborted
if (res == OK) {
android::base::Timer timer;
LOG(VERBOSE) << "Before drop_caches";
if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
PLOG(ERROR) << "Failed to drop_caches";
res = -1;
}
LOG(VERBOSE) << "After drop_caches";
#endif
nsecs_t drop = systemTime(SYSTEM_TIME_BOOTTIME);
BenchmarkRun();
sync();
nsecs_t run = systemTime(SYSTEM_TIME_BOOTTIME);
if (res == OK) extras->putLong(String16("drop"), timer.duration().count());
}
BenchmarkDestroy();
// Only run when we haven't aborted
if (res == OK) {
android::base::Timer timer;
LOG(INFO) << "Running " << path;
res |= BenchmarkRun([&](int progress) -> bool {
if (listener) {
listener->onStatus(progress, *extras);
}
return (timer.duration() < kTimeout);
});
sync();
nsecs_t destroy = systemTime(SYSTEM_TIME_BOOTTIME);
if (res == OK) extras->putLong(String16("run"), timer.duration().count());
}
// Always destroy
{
android::base::Timer timer;
LOG(INFO) << "Destroying " << path;
res |= BenchmarkDestroy();
sync();
if (res == OK) extras->putLong(String16("destroy"), timer.duration().count());
}
if (chdir(orig_cwd) != 0) {
PLOG(ERROR) << "Failed to chdir";
}
if (android_set_ioprio(0, orig_clazz, orig_ioprio)) {
PLOG(ERROR) << "Failed to android_set_ioprio";
}
if (setpriority(PRIO_PROCESS, 0, orig_prio) != 0) {
PLOG(ERROR) << "Failed to setpriority";
return -1;
}
nsecs_t create_d = create - start;
nsecs_t drop_d = drop - create;
nsecs_t run_d = run - drop;
nsecs_t destroy_d = destroy - run;
LOG(INFO) << "create took " << nanoseconds_to_milliseconds(create_d) << "ms";
LOG(INFO) << "drop took " << nanoseconds_to_milliseconds(drop_d) << "ms";
LOG(INFO) << "run took " << nanoseconds_to_milliseconds(run_d) << "ms";
LOG(INFO) << "destroy took " << nanoseconds_to_milliseconds(destroy_d) << "ms";
notifyResult(path, create_d, drop_d, run_d, destroy_d);
return run_d;
return res;
}
nsecs_t BenchmarkPrivate(const std::string& path) {
std::string benchPath(path);
benchPath += "/misc";
if (android::vold::PrepareDir(benchPath, 01771, AID_SYSTEM, AID_MISC)) {
return -1;
void Benchmark(const std::string& path,
const android::sp<android::os::IVoldTaskListener>& listener) {
std::lock_guard<std::mutex> lock(kBenchmarkLock);
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
PerformanceBoost boost;
android::os::PersistableBundle extras;
status_t res = benchmarkInternal(path, listener, &extras);
if (listener) {
listener->onFinished(res, extras);
}
benchPath += "/vold";
if (android::vold::PrepareDir(benchPath, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
benchPath += "/bench";
if (android::vold::PrepareDir(benchPath, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
return benchmark(benchPath);
release_wake_lock(kWakeLock);
}
} // namespace vold

View file

@ -17,16 +17,15 @@
#ifndef ANDROID_VOLD_BENCHMARK_H
#define ANDROID_VOLD_BENCHMARK_H
#include <utils/Errors.h>
#include <utils/Timers.h>
#include "android/os/IVoldTaskListener.h"
#include <string>
namespace android {
namespace vold {
/* Benchmark a private volume mounted at the given path */
nsecs_t BenchmarkPrivate(const std::string& path);
void Benchmark(const std::string& path,
const android::sp<android::os::IVoldTaskListener>& listener);
} // namespace vold
} // namespace android

View file

@ -29,6 +29,7 @@
#include <fcntl.h>
#include <algorithm>
#include <functional>
#include <string>
#include <Utils.h>
@ -36,7 +37,8 @@
namespace android {
namespace vold {
static status_t BenchmarkRun() {
static status_t BenchmarkRun(std::function<bool(int)> checkpoint) {
char* buf = (char*) malloc(1048576);
int t3433f17 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE));
@ -277,6 +279,7 @@ TEMP_FAILURE_RETRY(pread(t3455f18, buf, 4096, 57012224)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f18, buf, 1048576, 0)); // mmap2
close(t3455f18);
t3455f18 = TEMP_FAILURE_RETRY(open("file0", O_RDONLY|O_LARGEFILE));
if (!checkpoint(52)) return -1;
TEMP_FAILURE_RETRY(read(t3455f18, buf, 4));
TEMP_FAILURE_RETRY(lseek(t3455f18, 0, SEEK_SET));
TEMP_FAILURE_RETRY(lseek(t3455f18, 0, SEEK_END));
@ -533,6 +536,7 @@ TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 184320));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 69632));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 81920));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 90112));
if (!checkpoint(55)) return -1;
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 102400));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 114688));
TEMP_FAILURE_RETRY(pread(t3483f25, buf, 4096, 131072));
@ -776,6 +780,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 31, 32760741));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2073, 32759808)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32273035));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 37, 32273065));
if (!checkpoint(58)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 1692, 32272384)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34612102));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 38, 34612132));
@ -1001,6 +1006,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35474138));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 43, 35474168));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 3682, 35471360)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34394223));
if (!checkpoint(61)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 41, 34394253));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 481, 34394112)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 32648704));
@ -1223,6 +1229,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4096, 8724));
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 12820));
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 12824));
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4096, 12828));
if (!checkpoint(64)) return -1;
TEMP_FAILURE_RETRY(pwrite(t3499f40, buf, 4, 16924));
TEMP_FAILURE_RETRY(pread(t3499f40, buf, 8, 17408));
TEMP_FAILURE_RETRY(fdatasync(t3499f40));
@ -1452,6 +1459,7 @@ t3455f50 = TEMP_FAILURE_RETRY(open("file36", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 52, 0));
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 4096, 0)); // mmap2
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 187587, 0)); // mmap2
if (!checkpoint(67)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f50, buf, 4128, 188416)); // mmap2
close(t3455f50);
t3455f50 = TEMP_FAILURE_RETRY(open("file24", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
@ -1696,6 +1704,7 @@ TEMP_FAILURE_RETRY(read(t3532f53, buf, 16384));
close(t3519f43);
close(t3532f53);
int t3492f57 = TEMP_FAILURE_RETRY(open("file54", O_RDONLY|O_LARGEFILE));
if (!checkpoint(70)) return -1;
TEMP_FAILURE_RETRY(read(t3492f57, buf, 39938));
close(t3492f57);
int t3492f61 = TEMP_FAILURE_RETRY(open("file55", O_RDONLY|O_LARGEFILE));
@ -1928,6 +1937,7 @@ TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 516));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 4612));
if (!checkpoint(73)) return -1;
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 4616));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4096, 4620));
TEMP_FAILURE_RETRY(pwrite(t3499f55, buf, 4, 8716));
@ -2159,6 +2169,7 @@ TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 34267550));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 49, 34267580));
close(t3499f73);
TEMP_FAILURE_RETRY(pwrite(t3499f66, buf, 12, 0));
if (!checkpoint(76)) return -1;
close(t3532f68);
TEMP_FAILURE_RETRY(fdatasync(t3499f66));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 722, 34267136)); // mmap2
@ -2396,6 +2407,7 @@ close(t3519f67);
t3519f67 = TEMP_FAILURE_RETRY(open("file123", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f67);
t3519f67 = TEMP_FAILURE_RETRY(open("file124", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
if (!checkpoint(79)) return -1;
close(t3519f67);
t3519f67 = TEMP_FAILURE_RETRY(open("file125", O_RDONLY|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC));
close(t3519f67);
@ -2620,6 +2632,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f90));
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 28, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f90));
close(t3499f90);
if (!checkpoint(82)) return -1;
t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0));
close(t3499f90);
@ -2838,6 +2851,7 @@ TEMP_FAILURE_RETRY(pread(t3505f66, buf, 1, 0));
close(t3505f66);
t3505f66 = TEMP_FAILURE_RETRY(open("file31", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 512, 0));
if (!checkpoint(85)) return -1;
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 512));
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4096, 516));
TEMP_FAILURE_RETRY(pwrite(t3505f66, buf, 4, 4612));
@ -3066,6 +3080,7 @@ TEMP_FAILURE_RETRY(pread(t3505f96, buf, 16, 24));
t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f90, buf, 1, 0));
close(t3499f90);
if (!checkpoint(88)) return -1;
t3499f90 = TEMP_FAILURE_RETRY(open("file18", O_RDWR|O_CREAT|O_LARGEFILE|O_CLOEXEC, 0660));
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 512, 0));
TEMP_FAILURE_RETRY(pwrite(t3499f90, buf, 4, 512));
@ -3278,6 +3293,7 @@ TEMP_FAILURE_RETRY(fdatasync(t3499f100));
close(t3499f100);
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 30, 35636928));
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 60, 35636958));
if (!checkpoint(91)) return -1;
TEMP_FAILURE_RETRY(pread(t3455f17, buf, 2062, 35635200)); // mmap2
t3499f84 = TEMP_FAILURE_RETRY(open("file18", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(pread(t3499f84, buf, 1, 0));
@ -3514,6 +3530,7 @@ TEMP_FAILURE_RETRY(pread(t3499f26, buf, 8, 13312));
TEMP_FAILURE_RETRY(fdatasync(t3499f26));
t3499f97 = TEMP_FAILURE_RETRY(open("file22", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
TEMP_FAILURE_RETRY(fdatasync(t3499f97));
if (!checkpoint(93)) return -1;
close(t3499f97);
TEMP_FAILURE_RETRY(pwrite(t3499f26, buf, 12, 0));
TEMP_FAILURE_RETRY(fdatasync(t3499f26));
@ -3760,6 +3777,7 @@ close(t3533f90);
t3526f90 = TEMP_FAILURE_RETRY(open("file162", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
if (!checkpoint(96)) return -1;
close(t3526f90);
t3526f90 = TEMP_FAILURE_RETRY(open("file163", O_RDONLY|O_LARGEFILE));
TEMP_FAILURE_RETRY(read(t3526f90, buf, 16384));
@ -3994,6 +4012,7 @@ TEMP_FAILURE_RETRY(pread(t3597f110, buf, 1, 0));
close(t3597f110);
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 16, 24));
close(t3540f109);
if (!checkpoint(99)) return -1;
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 16384));
TEMP_FAILURE_RETRY(pread(t3597f108, buf, 4096, 12288));
t3597f109 = TEMP_FAILURE_RETRY(open("file178", O_RDONLY|O_LARGEFILE|O_CLOEXEC));
@ -4054,7 +4073,7 @@ static status_t CreateFile(const char* name, int len) {
return OK;
}
static status_t BenchmarkCreate() {
static status_t BenchmarkCreate(std::function<bool(int)> checkpoint) {
status_t res = 0;
res |= CreateFile("stub", 0);
@ -4069,6 +4088,7 @@ res |= CreateFile("file175", 9);
res |= CreateFile("file76", 0);
res |= CreateFile("file140", 4042);
res |= CreateFile("file80", 0);
if (!checkpoint(3)) return -1;
res |= CreateFile("file139", 49152);
res |= CreateFile("file50", 32768);
res |= CreateFile("file179", 4000);
@ -4081,6 +4101,7 @@ res |= CreateFile("file53", 32768);
res |= CreateFile("file72", 0);
res |= CreateFile("file55", 16384);
res |= CreateFile("file54", 39938);
if (!checkpoint(6)) return -1;
res |= CreateFile("file129", 3974);
res |= CreateFile("file107", 0);
res |= CreateFile("file95", 0);
@ -4093,6 +4114,7 @@ res |= CreateFile("file89", 0);
res |= CreateFile("file40", 4172);
res |= CreateFile("file20", 1);
res |= CreateFile("file151", 499712);
if (!checkpoint(10)) return -1;
res |= CreateFile("file106", 0);
res |= CreateFile("file159", 9);
res |= CreateFile("file47", 32768);
@ -4105,6 +4127,7 @@ res |= CreateFile("file172", 9);
res |= CreateFile("file148", 3461);
res |= CreateFile("file7", 794976);
res |= CreateFile("file68", 32768);
if (!checkpoint(13)) return -1;
res |= CreateFile("file109", 0);
res |= CreateFile("file142", 5057);
res |= CreateFile("file147", 3834);
@ -4117,6 +4140,7 @@ res |= CreateFile("file105", 0);
res |= CreateFile("file79", 0);
res |= CreateFile("file65", 32768);
res |= CreateFile("file135", 21257);
if (!checkpoint(16)) return -1;
res |= CreateFile("file124", 0);
res |= CreateFile("file87", 0);
res |= CreateFile("file64", 49152);
@ -4129,6 +4153,7 @@ res |= CreateFile("file178", 1);
res |= CreateFile("file163", 32768);
res |= CreateFile("file67", 32768);
res |= CreateFile("file155", 21512);
if (!checkpoint(20)) return -1;
res |= CreateFile("file156", 9);
res |= CreateFile("file23", 28700);
res |= CreateFile("file61", 32768);
@ -4141,6 +4166,7 @@ res |= CreateFile("file24", 94220);
res |= CreateFile("file57", 32768);
res |= CreateFile("file104", 0);
res |= CreateFile("file113", 0);
if (!checkpoint(23)) return -1;
res |= CreateFile("file99", 0);
res |= CreateFile("file120", 0);
res |= CreateFile("file154", 73728);
@ -4153,6 +4179,7 @@ res |= CreateFile("file96", 0);
res |= CreateFile("file91", 0);
res |= CreateFile("file158", 1);
res |= CreateFile("file174", 1);
if (!checkpoint(26)) return -1;
res |= CreateFile("file48", 32768);
res |= CreateFile("file33", 32566);
res |= CreateFile("file83", 0);
@ -4165,6 +4192,7 @@ res |= CreateFile("file16", 31392);
res |= CreateFile("file164", 32768);
res |= CreateFile("file36", 192544);
res |= CreateFile("file6", 4636);
if (!checkpoint(30)) return -1;
res |= CreateFile("file10", 16484);
res |= CreateFile("file150", 10056);
res |= CreateFile("file62", 32768);
@ -4177,6 +4205,7 @@ res |= CreateFile("file100", 0);
res |= CreateFile("file103", 0);
res |= CreateFile("file26", 28676);
res |= CreateFile("file46", 32768);
if (!checkpoint(33)) return -1;
res |= CreateFile("file60", 32768);
res |= CreateFile("file162", 32768);
res |= CreateFile("file25", 32872);
@ -4189,6 +4218,7 @@ res |= CreateFile("file51", 32768);
res |= CreateFile("file37", 159752);
res |= CreateFile("file73", 0);
res |= CreateFile("file71", 32768);
if (!checkpoint(36)) return -1;
res |= CreateFile("file98", 0);
res |= CreateFile("file74", 0);
res |= CreateFile("file93", 0);
@ -4201,6 +4231,7 @@ res |= CreateFile("file136", 4199);
res |= CreateFile("file132", 23233);
res |= CreateFile("file92", 0);
res |= CreateFile("file11", 0);
if (!checkpoint(40)) return -1;
res |= CreateFile("file86", 0);
res |= CreateFile("file22", 0);
res |= CreateFile("file56", 16384);
@ -4213,6 +4244,7 @@ res |= CreateFile("file63", 49152);
res |= CreateFile("file116", 0);
res |= CreateFile("file29", 1035);
res |= CreateFile("file35", 118788);
if (!checkpoint(43)) return -1;
res |= CreateFile("file170", 24576);
res |= CreateFile("file30", 98304);
res |= CreateFile("file14", 0);
@ -4225,6 +4257,7 @@ res |= CreateFile("file18", 17416);
res |= CreateFile("file134", 15056);
res |= CreateFile("file31", 25608);
res |= CreateFile("file97", 0);
if (!checkpoint(46)) return -1;
res |= CreateFile("file84", 0);
res |= CreateFile("file114", 0);
res |= CreateFile("file88", 0);
@ -4237,6 +4270,7 @@ res |= CreateFile("file133", 13332);
res |= CreateFile("file169", 11354);
res |= CreateFile("file166", 0);
res |= CreateFile("file49", 32768);
if (!checkpoint(50)) return -1;
res |= CreateFile("file177", 61440);
return res;

149
CheckEncryption.cpp Normal file
View file

@ -0,0 +1,149 @@
/*
* 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 "CheckEncryption.h"
#include "FileDeviceUtils.h"
#include "Utils.h"
#include "VolumeManager.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <cutils/iosched_policy.h>
#include <private/android_filesystem_config.h>
#include <sstream>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
using android::base::unique_fd;
using android::base::ReadFileToString;
using android::base::WriteStringToFile;
namespace android {
namespace vold {
constexpr uint32_t max_extents = 32;
constexpr size_t bytecount = 8;
constexpr int repeats = 256;
bool check_file(const std::string& needle) {
LOG(DEBUG) << "checkEncryption check_file: " << needle;
auto haystack = android::vold::BlockDeviceForPath(needle);
if (haystack.empty()) {
LOG(ERROR) << "Failed to find device for path: " << needle;
return false;
}
std::string randombytes;
if (ReadRandomBytes(bytecount, randombytes) != 0) {
LOG(ERROR) << "Failed to read random bytes";
return false;
}
std::string randomhex;
StrToHex(randombytes, randomhex);
std::ostringstream os;
for (int i = 0; i < repeats; i++) os << randomhex;
auto towrite = os.str();
if (access(needle.c_str(), F_OK) == 0) {
if (unlink(needle.c_str()) != 0) {
PLOG(ERROR) << "Failed to unlink " << needle;
return false;
}
}
LOG(DEBUG) << "Writing to " << needle;
if (!WriteStringToFile(towrite, needle)) {
PLOG(ERROR) << "Failed to write " << needle;
return false;
}
sync();
unique_fd haystack_fd(open(haystack.c_str(), O_RDONLY | O_CLOEXEC));
if (haystack_fd.get() == -1) {
PLOG(ERROR) << "Failed to open " << haystack;
return false;
}
auto fiemap = PathFiemap(needle, max_extents);
std::string area;
for (uint32_t i = 0; i < fiemap->fm_mapped_extents; i++) {
auto xt = &(fiemap->fm_extents[i]);
LOG(DEBUG) << "Extent " << i << " at " << xt->fe_physical << " length " << xt->fe_length;
if (lseek64(haystack_fd.get(), xt->fe_physical, SEEK_SET) == -1) {
PLOG(ERROR) << "Failed lseek";
return false;
}
auto toread = xt->fe_length;
while (toread > 0) {
char buf[BUFSIZ];
size_t wlen =
static_cast<size_t>(std::min(static_cast<typeof(toread)>(sizeof(buf)), toread));
auto l = read(haystack_fd.get(), buf, wlen);
if (l < 1) {
PLOG(ERROR) << "Failed read";
if (errno != EINTR) {
return false;
}
}
area.append(buf, l);
toread -= l;
}
}
LOG(DEBUG) << "Searching " << area.size() << " bytes of " << needle;
LOG(DEBUG) << "First position of blob: " << area.find(randomhex);
return true;
}
int CheckEncryption(const std::string& path) {
auto deNeedle(path);
deNeedle += "/misc";
if (android::vold::PrepareDir(deNeedle, 01771, AID_SYSTEM, AID_MISC)) {
return -1;
}
deNeedle += "/vold";
if (android::vold::PrepareDir(deNeedle, 0700, AID_ROOT, AID_ROOT)) {
return -1;
}
deNeedle += "/checkEncryption";
auto neNeedle(path);
neNeedle += "/unencrypted/checkEncryption";
check_file(deNeedle);
check_file(neNeedle);
return 0;
}
} // namespace vold
} // namespace android

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* 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.
@ -14,15 +14,18 @@
* limitations under the License.
*/
#ifndef _VOLD_COMMAND_H
#define _VOLD_COMMAND_H
#ifndef ANDROID_VOLD_CHECK_ENCRYPTION_H
#define ANDROID_VOLD_CHECK_ENCRYPTION_H
#include <sysutils/FrameworkCommand.h>
#include <string>
class VoldCommand : public FrameworkCommand {
public:
explicit VoldCommand(const char *cmd);
virtual ~VoldCommand() {}
};
namespace android {
namespace vold {
/* Check encryption of private volume mounted at the given path */
int CheckEncryption(const std::string& path);
} // namespace vold
} // namespace android
#endif

View file

@ -1,877 +0,0 @@
/*
* Copyright (C) 2008 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 <stdlib.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fs_mgr.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <ctype.h>
#define LOG_TAG "VoldCmdListener"
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <sysutils/SocketClient.h>
#include <private/android_filesystem_config.h>
#include "CommandListener.h"
#include "VolumeManager.h"
#include "VolumeBase.h"
#include "ResponseCode.h"
#include "Process.h"
#include "Loop.h"
#include "Devmapper.h"
#include "MoveTask.h"
#include "TrimTask.h"
#define DUMP_ARGS 0
#define DEBUG_APPFUSE 0
using android::base::unique_fd;
CommandListener::CommandListener() :
FrameworkListener("vold", true) {
registerCmd(new DumpCmd());
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ObbCmd());
registerCmd(new StorageCmd());
registerCmd(new FstrimCmd());
registerCmd(new AppFuseCmd());
}
#if DUMP_ARGS
void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
char buffer[4096];
char *p = buffer;
memset(buffer, 0, sizeof(buffer));
int i;
for (i = 0; i < argc; i++) {
unsigned int len = strlen(argv[i]) + 1; // Account for space
if (i == argObscure) {
len += 2; // Account for {}
}
if (((p - buffer) + len) < (sizeof(buffer)-1)) {
if (i == argObscure) {
*p++ = '{';
*p++ = '}';
*p++ = ' ';
continue;
}
strcpy(p, argv[i]);
p+= strlen(argv[i]);
if (i != (argc -1)) {
*p++ = ' ';
}
}
}
SLOGD("%s", buffer);
}
#else
void CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
#endif
int CommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
if (!cond) {
return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
} else {
return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
}
}
CommandListener::DumpCmd::DumpCmd() :
VoldCommand("dump") {
}
int CommandListener::DumpCmd::runCommand(SocketClient *cli,
int /*argc*/, char ** /*argv*/) {
cli->sendMsg(0, "Dumping loop status", false);
if (Loop::dumpState(cli)) {
cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
}
cli->sendMsg(0, "Dumping DM status", false);
if (Devmapper::dumpState(cli)) {
cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
}
cli->sendMsg(0, "Dumping mounted filesystems", false);
FILE *fp = fopen("/proc/mounts", "re");
if (fp) {
char line[1024];
while (fgets(line, sizeof(line), fp)) {
line[strlen(line)-1] = '\0';
cli->sendMsg(0, line, false);;
}
fclose(fp);
}
cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
return 0;
}
CommandListener::VolumeCmd::VolumeCmd() :
VoldCommand("volume") {
}
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
dumpArgs(argc, argv, -1);
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<std::mutex> lock(vm->getLock());
// TODO: tease out methods not directly related to volumes
std::string cmd(argv[1]);
if (cmd == "reset") {
return sendGenericOkFail(cli, vm->reset());
} else if (cmd == "shutdown") {
return sendGenericOkFail(cli, vm->shutdown());
} else if (cmd == "debug") {
return sendGenericOkFail(cli, vm->setDebug(true));
} else if (cmd == "partition" && argc > 3) {
// partition [diskId] [public|private|mixed] [ratio]
std::string id(argv[2]);
auto disk = vm->findDisk(id);
if (disk == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown disk", false);
}
std::string type(argv[3]);
if (type == "public") {
return sendGenericOkFail(cli, disk->partitionPublic());
} else if (type == "private") {
return sendGenericOkFail(cli, disk->partitionPrivate());
} else if (type == "mixed") {
if (argc < 4) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
int frac = atoi(argv[4]);
return sendGenericOkFail(cli, disk->partitionMixed(frac));
} else {
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
} else if (cmd == "mkdirs" && argc > 2) {
// mkdirs [path]
return sendGenericOkFail(cli, vm->mkdirs(argv[2]));
} else if (cmd == "user_added" && argc > 3) {
// user_added [user] [serial]
return sendGenericOkFail(cli, vm->onUserAdded(atoi(argv[2]), atoi(argv[3])));
} else if (cmd == "user_removed" && argc > 2) {
// user_removed [user]
return sendGenericOkFail(cli, vm->onUserRemoved(atoi(argv[2])));
} else if (cmd == "user_started" && argc > 2) {
// user_started [user]
return sendGenericOkFail(cli, vm->onUserStarted(atoi(argv[2])));
} else if (cmd == "user_stopped" && argc > 2) {
// user_stopped [user]
return sendGenericOkFail(cli, vm->onUserStopped(atoi(argv[2])));
} else if (cmd == "mount" && argc > 2) {
// mount [volId] [flags] [user]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
vol->setMountFlags(mountFlags);
vol->setMountUserId(mountUserId);
int res = vol->mount();
if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
vm->setPrimary(vol);
}
return sendGenericOkFail(cli, res);
} else if (cmd == "unmount" && argc > 2) {
// unmount [volId]
std::string id(argv[2]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->unmount());
} else if (cmd == "format" && argc > 3) {
// format [volId] [fsType|auto]
std::string id(argv[2]);
std::string fsType(argv[3]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
return sendGenericOkFail(cli, vol->format(fsType));
} else if (cmd == "move_storage" && argc > 3) {
// move_storage [fromVolId] [toVolId]
auto fromVol = vm->findVolume(std::string(argv[2]));
auto toVol = vm->findVolume(std::string(argv[3]));
if (fromVol == nullptr || toVol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
(new android::vold::MoveTask(fromVol, toVol))->start();
return sendGenericOkFail(cli, 0);
} else if (cmd == "benchmark" && argc > 2) {
// benchmark [volId]
std::string id(argv[2]);
nsecs_t res = vm->benchmarkPrivate(id);
return cli->sendMsg(ResponseCode::CommandOkay,
android::base::StringPrintf("%" PRId64, res).c_str(), false);
} else if (cmd == "forget_partition" && argc > 2) {
// forget_partition [partGuid]
std::string partGuid(argv[2]);
return sendGenericOkFail(cli, vm->forgetPartition(partGuid));
} else if (cmd == "remount_uid" && argc > 3) {
// remount_uid [uid] [none|default|read|write]
uid_t uid = atoi(argv[2]);
std::string mode(argv[3]);
return sendGenericOkFail(cli, vm->remountUid(uid, mode));
}
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
}
CommandListener::StorageCmd::StorageCmd() :
VoldCommand("storage") {
}
int CommandListener::StorageCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
/* Guarantied to be initialized by vold's main() before the CommandListener is active */
extern struct fstab *fstab;
dumpArgs(argc, argv, -1);
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
if (!strcmp(argv[1], "mountall")) {
if (argc != 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false);
return 0;
}
fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false);
return 0;
}
if (!strcmp(argv[1], "users")) {
DIR *dir;
struct dirent *de;
if (argc < 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);
return 0;
}
if (!(dir = opendir("/proc"))) {
cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
return 0;
}
while ((de = readdir(dir))) {
int pid = Process::getPid(de->d_name);
if (pid < 0) {
continue;
}
std::string processName;
Process::getProcessName(pid, processName);
if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
Process::checkFileMaps(pid, argv[2]) ||
Process::checkSymLink(pid, argv[2], "cwd") ||
Process::checkSymLink(pid, argv[2], "root") ||
Process::checkSymLink(pid, argv[2], "exe")) {
char msg[1024];
snprintf(msg, sizeof(msg), "%d %s", pid, processName.c_str());
cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
}
}
closedir(dir);
cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
}
return 0;
}
CommandListener::AsecCmd::AsecCmd() :
VoldCommand("asec") {
}
void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
DIR *d = opendir(directory);
if (!d) {
cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
return;
}
dirent* dent;
while ((dent = readdir(d)) != NULL) {
if (dent->d_name[0] == '.')
continue;
if (dent->d_type != DT_REG)
continue;
size_t name_len = strlen(dent->d_name);
if (name_len > 5 && name_len < 260 &&
!strcmp(&dent->d_name[name_len - 5], ".asec")) {
char id[255];
memset(id, 0, sizeof(id));
strlcpy(id, dent->d_name, name_len - 4);
cli->sendMsg(ResponseCode::AsecListResult, id, false);
}
}
closedir(d);
}
int CommandListener::AsecCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
int rc = 0;
if (!strcmp(argv[1], "list")) {
dumpArgs(argc, argv, -1);
listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_EXT);
listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_INT);
} else if (!strcmp(argv[1], "create")) {
dumpArgs(argc, argv, 5);
if (argc != 8) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
"<isExternal>", false);
return 0;
}
unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
const bool isExternal = (atoi(argv[7]) == 1);
rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
} else if (!strcmp(argv[1], "resize")) {
dumpArgs(argc, argv, -1);
if (argc != 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec resize <container-id> <size_mb> <key>", false);
return 0;
}
unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
rc = vm->resizeAsec(argv[2], numSectors, argv[4]);
} else if (!strcmp(argv[1], "finalize")) {
dumpArgs(argc, argv, -1);
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
return 0;
}
rc = vm->finalizeAsec(argv[2]);
} else if (!strcmp(argv[1], "fixperms")) {
dumpArgs(argc, argv, -1);
if (argc != 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
return 0;
}
char *endptr;
gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
if (*endptr != '\0') {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
return 0;
}
rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
} else if (!strcmp(argv[1], "destroy")) {
dumpArgs(argc, argv, -1);
if (argc < 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
return 0;
}
bool force = false;
if (argc > 3 && !strcmp(argv[3], "force")) {
force = true;
}
rc = vm->destroyAsec(argv[2], force);
} else if (!strcmp(argv[1], "mount")) {
dumpArgs(argc, argv, 3);
if (argc != 6) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: asec mount <namespace-id> <key> <ownerUid> <ro|rw>", false);
return 0;
}
bool readOnly = true;
if (!strcmp(argv[5], "rw")) {
readOnly = false;
}
rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]), readOnly);
} else if (!strcmp(argv[1], "unmount")) {
dumpArgs(argc, argv, -1);
if (argc < 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
return 0;
}
bool force = false;
if (argc > 3 && !strcmp(argv[3], "force")) {
force = true;
}
rc = vm->unmountAsec(argv[2], force);
} else if (!strcmp(argv[1], "rename")) {
dumpArgs(argc, argv, -1);
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: asec rename <old_id> <new_id>", false);
return 0;
}
rc = vm->renameAsec(argv[2], argv[3]);
} else if (!strcmp(argv[1], "path")) {
dumpArgs(argc, argv, -1);
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
return 0;
}
char path[255];
if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
cli->sendMsg(ResponseCode::AsecPathResult, path, false);
return 0;
}
} else if (!strcmp(argv[1], "fspath")) {
dumpArgs(argc, argv, -1);
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false);
return 0;
}
char path[255];
if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) {
cli->sendMsg(ResponseCode::AsecPathResult, path, false);
return 0;
}
} else {
dumpArgs(argc, argv, -1);
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
}
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
} else {
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "asec operation failed", true);
}
return 0;
}
CommandListener::ObbCmd::ObbCmd() :
VoldCommand("obb") {
}
int CommandListener::ObbCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
int rc = 0;
if (!strcmp(argv[1], "list")) {
dumpArgs(argc, argv, -1);
rc = vm->listMountedObbs(cli);
} else if (!strcmp(argv[1], "mount")) {
dumpArgs(argc, argv, 3);
if (argc != 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage: obb mount <filename> <key> <ownerGid>", false);
return 0;
}
rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
} else if (!strcmp(argv[1], "unmount")) {
dumpArgs(argc, argv, -1);
if (argc < 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
return 0;
}
bool force = false;
if (argc > 3 && !strcmp(argv[3], "force")) {
force = true;
}
rc = vm->unmountObb(argv[2], force);
} else if (!strcmp(argv[1], "path")) {
dumpArgs(argc, argv, -1);
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
return 0;
}
char path[255];
if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
cli->sendMsg(ResponseCode::AsecPathResult, path, false);
return 0;
}
} else {
dumpArgs(argc, argv, -1);
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
}
if (!rc) {
cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
} else {
rc = ResponseCode::convertFromErrno();
cli->sendMsg(rc, "obb operation failed", true);
}
return 0;
}
CommandListener::FstrimCmd::FstrimCmd() :
VoldCommand("fstrim") {
}
int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
return 0;
}
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
return 0;
}
VolumeManager *vm = VolumeManager::Instance();
std::lock_guard<std::mutex> lock(vm->getLock());
int flags = 0;
std::string cmd(argv[1]);
if (cmd == "dotrim") {
flags = 0;
} else if (cmd == "dotrimbench") {
flags = android::vold::TrimTask::Flags::kBenchmarkAfter;
} else if (cmd == "dodtrim") {
flags = android::vold::TrimTask::Flags::kDeepTrim;
} else if (cmd == "dodtrimbench") {
flags = android::vold::TrimTask::Flags::kDeepTrim
| android::vold::TrimTask::Flags::kBenchmarkAfter;
}
(new android::vold::TrimTask(flags))->start();
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") {}
int CommandListener::AppFuseCmd::runCommand(SocketClient *cli, int argc, char **argv) {
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
return 0;
}
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]);
// Check mount point name.
std::string path;
if (getMountPath(uid, name, &path) != android::OK) {
return cli->sendMsg(ResponseCode::CommandParameterError,
"Invalid mount point name.",
false);
}
// 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]);
// 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 */);
return sendGenericOkFail(cli, result);
}
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown appfuse cmd", false);
}
android::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) {
struct iovec data;
char dataBuffer[128];
char controlBuffer[CMSG_SPACE(sizeof(int))];
struct msghdr message;
// Message.
memset(&message, 0, sizeof(struct msghdr));
message.msg_iov = &data;
message.msg_iovlen = 1;
message.msg_control = controlBuffer;
message.msg_controllen = CMSG_SPACE(sizeof(int));
// Data.
data.iov_base = dataBuffer;
data.iov_len = snprintf(dataBuffer,
sizeof(dataBuffer),
"200 %d AppFuse command succeeded",
cli->getCmdNum()) + 1;
// Control.
struct cmsghdr* const controlMessage = CMSG_FIRSTHDR(&message);
memset(controlBuffer, 0, CMSG_SPACE(sizeof(int)));
controlMessage->cmsg_level = SOL_SOCKET;
controlMessage->cmsg_type = SCM_RIGHTS;
controlMessage->cmsg_len = CMSG_LEN(sizeof(int));
*((int *) CMSG_DATA(controlMessage)) = fd;
const int result = TEMP_FAILURE_RETRY(sendmsg(cli->getSocket(), &message, 0));
if (result == -1) {
PLOG(ERROR) << "Failed to send FD from vold";
return -errno;
}
return android::OK;
}

View file

@ -1,87 +0,0 @@
/*
* Copyright (C) 2008 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 _COMMANDLISTENER_H__
#define _COMMANDLISTENER_H__
#include <sysutils/FrameworkListener.h>
#include <utils/Errors.h>
#include "VoldCommand.h"
class CommandListener : public FrameworkListener {
public:
CommandListener();
virtual ~CommandListener() {}
private:
static void dumpArgs(int argc, char **argv, int argObscure);
static int sendGenericOkFail(SocketClient *cli, int cond);
class DumpCmd : public VoldCommand {
public:
DumpCmd();
virtual ~DumpCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
};
class VolumeCmd : public VoldCommand {
public:
VolumeCmd();
virtual ~VolumeCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
};
class AsecCmd : public VoldCommand {
public:
AsecCmd();
virtual ~AsecCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
private:
void listAsecsInDirectory(SocketClient *c, const char *directory);
};
class ObbCmd : public VoldCommand {
public:
ObbCmd();
virtual ~ObbCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
};
class StorageCmd : public VoldCommand {
public:
StorageCmd();
virtual ~StorageCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
};
class FstrimCmd : public VoldCommand {
public:
FstrimCmd();
virtual ~FstrimCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
};
class AppFuseCmd : public VoldCommand {
public:
AppFuseCmd();
virtual ~AppFuseCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
private:
android::status_t sendFd(SocketClient *c, int fd);
};
};
#endif

View file

@ -1,448 +0,0 @@
/*
* Copyright (C) 2015 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 <assert.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fs_mgr.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
#include <algorithm>
#include <thread>
#define LOG_TAG "VoldCryptCmdListener"
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <cutils/log.h>
#include <cutils/sockets.h>
#include <sysutils/SocketClient.h>
#include <private/android_filesystem_config.h>
#include "CryptCommandListener.h"
#include "Process.h"
#include "ResponseCode.h"
#include "cryptfs.h"
#include "Ext4Crypt.h"
#include "MetadataCrypt.h"
#include "Utils.h"
#define DUMP_ARGS 0
CryptCommandListener::CryptCommandListener() :
FrameworkListener("cryptd", true) {
registerCmd(new CryptfsCmd());
}
#if DUMP_ARGS
void CryptCommandListener::dumpArgs(int argc, char **argv, int argObscure) {
char buffer[4096];
char *p = buffer;
memset(buffer, 0, sizeof(buffer));
int i;
for (i = 0; i < argc; i++) {
unsigned int len = strlen(argv[i]) + 1; // Account for space
if (i == argObscure) {
len += 2; // Account for {}
}
if (((p - buffer) + len) < (sizeof(buffer)-1)) {
if (i == argObscure) {
*p++ = '{';
*p++ = '}';
*p++ = ' ';
continue;
}
strcpy(p, argv[i]);
p+= strlen(argv[i]);
if (i != (argc -1)) {
*p++ = ' ';
}
}
}
SLOGD("%s", buffer);
}
#else
void CryptCommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
#endif
int CryptCommandListener::sendGenericOkFailOnBool(SocketClient *cli, bool success) {
if (success) {
return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
} else {
return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
}
}
CryptCommandListener::CryptfsCmd::CryptfsCmd() :
VoldCommand("cryptfs") {
}
static int getType(const char* type)
{
if (!strcmp(type, "default")) {
return CRYPT_TYPE_DEFAULT;
} else if (!strcmp(type, "password")) {
return CRYPT_TYPE_PASSWORD;
} else if (!strcmp(type, "pin")) {
return CRYPT_TYPE_PIN;
} else if (!strcmp(type, "pattern")) {
return CRYPT_TYPE_PATTERN;
} else {
return -1;
}
}
static char* parseNull(char* arg) {
if (strcmp(arg, "!") == 0) {
return nullptr;
} else {
return arg;
}
}
static bool check_argc(SocketClient *cli, const std::string &subcommand, int argc,
int expected, std::string usage) {
assert(expected >= 2);
if (expected == 2) {
assert(usage.empty());
} else {
assert(!usage.empty());
assert(std::count(usage.begin(), usage.end(), ' ') + 3 == expected);
}
if (argc == expected) {
return true;
}
auto message = std::string() + "Usage: cryptfs " + subcommand;
if (!usage.empty()) {
message += " " + usage;
}
cli->sendMsg(ResponseCode::CommandSyntaxError, message.c_str(), false);
return false;
}
static int do_enablecrypto(char* arg2, char* arg4, int type, bool no_ui) {
int rc;
int tries;
for (tries = 0; tries < 2; ++tries) {
if (type == CRYPT_TYPE_DEFAULT) {
rc = cryptfs_enable_default(arg2, no_ui);
} else {
rc = cryptfs_enable(arg2, type, arg4, no_ui);
}
if (rc == 0) {
free(arg2);
free(arg4);
return 0;
} else if (tries == 0) {
Process::killProcessesWithOpenFiles(DATA_MNT_POINT, SIGKILL);
}
}
free(arg2);
free(arg4);
return -1;
}
int CryptCommandListener::CryptfsCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
return 0;
}
if (argc < 2) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing subcommand", false);
return 0;
}
int rc = 0;
std::string subcommand(argv[1]);
if (subcommand == "checkpw") {
if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
dumpArgs(argc, argv, 2);
rc = cryptfs_check_passwd(argv[2]);
} else if (subcommand == "restart") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
dumpArgs(argc, argv, -1);
// 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();
} else if (subcommand == "cryptocomplete") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
dumpArgs(argc, argv, -1);
rc = cryptfs_crypto_complete();
} else if (subcommand == "enablecrypto") {
if (e4crypt_is_native()) {
if (argc != 5 || strcmp(argv[2], "inplace") || strcmp(argv[3], "default")
|| strcmp(argv[4], "noui")) {
cli->sendMsg(ResponseCode::CommandSyntaxError,
"Usage with ext4crypt: cryptfs enablecrypto inplace default noui", false);
return 0;
}
return sendGenericOkFailOnBool(cli, e4crypt_enable_crypto());
}
const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
"default|password|pin|pattern [passwd] [noui]";
// This should be replaced with a command line parser if more options
// are added
bool valid = true;
bool no_ui = false;
int type = CRYPT_TYPE_DEFAULT;
int options = 4; // Optional parameters are at this offset
if (argc < 4) {
// Minimum 4 parameters
valid = false;
} else if (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace") ) {
// Second parameter must be wipe or inplace
valid = false;
} else {
// Third parameter must be valid type
type = getType(argv[3]);
if (type == -1) {
valid = false;
} else if (type != CRYPT_TYPE_DEFAULT) {
options++;
}
}
if (valid) {
if(argc < options) {
// Too few parameters
valid = false;
} else if (argc == options) {
// No more, done
} else if (argc == options + 1) {
// One option, must be noui
if (!strcmp(argv[options], "noui")) {
no_ui = true;
} else {
valid = false;
}
} else {
// Too many options
valid = false;
}
}
if (!valid) {
cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
return 0;
}
dumpArgs(argc, argv, 4);
// Spawn as thread so init can issue commands back to vold without
// causing deadlock, usually as a result of prep_data_fs.
char* arg2 = argc > 2 ? strdup(argv[2]) : NULL;
char* arg4 = argc > 4 ? strdup(argv[4]) : NULL;
std::thread(&do_enablecrypto, arg2, arg4, type, no_ui).detach();
} else if (subcommand == "enablefilecrypto") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
dumpArgs(argc, argv, -1);
rc = e4crypt_initialize_global_de();
} else if (subcommand == "changepw") {
const char* syntax = "Usage: cryptfs changepw "
"default|password|pin|pattern [newpasswd]";
const char* password;
if (argc == 3) {
password = "";
} else if (argc == 4) {
password = argv[3];
} else {
cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
return 0;
}
int type = getType(argv[2]);
if (type == -1) {
cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
return 0;
}
SLOGD("cryptfs changepw %s {}", argv[2]);
rc = cryptfs_changepw(type, password);
} else if (subcommand == "verifypw") {
if (!check_argc(cli, subcommand, argc, 3, "<passwd>")) return 0;
SLOGD("cryptfs verifypw {}");
rc = cryptfs_verify_passwd(argv[2]);
} else if (subcommand == "getfield") {
if (!check_argc(cli, subcommand, argc, 3, "<fieldname>")) return 0;
char *valbuf;
int valbuf_len = PROPERTY_VALUE_MAX;
dumpArgs(argc, argv, -1);
// Increase the buffer size until it is big enough for the field value stored.
while (1) {
valbuf = (char*)malloc(valbuf_len);
if (valbuf == NULL) {
cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
return 0;
}
rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
break;
}
free(valbuf);
valbuf_len *= 2;
}
if (rc == CRYPTO_GETFIELD_OK) {
cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
}
free(valbuf);
} else if (subcommand == "setfield") {
if (!check_argc(cli, subcommand, argc, 4, "<fieldname> <value>")) return 0;
dumpArgs(argc, argv, -1);
rc = cryptfs_setfield(argv[2], argv[3]);
} else if (subcommand == "mountdefaultencrypted") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
SLOGD("cryptfs mountdefaultencrypted");
dumpArgs(argc, argv, -1);
if (e4crypt_is_native()) {
return sendGenericOkFailOnBool(cli, e4crypt_mount_metadata_encrypted());
}
// 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();
} else if (subcommand == "getpwtype") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
SLOGD("cryptfs getpwtype");
dumpArgs(argc, argv, -1);
switch(cryptfs_get_password_type()) {
case CRYPT_TYPE_PASSWORD:
cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
return 0;
case CRYPT_TYPE_PATTERN:
cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
return 0;
case CRYPT_TYPE_PIN:
cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
return 0;
case CRYPT_TYPE_DEFAULT:
cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
return 0;
default:
/** @TODO better error and make sure handled by callers */
cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
return 0;
}
} else if (subcommand == "getpw") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
SLOGD("cryptfs getpw");
dumpArgs(argc, argv, -1);
const char* password = cryptfs_get_password();
if (password) {
char* message = 0;
int size = asprintf(&message, "{{sensitive}} %s", password);
if (size != -1) {
cli->sendMsg(ResponseCode::CommandOkay, message, false);
memset(message, 0, size);
free (message);
return 0;
}
}
rc = -1;
} else if (subcommand == "clearpw") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
SLOGD("cryptfs clearpw");
dumpArgs(argc, argv, -1);
cryptfs_clear_password();
rc = 0;
} else if (subcommand == "isConvertibleToFBE") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
// ext4enc:TODO: send a CommandSyntaxError if argv[2] not an integer
SLOGD("cryptfs isConvertibleToFBE");
dumpArgs(argc, argv, -1);
rc = cryptfs_isConvertibleToFBE();
} else if (subcommand == "init_user0") {
if (!check_argc(cli, subcommand, argc, 2, "")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_init_user0());
} else if (subcommand == "create_user_key") {
if (!check_argc(cli, subcommand, argc, 5, "<user> <serial> <ephemeral>")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_vold_create_user_key(
atoi(argv[2]), atoi(argv[3]), atoi(argv[4]) != 0));
} else if (subcommand == "destroy_user_key") {
if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_destroy_user_key(atoi(argv[2])));
} else if (subcommand == "add_user_key_auth") {
if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_add_user_key_auth(
atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
} else if (subcommand == "fixate_newest_user_key_auth") {
if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_fixate_newest_user_key_auth(atoi(argv[2])));
} else if (subcommand == "unlock_user_key") {
if (!check_argc(cli, subcommand, argc, 6, "<user> <serial> <token> <secret>")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_unlock_user_key(
atoi(argv[2]), atoi(argv[3]), argv[4], argv[5]));
} else if (subcommand == "lock_user_key") {
if (!check_argc(cli, subcommand, argc, 3, "<user>")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_lock_user_key(atoi(argv[2])));
} else if (subcommand == "prepare_user_storage") {
if (!check_argc(cli, subcommand, argc, 6, "<uuid> <user> <serial> <flags>")) return 0;
return sendGenericOkFailOnBool(cli, e4crypt_prepare_user_storage(
parseNull(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5])));
} else if (subcommand == "destroy_user_storage") {
if (!check_argc(cli, subcommand, argc, 5, "<uuid> <user> <flags>")) return 0;
return sendGenericOkFailOnBool(cli,
e4crypt_destroy_user_storage(parseNull(argv[2]), atoi(argv[3]), atoi(argv[4])));
} else if (subcommand == "secdiscard") {
if (!check_argc(cli, subcommand, argc, 3, "<path>")) return 0;
return sendGenericOkFailOnBool(cli,
e4crypt_secdiscard(parseNull(argv[2])));
} else {
dumpArgs(argc, argv, -1);
cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs subcommand", false);
return 0;
}
// Always report that the command succeeded and return the error code.
// The caller will check the return value to see what the error was.
char msg[255];
snprintf(msg, sizeof(msg), "%d", rc);
cli->sendMsg(ResponseCode::CommandOkay, msg, false);
return 0;
}

View file

@ -1,42 +0,0 @@
/*
* Copyright (C) 2015 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 _CRYPTCOMMANDLISTENER_H__
#define _CRYPTCOMMANDLISTENER_H__
#include <sysutils/FrameworkListener.h>
#include <utils/Errors.h>
#include "VoldCommand.h"
class CryptCommandListener : public FrameworkListener {
public:
CryptCommandListener();
virtual ~CryptCommandListener() {}
private:
static void dumpArgs(int argc, char **argv, int argObscure);
static int sendGenericOkFailOnBool(SocketClient *cli, bool success);
class CryptfsCmd : public VoldCommand {
public:
CryptfsCmd();
virtual ~CryptfsCmd() {}
int runCommand(SocketClient *c, int argc, char ** argv);
};
int getSocket();
};
#endif

View file

@ -14,6 +14,8 @@
* limitations under the License.
*/
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
@ -28,91 +30,18 @@
#include <linux/kdev_t.h>
#define LOG_TAG "Vold"
#include <cutils/log.h>
#include <sysutils/SocketClient.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <utils/Trace.h>
#include "Devmapper.h"
#define DEVMAPPER_BUFFER_SIZE 4096
int Devmapper::dumpState(SocketClient *c) {
using android::base::StringPrintf;
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);
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_STATUS, io2)) {
if (errno != ENXIO) {
SLOGE("DM_DEV_STATUS ioctl failed (%s)", strerror(errno));
}
io2 = NULL;
}
char *tmp;
if (!io2) {
asprintf(&tmp, "%s %llu:%llu (no status available)", n->name, MAJOR(n->dev), MINOR(n->dev));
} else {
asprintf(&tmp, "%s %llu:%llu %d %d 0x%.8x %llu:%llu", n->name, MAJOR(n->dev),
MINOR(n->dev), io2->target_count, io2->open_count, io2->flags, MAJOR(io2->dev),
MINOR(io2->dev));
}
c->sendMsg(0, tmp, false);
free(tmp);
nxt = n->next;
} while (nxt);
free(buffer);
free(buffer2);
close(fd);
return 0;
}
static const char* kVoldPrefix = "vold:";
void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize,
const char *name, unsigned flags) {
@ -130,50 +59,20 @@ void Devmapper::ioctlInit(struct dm_ioctl *io, size_t dataSize,
}
}
int Devmapper::lookupActive(const char *name, char *ubuffer, size_t len) {
char *buffer = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
if (!buffer) {
SLOGE("Error allocating memory (%s)", strerror(errno));
return -1;
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening devmapper (%s)", strerror(errno));
free(buffer);
return -1;
}
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
if (ioctl(fd, DM_DEV_STATUS, io)) {
if (errno != ENXIO) {
SLOGE("DM_DEV_STATUS ioctl failed for lookup (%s)", strerror(errno));
}
free(buffer);
close(fd);
return -1;
}
close(fd);
unsigned minor = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
free(buffer);
snprintf(ubuffer, len, "/dev/block/dm-%u", minor);
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));
PLOG(ERROR) << "Failed malloc";
return -1;
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening devmapper (%s)", strerror(errno));
PLOG(ERROR) << "Failed open";
free(buffer);
return -1;
}
@ -184,7 +83,7 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
if (ioctl(fd, DM_DEV_CREATE, io)) {
SLOGE("Error creating device mapping (%s)", strerror(errno));
PLOG(ERROR) << "Failed DM_DEV_CREATE";
free(buffer);
close(fd);
return -1;
@ -199,7 +98,7 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
geoParams += strlen(geoParams) + 1;
geoParams = (char *) _align(geoParams, 8);
if (ioctl(fd, DM_DEV_SET_GEOMETRY, io)) {
SLOGE("Error setting device geometry (%s)", strerror(errno));
PLOG(ERROR) << "Failed DM_DEV_SET_GEOMETRY";
free(buffer);
close(fd);
return -1;
@ -208,7 +107,7 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
// Retrieve the device number we were allocated
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
if (ioctl(fd, DM_DEV_STATUS, io)) {
SLOGE("Error retrieving devmapper status (%s)", strerror(errno));
PLOG(ERROR) << "Failed DM_DEV_STATUS";
free(buffer);
close(fd);
return -1;
@ -239,7 +138,7 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
tgt->next = cryptParams - buffer;
if (ioctl(fd, DM_TABLE_LOAD, io)) {
SLOGE("Error loading mapping table (%s)", strerror(errno));
PLOG(ERROR) << "Failed DM_TABLE_LOAD";
free(buffer);
close(fd);
return -1;
@ -249,7 +148,7 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
ioctlInit(io, DEVMAPPER_BUFFER_SIZE, name, 0);
if (ioctl(fd, DM_DEV_SUSPEND, io)) {
SLOGE("Error Resuming (%s)", strerror(errno));
PLOG(ERROR) << "Failed DM_DEV_SUSPEND";
free(buffer);
close(fd);
return -1;
@ -261,16 +160,19 @@ int Devmapper::create(const char *name, const char *loopFile, const char *key,
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));
PLOG(ERROR) << "Failed malloc";
return -1;
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening devmapper (%s)", strerror(errno));
PLOG(ERROR) << "Failed open";
free(buffer);
return -1;
}
@ -282,7 +184,7 @@ int Devmapper::destroy(const char *name) {
if (ioctl(fd, DM_DEV_REMOVE, io)) {
if (errno != ENXIO) {
SLOGE("Error destroying device mapping (%s)", strerror(errno));
PLOG(ERROR) << "Failed DM_DEV_REMOVE";
}
free(buffer);
close(fd);
@ -294,6 +196,76 @@ int Devmapper::destroy(const char *name) {
return 0;
}
int Devmapper::destroyAll() {
ATRACE_NAME("Devmapper::destroyAll");
char *buffer = (char *) malloc(1024 * 64);
if (!buffer) {
PLOG(ERROR) << "Failed malloc";
return -1;
}
memset(buffer, 0, (1024 * 64));
char *buffer2 = (char *) malloc(DEVMAPPER_BUFFER_SIZE);
if (!buffer2) {
PLOG(ERROR) << "Failed malloc";
free(buffer);
return -1;
}
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR | O_CLOEXEC)) < 0) {
PLOG(ERROR) << "Failed open";
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)) {
PLOG(ERROR) << "Failed DM_LIST_DEVICES";
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);
auto name = std::string(n->name);
if (android::base::StartsWith(name, kVoldPrefix)) {
LOG(DEBUG) << "Tearing down stale dm device named " << 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 " << name;
}
}
} else {
LOG(VERBOSE) << "Found unmanaged dm device named " << 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;

View file

@ -20,15 +20,12 @@
#include <unistd.h>
#include <linux/dm-ioctl.h>
class SocketClient;
class Devmapper {
public:
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 lookupActive(const char *name, char *buffer, size_t len);
static int dumpState(SocketClient *c);
static int destroyAll();
private:
static void *_align(void *ptr, unsigned int a);

View file

@ -18,7 +18,6 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#include <time.h>
#include <sys/types.h>
@ -30,9 +29,8 @@
#include <algorithm>
#include "cutils/properties.h"
#define LOG_TAG "EncryptInplace"
#include "cutils/log.h"
#include <android-base/logging.h>
#include <android-base/properties.h>
// HORRIBLE HACK, FIXME
#include "cryptfs.h"
@ -75,6 +73,7 @@ struct encryptGroupsData
int completed;
time_t time_started;
int remaining_time;
bool set_progress_properties;
};
static void update_progress(struct encryptGroupsData* data, int is_used)
@ -90,17 +89,19 @@ static void update_progress(struct encryptGroupsData* data, int is_used)
data->new_pct = data->blocks_already_done / data->one_pct;
}
if (!data->set_progress_properties) return;
if (data->new_pct > data->cur_pct) {
char buf[8];
data->cur_pct = data->new_pct;
snprintf(buf, sizeof(buf), "%" PRId64, data->cur_pct);
property_set("vold.encrypt_progress", buf);
android::base::SetProperty("vold.encrypt_progress", buf);
}
if (data->cur_pct >= 5) {
struct timespec time_now;
if (clock_gettime(CLOCK_MONOTONIC, &time_now)) {
SLOGW("Error getting time");
LOG(WARNING) << "Error getting time";
} else {
double elapsed_time = difftime(time_now.tv_sec, data->time_started);
off64_t remaining_blocks = data->tot_used_blocks
@ -115,7 +116,7 @@ static void update_progress(struct encryptGroupsData* data, int is_used)
|| remaining_time > data->remaining_time + 60) {
char buf[8];
snprintf(buf, sizeof(buf), "%d", remaining_time);
property_set("vold.encrypt_time_remaining", buf);
android::base::SetProperty("vold.encrypt_time_remaining", buf);
data->remaining_time = remaining_time;
}
}
@ -131,15 +132,13 @@ static void log_progress(struct encryptGroupsData const* data, bool completed)
// Need to close existing 'Encrypting from' log?
if (completed || (offset != -1 && data->offset != offset)) {
SLOGI("Encrypted to sector %" PRId64,
offset / info.block_size * CRYPT_SECTOR_SIZE);
LOG(INFO) << "Encrypted to sector " << offset / info.block_size * CRYPT_SECTOR_SIZE;
offset = -1;
}
// Need to start new 'Encrypting from' log?
if (!completed && offset != data->offset) {
SLOGI("Encrypting from sector %" PRId64,
data->offset / info.block_size * CRYPT_SECTOR_SIZE);
LOG(INFO) << "Encrypting from sector " << data->offset / info.block_size * CRYPT_SECTOR_SIZE;
}
// Update offset
@ -154,21 +153,16 @@ static int flush_outstanding_data(struct encryptGroupsData* data)
return 0;
}
SLOGV("Copying %d blocks at offset %" PRIx64, data->count, data->offset);
LOG(VERBOSE) << "Copying " << data->count << " blocks at offset " << data->offset;
if (pread64(data->realfd, data->buffer,
info.block_size * data->count, data->offset)
<= 0) {
SLOGE("Error reading real_blkdev %s for inplace encrypt",
data->real_blkdev);
if (pread64(data->realfd, data->buffer, info.block_size * data->count, data->offset) <= 0) {
LOG(ERROR) << "Error reading real_blkdev " << data->real_blkdev << " for inplace encrypt";
return -1;
}
if (pwrite64(data->cryptofd, data->buffer,
info.block_size * data->count, data->offset)
<= 0) {
SLOGE("Error writing crypto_blkdev %s for inplace encrypt",
data->crypto_blkdev);
if (pwrite64(data->cryptofd, data->buffer, info.block_size * data->count, data->offset) <= 0) {
LOG(ERROR) << "Error writing crypto_blkdev " << data->crypto_blkdev
<< " for inplace encrypt";
return -1;
} else {
log_progress(data, false);
@ -190,18 +184,18 @@ static int encrypt_groups(struct encryptGroupsData* data)
data->buffer = (char*) malloc(info.block_size * BLOCKS_AT_A_TIME);
if (!data->buffer) {
SLOGE("Failed to allocate crypto buffer");
LOG(ERROR) << "Failed to allocate crypto buffer";
goto errout;
}
block_bitmap = (u8*) malloc(info.block_size);
if (!block_bitmap) {
SLOGE("failed to allocate block bitmap");
LOG(ERROR) << "failed to allocate block bitmap";
goto errout;
}
for (i = 0; i < aux_info.groups; ++i) {
SLOGI("Encrypting group %d", i);
LOG(INFO) << "Encrypting group " << i;
u32 first_block = aux_info.first_data_block + i * info.blocks_per_group;
u32 block_count = std::min(info.blocks_per_group,
@ -212,7 +206,7 @@ static int encrypt_groups(struct encryptGroupsData* data)
ret = pread64(data->realfd, block_bitmap, info.block_size, offset);
if (ret != (int)info.block_size) {
SLOGE("failed to read all of block group bitmap %d", i);
LOG(ERROR) << "failed to read all of block group bitmap " << i;
goto errout;
}
@ -260,13 +254,10 @@ errout:
return rc;
}
static int cryptfs_enable_inplace_ext4(char *crypto_blkdev,
char *real_blkdev,
off64_t size,
off64_t *size_already_done,
off64_t tot_size,
off64_t previously_encrypted_upto)
{
static int cryptfs_enable_inplace_ext4(char* crypto_blkdev, char* real_blkdev, off64_t size,
off64_t* size_already_done, off64_t tot_size,
off64_t previously_encrypted_upto,
bool set_progress_properties) {
u32 i;
struct encryptGroupsData data;
int rc; // Can't initialize without causing warning -Wclobbered
@ -274,43 +265,45 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev,
struct timespec time_started = {0};
if (previously_encrypted_upto > *size_already_done) {
SLOGD("Not fast encrypting since resuming part way through");
LOG(DEBUG) << "Not fast encrypting since resuming part way through";
return -1;
}
memset(&data, 0, sizeof(data));
data.real_blkdev = real_blkdev;
data.crypto_blkdev = crypto_blkdev;
data.set_progress_properties = set_progress_properties;
LOG(DEBUG) << "Opening" << real_blkdev;
if ( (data.realfd = open(real_blkdev, O_RDWR|O_CLOEXEC)) < 0) {
SLOGE("Error opening real_blkdev %s for inplace encrypt. err=%d(%s)\n",
real_blkdev, errno, strerror(errno));
PLOG(ERROR) << "Error opening real_blkdev " << real_blkdev << " for inplace encrypt";
rc = -1;
goto errout;
}
LOG(DEBUG) << "Opening" << crypto_blkdev;
// Wait until the block device appears. Re-use the mount retry values since it is reasonable.
while ((data.cryptofd = open(crypto_blkdev, O_WRONLY|O_CLOEXEC)) < 0) {
if (--retries) {
SLOGE("Error opening crypto_blkdev %s for ext4 inplace encrypt. err=%d(%s), retrying\n",
crypto_blkdev, errno, strerror(errno));
PLOG(ERROR) << "Error opening crypto_blkdev " << crypto_blkdev
<< " for ext4 inplace encrypt, retrying";
sleep(RETRY_MOUNT_DELAY_SECONDS);
} else {
SLOGE("Error opening crypto_blkdev %s for ext4 inplace encrypt. err=%d(%s)\n",
crypto_blkdev, errno, strerror(errno));
PLOG(ERROR) << "Error opening crypto_blkdev " << crypto_blkdev
<< " for ext4 inplace encrypt";
rc = ENABLE_INPLACE_ERR_DEV;
goto errout;
}
}
if (setjmp(setjmp_env)) { // NOLINT
SLOGE("Reading ext4 extent caused an exception\n");
LOG(ERROR) << "Reading ext4 extent caused an exception";
rc = -1;
goto errout;
}
if (read_ext(data.realfd, 0) != 0) {
SLOGE("Failed to read ext4 extent\n");
LOG(ERROR) << "Failed to read ext4 extent";
rc = -1;
goto errout;
}
@ -319,7 +312,7 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev,
data.tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE;
data.blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE;
SLOGI("Encrypting ext4 filesystem in place...");
LOG(INFO) << "Encrypting ext4 filesystem in place...";
data.tot_used_blocks = data.numblocks;
for (i = 0; i < aux_info.groups; ++i) {
@ -330,7 +323,7 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev,
data.cur_pct = 0;
if (clock_gettime(CLOCK_MONOTONIC, &time_started)) {
SLOGW("Error getting time at start");
LOG(WARNING) << "Error getting time at start";
// Note - continue anyway - we'll run with 0
}
data.time_started = time_started.tv_sec;
@ -338,7 +331,7 @@ static int cryptfs_enable_inplace_ext4(char *crypto_blkdev,
rc = encrypt_groups(&data);
if (rc) {
SLOGE("Error encrypting groups");
LOG(ERROR) << "Error encrypting groups";
goto errout;
}
@ -361,13 +354,13 @@ static void log_progress_f2fs(u64 block, bool completed)
// Need to close existing 'Encrypting from' log?
if (completed || (last_block != (u64)-1 && block != last_block + 1)) {
SLOGI("Encrypted to block %" PRId64, last_block);
LOG(INFO) << "Encrypted to block " << last_block;
last_block = -1;
}
// Need to start new 'Encrypting from' log?
if (!completed && (last_block == (u64)-1 || block != last_block + 1)) {
SLOGI("Encrypting from block %" PRId64, block);
LOG(INFO) << "Encrypting from block " << block;
}
// Update offset
@ -386,12 +379,14 @@ static int encrypt_one_block_f2fs(u64 pos, void *data)
off64_t offset = pos * CRYPT_INPLACE_BUFSIZE;
if (pread64(priv_dat->realfd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) {
SLOGE("Error reading real_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev);
LOG(ERROR) << "Error reading real_blkdev " << priv_dat->crypto_blkdev
<< " for f2fs inplace encrypt";
return -1;
}
if (pwrite64(priv_dat->cryptofd, priv_dat->buffer, CRYPT_INPLACE_BUFSIZE, offset) <= 0) {
SLOGE("Error writing crypto_blkdev %s for f2fs inplace encrypt", priv_dat->crypto_blkdev);
LOG(ERROR) << "Error writing crypto_blkdev " << priv_dat->crypto_blkdev
<< " for f2fs inplace encrypt";
return -1;
} else {
log_progress_f2fs(pos, false);
@ -400,33 +395,30 @@ static int encrypt_one_block_f2fs(u64 pos, void *data)
return 0;
}
static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev,
char *real_blkdev,
off64_t size,
off64_t *size_already_done,
off64_t tot_size,
off64_t previously_encrypted_upto)
{
static int cryptfs_enable_inplace_f2fs(char* crypto_blkdev, char* real_blkdev, off64_t size,
off64_t* size_already_done, off64_t tot_size,
off64_t previously_encrypted_upto,
bool set_progress_properties) {
struct encryptGroupsData data;
struct f2fs_info *f2fs_info = NULL;
int rc = ENABLE_INPLACE_ERR_OTHER;
if (previously_encrypted_upto > *size_already_done) {
SLOGD("Not fast encrypting since resuming part way through");
LOG(DEBUG) << "Not fast encrypting since resuming part way through";
return ENABLE_INPLACE_ERR_OTHER;
}
memset(&data, 0, sizeof(data));
data.real_blkdev = real_blkdev;
data.crypto_blkdev = crypto_blkdev;
data.set_progress_properties = set_progress_properties;
data.realfd = -1;
data.cryptofd = -1;
if ( (data.realfd = open64(real_blkdev, O_RDWR|O_CLOEXEC)) < 0) {
SLOGE("Error opening real_blkdev %s for f2fs inplace encrypt\n",
real_blkdev);
PLOG(ERROR) << "Error opening real_blkdev " << real_blkdev << " for f2fs inplace encrypt";
goto errout;
}
if ( (data.cryptofd = open64(crypto_blkdev, O_WRONLY|O_CLOEXEC)) < 0) {
SLOGE("Error opening crypto_blkdev %s for f2fs inplace encrypt. err=%d(%s)\n",
crypto_blkdev, errno, strerror(errno));
PLOG(ERROR) << "Error opening crypto_blkdev " << crypto_blkdev
<< " for f2fs inplace encrypt";
rc = ENABLE_INPLACE_ERR_DEV;
goto errout;
}
@ -448,7 +440,7 @@ static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev,
data.buffer = (char*) malloc(f2fs_info->block_size);
if (!data.buffer) {
SLOGE("Failed to allocate crypto buffer");
LOG(ERROR) << "Failed to allocate crypto buffer";
goto errout;
}
@ -458,7 +450,7 @@ static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev,
rc = run_on_used_blocks(data.blocks_already_done, f2fs_info, &encrypt_one_block_f2fs, &data);
if (rc) {
SLOGE("Error in running over f2fs blocks");
LOG(ERROR) << "Error in running over f2fs blocks";
rc = ENABLE_INPLACE_ERR_OTHER;
goto errout;
}
@ -467,8 +459,7 @@ static int cryptfs_enable_inplace_f2fs(char *crypto_blkdev,
rc = 0;
errout:
if (rc)
SLOGE("Failed to encrypt f2fs filesystem on %s", real_blkdev);
if (rc) LOG(ERROR) << "Failed to encrypt f2fs filesystem on " << real_blkdev;
log_progress_f2fs(0, true);
free(f2fs_info);
@ -479,11 +470,10 @@ errout:
return rc;
}
static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
off64_t size, off64_t *size_already_done,
off64_t tot_size,
off64_t previously_encrypted_upto)
{
static int cryptfs_enable_inplace_full(char* crypto_blkdev, char* real_blkdev, off64_t size,
off64_t* size_already_done, off64_t tot_size,
off64_t previously_encrypted_upto,
bool set_progress_properties) {
int realfd, cryptofd;
char *buf[CRYPT_INPLACE_BUFSIZE];
int rc = ENABLE_INPLACE_ERR_OTHER;
@ -492,13 +482,12 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
off64_t blocks_already_done, tot_numblocks;
if ( (realfd = open(real_blkdev, O_RDONLY|O_CLOEXEC)) < 0) {
SLOGE("Error opening real_blkdev %s for inplace encrypt\n", real_blkdev);
PLOG(ERROR) << "Error opening real_blkdev " << real_blkdev << " for inplace encrypt";
return ENABLE_INPLACE_ERR_OTHER;
}
if ( (cryptofd = open(crypto_blkdev, O_WRONLY|O_CLOEXEC)) < 0) {
SLOGE("Error opening crypto_blkdev %s for inplace encrypt. err=%d(%s)\n",
crypto_blkdev, errno, strerror(errno));
PLOG(ERROR) << "Error opening crypto_blkdev " << crypto_blkdev << " for inplace encrypt";
close(realfd);
return ENABLE_INPLACE_ERR_DEV;
}
@ -513,32 +502,32 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
tot_numblocks = tot_size / CRYPT_SECTORS_PER_BUFSIZE;
blocks_already_done = *size_already_done / CRYPT_SECTORS_PER_BUFSIZE;
SLOGE("Encrypting filesystem in place...");
LOG(ERROR) << "Encrypting filesystem in place...";
i = previously_encrypted_upto + 1 - *size_already_done;
if (lseek64(realfd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
SLOGE("Cannot seek to previously encrypted point on %s", real_blkdev);
PLOG(ERROR) << "Cannot seek to previously encrypted point on " << real_blkdev;
goto errout;
}
if (lseek64(cryptofd, i * CRYPT_SECTOR_SIZE, SEEK_SET) < 0) {
SLOGE("Cannot seek to previously encrypted point on %s", crypto_blkdev);
PLOG(ERROR) << "Cannot seek to previously encrypted point on " << crypto_blkdev;
goto errout;
}
for (;i < size && i % CRYPT_SECTORS_PER_BUFSIZE != 0; ++i) {
if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) {
SLOGE("Error reading initial sectors from real_blkdev %s for "
"inplace encrypt\n", crypto_blkdev);
PLOG(ERROR) << "Error reading initial sectors from real_blkdev " << real_blkdev
<< " for inplace encrypt";
goto errout;
}
if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) {
SLOGE("Error writing initial sectors to crypto_blkdev %s for "
"inplace encrypt\n", crypto_blkdev);
PLOG(ERROR) << "Error writing initial sectors to crypto_blkdev " << crypto_blkdev
<< " for inplace encrypt";
goto errout;
} else {
SLOGI("Encrypted 1 block at %" PRId64, i);
LOG(INFO) << "Encrypted 1 block at " << i;
}
}
@ -547,38 +536,39 @@ static int cryptfs_enable_inplace_full(char *crypto_blkdev, char *real_blkdev,
/* process the majority of the filesystem in blocks */
for (i/=CRYPT_SECTORS_PER_BUFSIZE; i<numblocks; i++) {
new_pct = (i + blocks_already_done) / one_pct;
if (new_pct > cur_pct) {
if (set_progress_properties && new_pct > cur_pct) {
char buf[8];
cur_pct = new_pct;
snprintf(buf, sizeof(buf), "%" PRId64, cur_pct);
property_set("vold.encrypt_progress", buf);
android::base::SetProperty("vold.encrypt_progress", buf);
}
if (unix_read(realfd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
SLOGE("Error reading real_blkdev %s for inplace encrypt", crypto_blkdev);
PLOG(ERROR) << "Error reading real_blkdev " << real_blkdev << " for inplace encrypt";
goto errout;
}
if (unix_write(cryptofd, buf, CRYPT_INPLACE_BUFSIZE) <= 0) {
SLOGE("Error writing crypto_blkdev %s for inplace encrypt", crypto_blkdev);
PLOG(ERROR) << "Error writing crypto_blkdev " << crypto_blkdev << " for inplace encrypt";
goto errout;
} else {
SLOGD("Encrypted %d block at %" PRId64,
CRYPT_SECTORS_PER_BUFSIZE,
i * CRYPT_SECTORS_PER_BUFSIZE);
LOG(DEBUG) << "Encrypted " << CRYPT_SECTORS_PER_BUFSIZE << " block at "
<< i * CRYPT_SECTORS_PER_BUFSIZE;
}
}
/* Do any remaining sectors */
for (i=0; i<remainder; i++) {
if (unix_read(realfd, buf, CRYPT_SECTOR_SIZE) <= 0) {
SLOGE("Error reading final sectors from real_blkdev %s for inplace encrypt", crypto_blkdev);
LOG(ERROR) << "Error reading final sectors from real_blkdev " << real_blkdev
<< " for inplace encrypt";
goto errout;
}
if (unix_write(cryptofd, buf, CRYPT_SECTOR_SIZE) <= 0) {
SLOGE("Error writing final sectors to crypto_blkdev %s for inplace encrypt", crypto_blkdev);
LOG(ERROR) << "Error writing final sectors to crypto_blkdev " << crypto_blkdev
<< " for inplace encrypt";
goto errout;
} else {
SLOGI("Encrypted 1 block at next location");
LOG(INFO) << "Encrypted 1 block at next location";
}
}
@ -593,17 +583,19 @@ errout:
}
/* returns on of the ENABLE_INPLACE_* return codes */
int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev,
off64_t size, off64_t *size_already_done,
off64_t tot_size,
off64_t previously_encrypted_upto)
{
int cryptfs_enable_inplace(char* crypto_blkdev, char* real_blkdev, off64_t size,
off64_t* size_already_done, off64_t tot_size,
off64_t previously_encrypted_upto, bool set_progress_properties) {
int rc_ext4, rc_f2fs, rc_full;
LOG(DEBUG) << "cryptfs_enable_inplace(" << crypto_blkdev << ", " << real_blkdev << ", " << size
<< ", " << size_already_done << ", " << tot_size << ", " << previously_encrypted_upto
<< ", " << set_progress_properties << ")";
if (previously_encrypted_upto) {
SLOGD("Continuing encryption from %" PRId64, previously_encrypted_upto);
LOG(DEBUG) << "Continuing encryption from " << previously_encrypted_upto;
}
if (*size_already_done + size < previously_encrypted_upto) {
LOG(DEBUG) << "cryptfs_enable_inplace already done";
*size_already_done += size;
return 0;
}
@ -612,29 +604,32 @@ int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev,
* As is, cryptfs_enable_inplace_ext4 will fail on an f2fs partition, and
* then we will drop down to cryptfs_enable_inplace_f2fs.
* */
if ((rc_ext4 = cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev,
size, size_already_done,
tot_size, previously_encrypted_upto)) == 0) {
if ((rc_ext4 = cryptfs_enable_inplace_ext4(crypto_blkdev, real_blkdev, size, size_already_done,
tot_size, previously_encrypted_upto,
set_progress_properties)) == 0) {
LOG(DEBUG) << "cryptfs_enable_inplace_ext4 success";
return 0;
}
SLOGD("cryptfs_enable_inplace_ext4()=%d\n", rc_ext4);
LOG(DEBUG) << "cryptfs_enable_inplace_ext4()=" << rc_ext4;
if ((rc_f2fs = cryptfs_enable_inplace_f2fs(crypto_blkdev, real_blkdev,
size, size_already_done,
tot_size, previously_encrypted_upto)) == 0) {
if ((rc_f2fs = cryptfs_enable_inplace_f2fs(crypto_blkdev, real_blkdev, size, size_already_done,
tot_size, previously_encrypted_upto,
set_progress_properties)) == 0) {
LOG(DEBUG) << "cryptfs_enable_inplace_f2fs success";
return 0;
}
SLOGD("cryptfs_enable_inplace_f2fs()=%d\n", rc_f2fs);
LOG(DEBUG) << "cryptfs_enable_inplace_f2fs()=" << rc_f2fs;
rc_full = cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev,
size, size_already_done, tot_size,
previously_encrypted_upto);
SLOGD("cryptfs_enable_inplace_full()=%d\n", rc_full);
rc_full =
cryptfs_enable_inplace_full(crypto_blkdev, real_blkdev, size, size_already_done, tot_size,
previously_encrypted_upto, set_progress_properties);
LOG(DEBUG) << "cryptfs_enable_inplace_full()=" << rc_full;
/* Hack for b/17898962, the following is the symptom... */
if (rc_ext4 == ENABLE_INPLACE_ERR_DEV
&& rc_f2fs == ENABLE_INPLACE_ERR_DEV
&& rc_full == ENABLE_INPLACE_ERR_DEV) {
LOG(DEBUG) << "ENABLE_INPLACE_ERR_DEV";
return ENABLE_INPLACE_ERR_DEV;
}
return rc_full;

View file

@ -24,9 +24,8 @@
#define RETRY_MOUNT_ATTEMPTS 10
#define RETRY_MOUNT_DELAY_SECONDS 1
int cryptfs_enable_inplace(char *crypto_blkdev, char *real_blkdev,
off64_t size, off64_t *size_already_done,
off64_t tot_size,
off64_t previously_encrypted_upto);
int cryptfs_enable_inplace(char* crypto_blkdev, char* real_blkdev, off64_t size,
off64_t* size_already_done, off64_t tot_size,
off64_t previously_encrypted_upto, bool set_progress_properties);
#endif

View file

@ -19,6 +19,7 @@
#include "KeyStorage.h"
#include "KeyUtil.h"
#include "Utils.h"
#include "VoldUtil.h"
#include <algorithm>
#include <map>
@ -39,6 +40,8 @@
#include <private/android_filesystem_config.h>
#include "android/os/IVold.h"
#include "cryptfs.h"
#define EMULATED_USES_SELINUX 0
@ -52,6 +55,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
using android::base::StringPrintf;
@ -59,18 +63,24 @@ using android::base::WriteStringToFile;
using android::vold::kEmptyAuthentication;
using android::vold::KeyBuffer;
// NOTE: keep in sync with StorageManager
static constexpr int FLAG_STORAGE_DE = 1 << 0;
static constexpr int FLAG_STORAGE_CE = 1 << 1;
namespace {
struct PolicyKeyRef {
std::string contents_mode;
std::string filenames_mode;
std::string key_raw_ref;
};
const std::string device_key_dir = std::string() + DATA_MNT_POINT + e4crypt_unencrypted_folder;
const std::string device_key_path = device_key_dir + "/key";
const std::string device_key_temp = device_key_dir + "/temp";
const std::string user_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/user_keys";
const std::string user_key_temp = user_key_dir + "/temp";
const std::string prepare_subdirs_path = "/system/bin/vold_prepare_subdirs";
const std::string systemwide_volume_key_dir =
std::string() + DATA_MNT_POINT + "/misc/vold/volume_keys";
bool s_global_de_initialized = false;
@ -89,8 +99,8 @@ static bool e4crypt_is_emulated() {
return property_get_bool("persist.sys.emulate_fbe", false);
}
static const char* escape_null(const char* value) {
return (value == nullptr) ? "null" : value;
static const char* escape_empty(const std::string& value) {
return value.empty() ? "null" : value.c_str();
}
static std::string get_de_key_path(userid_t user_id) {
@ -261,19 +271,19 @@ static bool lookup_key_ref(const std::map<userid_t, std::string>& key_map, useri
return true;
}
static bool ensure_policy(const std::string& raw_ref, const std::string& path) {
const char *contents_mode;
const char *filenames_mode;
static void get_data_file_encryption_modes(PolicyKeyRef* key_ref) {
struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab_default, DATA_MNT_POINT);
char const* contents_mode;
char const* filenames_mode;
fs_mgr_get_file_encryption_modes(rec, &contents_mode, &filenames_mode);
key_ref->contents_mode = contents_mode;
key_ref->filenames_mode = filenames_mode;
}
cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode);
if (e4crypt_policy_ensure(path.c_str(),
raw_ref.data(), raw_ref.size(),
contents_mode, filenames_mode) != 0) {
LOG(ERROR) << "Failed to set policy on: " << path;
return false;
}
return true;
static bool ensure_policy(const PolicyKeyRef& key_ref, const std::string& path) {
return e4crypt_policy_ensure(path.c_str(), key_ref.key_raw_ref.data(),
key_ref.key_raw_ref.size(), key_ref.contents_mode.c_str(),
key_ref.filenames_mode.c_str()) == 0;
}
static bool is_numeric(const char* name) {
@ -304,7 +314,7 @@ static bool load_all_de_keys() {
LOG(DEBUG) << "Skipping non-de-key " << entry->d_name;
continue;
}
userid_t user_id = atoi(entry->d_name);
userid_t user_id = std::stoi(entry->d_name);
if (s_de_key_raw_refs.count(user_id) == 0) {
auto key_path = de_dir + "/" + entry->d_name;
KeyBuffer key;
@ -328,23 +338,21 @@ bool e4crypt_initialize_global_de() {
return true;
}
const char *contents_mode;
const char *filenames_mode;
cryptfs_get_file_encryption_modes(&contents_mode, &filenames_mode);
std::string modestring = std::string(contents_mode) + ":" + filenames_mode;
PolicyKeyRef device_ref;
if (!android::vold::retrieveAndInstallKey(true, kEmptyAuthentication, device_key_path,
device_key_temp, &device_ref.key_raw_ref))
return false;
get_data_file_encryption_modes(&device_ref);
std::string modestring = device_ref.contents_mode + ":" + device_ref.filenames_mode;
std::string mode_filename = std::string("/data") + e4crypt_key_mode;
if (!android::base::WriteStringToFile(modestring, mode_filename)) {
PLOG(ERROR) << "Cannot save type";
return false;
}
std::string device_key_ref;
if (!android::vold::retrieveAndInstallKey(true,
device_key_path, device_key_temp, &device_key_ref)) return false;
std::string ref_filename = std::string("/data") + e4crypt_key_ref;
if (!android::base::WriteStringToFile(device_key_ref, ref_filename)) {
if (!android::base::WriteStringToFile(device_ref.key_raw_ref, ref_filename)) {
PLOG(ERROR) << "Cannot save key reference to:" << ref_filename;
return false;
}
@ -370,7 +378,7 @@ bool e4crypt_init_user0() {
// We can only safely prepare DE storage here, since CE keys are probably
// entangled with user credentials. The framework will always prepare CE
// storage once CE keys are installed.
if (!e4crypt_prepare_user_storage(nullptr, 0, 0, FLAG_STORAGE_DE)) {
if (!e4crypt_prepare_user_storage("", 0, 0, android::os::IVold::STORAGE_FLAG_DE)) {
LOG(ERROR) << "Failed to prepare user 0 storage";
return false;
}
@ -482,8 +490,8 @@ static bool emulated_unlock(const std::string& path, mode_t mode) {
return true;
}
static bool parse_hex(const char* hex, std::string* result) {
if (strcmp("!", hex) == 0) {
static bool parse_hex(const std::string& hex, std::string* result) {
if (hex == "!") {
*result = "";
return true;
}
@ -494,10 +502,55 @@ static bool parse_hex(const char* hex, std::string* result) {
return true;
}
bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const char* token_hex,
const char* secret_hex) {
static std::string volkey_path(const std::string& misc_path, const std::string& volume_uuid) {
return misc_path + "/vold/volume_keys/" + volume_uuid + "/default";
}
static std::string volume_secdiscardable_path(const std::string& volume_uuid) {
return systemwide_volume_key_dir + "/" + volume_uuid + "/secdiscardable";
}
static bool read_or_create_volkey(const std::string& misc_path, const std::string& volume_uuid,
PolicyKeyRef* key_ref) {
auto secdiscardable_path = volume_secdiscardable_path(volume_uuid);
std::string secdiscardable_hash;
if (android::vold::pathExists(secdiscardable_path)) {
if (!android::vold::readSecdiscardable(secdiscardable_path, &secdiscardable_hash))
return false;
} else {
if (fs_mkdirs(secdiscardable_path.c_str(), 0700) != 0) {
PLOG(ERROR) << "Creating directories for: " << secdiscardable_path;
return false;
}
if (!android::vold::createSecdiscardable(secdiscardable_path, &secdiscardable_hash))
return false;
}
auto key_path = volkey_path(misc_path, volume_uuid);
if (fs_mkdirs(key_path.c_str(), 0700) != 0) {
PLOG(ERROR) << "Creating directories for: " << key_path;
return false;
}
android::vold::KeyAuthentication auth("", secdiscardable_hash);
if (!android::vold::retrieveAndInstallKey(true, auth, key_path, key_path + "_tmp",
&key_ref->key_raw_ref))
return false;
key_ref->contents_mode =
android::base::GetProperty("ro.crypto.volume.contents_mode", "aes-256-xts");
key_ref->filenames_mode =
android::base::GetProperty("ro.crypto.volume.filenames_mode", "aes-256-heh");
return true;
}
static bool destroy_volkey(const std::string& misc_path, const std::string& volume_uuid) {
auto path = volkey_path(misc_path, volume_uuid);
if (!android::vold::pathExists(path)) return true;
return android::vold::destroyKey(path);
}
bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token_hex,
const std::string& secret_hex) {
LOG(DEBUG) << "e4crypt_add_user_key_auth " << user_id << " serial=" << serial
<< " token_present=" << (strcmp(token_hex, "!") != 0);
<< " token_present=" << (token_hex != "!");
if (!e4crypt_is_native()) return true;
if (s_ephemeral_users.count(user_id) != 0) return true;
std::string token, secret;
@ -534,10 +587,10 @@ bool e4crypt_fixate_newest_user_key_auth(userid_t user_id) {
}
// TODO: rename to 'install' for consistency, and take flags to know which keys to install
bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token_hex,
const char* secret_hex) {
bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token_hex,
const std::string& secret_hex) {
LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " serial=" << serial
<< " token_present=" << (strcmp(token_hex, "!") != 0);
<< " token_present=" << (token_hex != "!");
if (e4crypt_is_native()) {
if (s_ce_key_raw_refs.count(user_id) != 0) {
LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id;
@ -557,8 +610,8 @@ bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token_hex
// back into a known-good state.
if (!emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) ||
!emulated_unlock(android::vold::BuildDataMiscCePath(user_id), 01771) ||
!emulated_unlock(android::vold::BuildDataMediaCePath(nullptr, user_id), 0770) ||
!emulated_unlock(android::vold::BuildDataUserCePath(nullptr, user_id), 0771)) {
!emulated_unlock(android::vold::BuildDataMediaCePath("", user_id), 0770) ||
!emulated_unlock(android::vold::BuildDataUserCePath("", user_id), 0771)) {
LOG(ERROR) << "Failed to unlock user " << user_id;
return false;
}
@ -575,8 +628,8 @@ bool e4crypt_lock_user_key(userid_t user_id) {
// When in emulation mode, we just use chmod
if (!emulated_lock(android::vold::BuildDataSystemCePath(user_id)) ||
!emulated_lock(android::vold::BuildDataMiscCePath(user_id)) ||
!emulated_lock(android::vold::BuildDataMediaCePath(nullptr, user_id)) ||
!emulated_lock(android::vold::BuildDataUserCePath(nullptr, user_id))) {
!emulated_lock(android::vold::BuildDataMediaCePath("", user_id)) ||
!emulated_lock(android::vold::BuildDataUserCePath("", user_id))) {
LOG(ERROR) << "Failed to lock user " << user_id;
return false;
}
@ -585,12 +638,23 @@ bool e4crypt_lock_user_key(userid_t user_id) {
return true;
}
bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial,
static bool prepare_subdirs(const std::string& action, const std::string& volume_uuid,
userid_t user_id, int flags) {
if (0 != android::vold::ForkExecvp(
std::vector<std::string>{prepare_subdirs_path, action, volume_uuid,
std::to_string(user_id), std::to_string(flags)})) {
LOG(ERROR) << "vold_prepare_subdirs failed";
return false;
}
return true;
}
bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
int flags) {
LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_null(volume_uuid)
LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_empty(volume_uuid)
<< ", user " << user_id << ", serial " << serial << ", flags " << flags;
if (flags & FLAG_STORAGE_DE) {
if (flags & android::os::IVold::STORAGE_FLAG_DE) {
// DE_sys key
auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
@ -599,8 +663,10 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int
// DE_n key
auto system_de_path = android::vold::BuildDataSystemDePath(user_id);
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
if (volume_uuid.empty()) {
if (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
#if MANAGE_MISC_DIRS
if (!prepare_dir(misc_legacy_path, 0750, multiuser_get_uid(user_id, AID_SYSTEM),
@ -610,37 +676,58 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int
if (!prepare_dir(system_de_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
if (!prepare_dir(vendor_de_path, 0771, AID_ROOT, AID_ROOT)) return false;
}
if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
if (e4crypt_is_native()) {
std::string de_raw_ref;
if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_raw_ref)) return false;
if (!ensure_policy(de_raw_ref, system_de_path)) return false;
if (!ensure_policy(de_raw_ref, misc_de_path)) return false;
if (!ensure_policy(de_raw_ref, user_de_path)) return false;
PolicyKeyRef de_ref;
if (volume_uuid.empty()) {
if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_ref.key_raw_ref)) return false;
get_data_file_encryption_modes(&de_ref);
if (!ensure_policy(de_ref, system_de_path)) return false;
if (!ensure_policy(de_ref, misc_de_path)) return false;
if (!ensure_policy(de_ref, vendor_de_path)) return false;
} else {
if (!read_or_create_volkey(misc_de_path, volume_uuid, &de_ref)) return false;
}
if (!ensure_policy(de_ref, user_de_path)) return false;
}
}
if (flags & FLAG_STORAGE_CE) {
if (flags & android::os::IVold::STORAGE_FLAG_CE) {
// CE_n key
auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
auto vendor_ce_path = android::vold::BuildDataVendorCePath(user_id);
auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
if (volume_uuid.empty()) {
if (!prepare_dir(system_ce_path, 0770, AID_SYSTEM, AID_SYSTEM)) return false;
if (!prepare_dir(misc_ce_path, 01771, AID_SYSTEM, AID_MISC)) return false;
if (!prepare_dir(vendor_ce_path, 0771, AID_ROOT, AID_ROOT)) return false;
}
if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
if (e4crypt_is_native()) {
std::string ce_raw_ref;
if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_raw_ref)) return false;
if (!ensure_policy(ce_raw_ref, system_ce_path)) return false;
if (!ensure_policy(ce_raw_ref, misc_ce_path)) return false;
if (!ensure_policy(ce_raw_ref, media_ce_path)) return false;
if (!ensure_policy(ce_raw_ref, user_ce_path)) return false;
PolicyKeyRef ce_ref;
if (volume_uuid.empty()) {
if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_ref.key_raw_ref)) return false;
get_data_file_encryption_modes(&ce_ref);
if (!ensure_policy(ce_ref, system_ce_path)) return false;
if (!ensure_policy(ce_ref, misc_ce_path)) return false;
if (!ensure_policy(ce_ref, vendor_ce_path)) return false;
} else {
if (!read_or_create_volkey(misc_ce_path, volume_uuid, &ce_ref)) return false;
}
if (!ensure_policy(ce_ref, media_ce_path)) return false;
if (!ensure_policy(ce_ref, user_ce_path)) return false;
}
if (volume_uuid.empty()) {
// Now that credentials have been installed, we can run restorecon
// over these paths
// NOTE: these paths need to be kept in sync with libselinux
@ -648,16 +735,40 @@ bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int
android::vold::RestoreconRecursive(misc_ce_path);
}
}
if (!prepare_subdirs("prepare", volume_uuid, user_id, flags)) return false;
return true;
}
bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int flags) {
LOG(DEBUG) << "e4crypt_destroy_user_storage for volume " << escape_null(volume_uuid)
bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags) {
LOG(DEBUG) << "e4crypt_destroy_user_storage for volume " << escape_empty(volume_uuid)
<< ", user " << user_id << ", flags " << flags;
bool res = true;
if (flags & FLAG_STORAGE_DE) {
res &= prepare_subdirs("destroy", volume_uuid, user_id, flags);
if (flags & android::os::IVold::STORAGE_FLAG_CE) {
// CE_n key
auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
auto vendor_ce_path = android::vold::BuildDataVendorCePath(user_id);
auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
res &= destroy_dir(media_ce_path);
res &= destroy_dir(user_ce_path);
if (volume_uuid.empty()) {
res &= destroy_dir(system_ce_path);
res &= destroy_dir(misc_ce_path);
res &= destroy_dir(vendor_ce_path);
} else {
if (e4crypt_is_native()) {
res &= destroy_volkey(misc_ce_path, volume_uuid);
}
}
}
if (flags & android::os::IVold::STORAGE_FLAG_DE) {
// DE_sys key
auto system_legacy_path = android::vold::BuildDataSystemLegacyPath(user_id);
auto misc_legacy_path = android::vold::BuildDataMiscLegacyPath(user_id);
@ -666,9 +777,11 @@ bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int
// DE_n key
auto system_de_path = android::vold::BuildDataSystemDePath(user_id);
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
if (volume_uuid == nullptr) {
res &= destroy_dir(user_de_path);
if (volume_uuid.empty()) {
res &= destroy_dir(system_legacy_path);
#if MANAGE_MISC_DIRS
res &= destroy_dir(misc_legacy_path);
@ -676,28 +789,49 @@ bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int
res &= destroy_dir(profiles_de_path);
res &= destroy_dir(system_de_path);
res &= destroy_dir(misc_de_path);
res &= destroy_dir(vendor_de_path);
} else {
if (e4crypt_is_native()) {
res &= destroy_volkey(misc_de_path, volume_uuid);
}
res &= destroy_dir(user_de_path);
}
if (flags & FLAG_STORAGE_CE) {
// CE_n key
auto system_ce_path = android::vold::BuildDataSystemCePath(user_id);
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
auto media_ce_path = android::vold::BuildDataMediaCePath(volume_uuid, user_id);
auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
if (volume_uuid == nullptr) {
res &= destroy_dir(system_ce_path);
res &= destroy_dir(misc_ce_path);
}
res &= destroy_dir(media_ce_path);
res &= destroy_dir(user_ce_path);
}
return res;
}
bool e4crypt_secdiscard(const char* path) {
return android::vold::runSecdiscardSingle(std::string(path));
static bool destroy_volume_keys(const std::string& directory_path, const std::string& volume_uuid) {
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(directory_path.c_str()), closedir);
if (!dirp) {
PLOG(ERROR) << "Unable to open directory: " + directory_path;
return false;
}
bool res = true;
for (;;) {
errno = 0;
auto const entry = readdir(dirp.get());
if (!entry) {
if (errno) {
PLOG(ERROR) << "Unable to read directory: " + directory_path;
return false;
}
break;
}
if (entry->d_type != DT_DIR || entry->d_name[0] == '.') {
LOG(DEBUG) << "Skipping non-user " << entry->d_name;
continue;
}
res &= destroy_volkey(directory_path + "/" + entry->d_name, volume_uuid);
}
return res;
}
bool e4crypt_destroy_volume_keys(const std::string& volume_uuid) {
bool res = true;
LOG(DEBUG) << "e4crypt_destroy_volume_keys for volume " << escape_empty(volume_uuid);
auto secdiscardable_path = volume_secdiscardable_path(volume_uuid);
res &= android::vold::runSecdiscardSingle(secdiscardable_path);
res &= destroy_volume_keys("/data/misc_ce", volume_uuid);
res &= destroy_volume_keys("/data/misc_de", volume_uuid);
return res;
}

View file

@ -14,29 +14,25 @@
* limitations under the License.
*/
#include <stdbool.h>
#include <sys/cdefs.h>
#include <string>
#include <cutils/multiuser.h>
__BEGIN_DECLS
// General functions
bool e4crypt_is_native();
bool e4crypt_initialize_global_de();
bool e4crypt_init_user0();
bool e4crypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral);
bool e4crypt_destroy_user_key(userid_t user_id);
bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const char* token,
const char* secret);
bool e4crypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token,
const std::string& secret);
bool e4crypt_fixate_newest_user_key_auth(userid_t user_id);
bool e4crypt_unlock_user_key(userid_t user_id, int serial, const char* token, const char* secret);
bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token,
const std::string& secret);
bool e4crypt_lock_user_key(userid_t user_id);
bool e4crypt_prepare_user_storage(const char* volume_uuid, userid_t user_id, int serial, int flags);
bool e4crypt_destroy_user_storage(const char* volume_uuid, userid_t user_id, int flags);
bool e4crypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_id, int serial,
int flags);
bool e4crypt_destroy_user_storage(const std::string& volume_uuid, userid_t user_id, int flags);
bool e4crypt_secdiscard(const char* path);
__END_DECLS
bool e4crypt_destroy_volume_keys(const std::string& volume_uuid);

388
IdleMaint.cpp Normal file
View file

@ -0,0 +1,388 @@
/*
* Copyright (C) 2015 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 "IdleMaint.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "model/PrivateVolume.h"
#include <thread>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <fs_mgr.h>
#include <private/android_filesystem_config.h>
#include <hardware_legacy/power.h>
#include <dirent.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
using android::base::Basename;
using android::base::ReadFileToString;
using android::base::Realpath;
using android::base::StringPrintf;
using android::base::Timer;
using android::base::WriteStringToFile;
namespace android {
namespace vold {
enum class PathTypes {
kMountPoint = 1,
kBlkDevice,
};
enum class IdleMaintStats {
kStopped = 1,
kRunning,
kAbort,
};
static const char* kWakeLock = "IdleMaint";
static const int DIRTY_SEGMENTS_THRESHOLD = 100;
/*
* Timing policy:
* 1. F2FS_GC = 7 mins
* 2. Trim = 1 min
* 3. Dev GC = 2 mins
*/
static const int GC_TIMEOUT_SEC = 420;
static const int DEVGC_TIMEOUT_SEC = 120;
static IdleMaintStats idle_maint_stat(IdleMaintStats::kStopped);
static std::condition_variable cv_abort, cv_stop;
static std::mutex cv_m;
static void addFromVolumeManager(std::list<std::string>* paths,
PathTypes path_type) {
VolumeManager* vm = VolumeManager::Instance();
std::list<std::string> privateIds;
vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
for (const auto& id : privateIds) {
PrivateVolume* vol = static_cast<PrivateVolume*>(vm->findVolume(id).get());
if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
if (path_type == PathTypes::kMountPoint) {
paths->push_back(vol->getPath());
} else if (path_type == PathTypes::kBlkDevice) {
std::string gc_path;
const std::string& fs_type = vol->getFsType();
if (fs_type == "f2fs" &&
Realpath(vol->getRawDevPath(), &gc_path)) {
paths->push_back(std::string("/sys/fs/") + fs_type +
"/" + Basename(gc_path));
}
}
}
}
}
static void addFromFstab(std::list<std::string>* paths, PathTypes path_type) {
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
struct fstab_rec *prev_rec = NULL;
for (int i = 0; i < fstab->num_entries; i++) {
auto fs_type = std::string(fstab->recs[i].fs_type);
/* Skip raw partitions */
if (fs_type == "emmc" || fs_type == "mtd") {
continue;
}
/* Skip read-only filesystems */
if (fstab->recs[i].flags & MS_RDONLY) {
continue;
}
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
continue; /* Should we trim fat32 filesystems? */
}
if (fs_mgr_is_notrim(&fstab->recs[i])) {
continue;
}
/* Skip the multi-type partitions, which are required to be following each other.
* See fs_mgr.c's mount_with_alternatives().
*/
if (prev_rec && !strcmp(prev_rec->mount_point, fstab->recs[i].mount_point)) {
continue;
}
if (path_type == PathTypes::kMountPoint) {
paths->push_back(fstab->recs[i].mount_point);
} else if (path_type == PathTypes::kBlkDevice) {
std::string gc_path;
if (std::string(fstab->recs[i].fs_type) == "f2fs" &&
Realpath(fstab->recs[i].blk_device, &gc_path)) {
paths->push_back(std::string("/sys/fs/") + fstab->recs[i].fs_type +
"/" + Basename(gc_path));
}
}
prev_rec = &fstab->recs[i];
}
}
void Trim(const android::sp<android::os::IVoldTaskListener>& listener) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
// Collect both fstab and vold volumes
std::list<std::string> paths;
addFromFstab(&paths, PathTypes::kMountPoint);
addFromVolumeManager(&paths, PathTypes::kMountPoint);
for (const auto& path : paths) {
LOG(DEBUG) << "Starting trim of " << path;
android::os::PersistableBundle extras;
extras.putString(String16("path"), String16(path.c_str()));
int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
if (fd < 0) {
PLOG(WARNING) << "Failed to open " << path;
if (listener) {
listener->onStatus(-1, extras);
}
continue;
}
struct fstrim_range range;
memset(&range, 0, sizeof(range));
range.len = ULLONG_MAX;
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
if (ioctl(fd, FITRIM, &range)) {
PLOG(WARNING) << "Trim failed on " << path;
if (listener) {
listener->onStatus(-1, extras);
}
} else {
nsecs_t time = systemTime(SYSTEM_TIME_BOOTTIME) - start;
LOG(INFO) << "Trimmed " << range.len << " bytes on " << path
<< " in " << nanoseconds_to_milliseconds(time) << "ms";
extras.putLong(String16("bytes"), range.len);
extras.putLong(String16("time"), time);
if (listener) {
listener->onStatus(0, extras);
}
}
close(fd);
}
if (listener) {
android::os::PersistableBundle extras;
listener->onFinished(0, extras);
}
release_wake_lock(kWakeLock);
}
static bool waitForGc(const std::list<std::string>& paths) {
std::unique_lock<std::mutex> lk(cv_m, std::defer_lock);
bool stop = false, aborted = false;
Timer timer;
while (!stop && !aborted) {
stop = true;
for (const auto& path : paths) {
std::string dirty_segments;
if (!ReadFileToString(path + "/dirty_segments", &dirty_segments)) {
PLOG(WARNING) << "Reading dirty_segments failed in " << path;
continue;
}
if (std::stoi(dirty_segments) > DIRTY_SEGMENTS_THRESHOLD) {
stop = false;
break;
}
}
if (stop) break;
if (timer.duration() >= std::chrono::seconds(GC_TIMEOUT_SEC)) {
LOG(WARNING) << "GC timeout";
break;
}
lk.lock();
aborted = cv_abort.wait_for(lk, 10s, []{
return idle_maint_stat == IdleMaintStats::kAbort;});
lk.unlock();
}
return aborted;
}
static int startGc(const std::list<std::string>& paths) {
for (const auto& path : paths) {
LOG(DEBUG) << "Start GC on " << path;
if (!WriteStringToFile("1", path + "/discard_granularity")) {
PLOG(WARNING) << "Set discard gralunarity failed on" << path;
}
if (!WriteStringToFile("1", path + "/gc_urgent")) {
PLOG(WARNING) << "Start GC failed on " << path;
}
}
return android::OK;
}
static int stopGc(const std::list<std::string>& paths) {
for (const auto& path : paths) {
LOG(DEBUG) << "Stop GC on " << path;
if (!WriteStringToFile("0", path + "/gc_urgent")) {
PLOG(WARNING) << "Stop GC failed on " << path;
}
if (!WriteStringToFile("16", path + "/discard_granularity")) {
PLOG(WARNING) << "Set discard gralunarity failed on" << path;
}
}
return android::OK;
}
static void runDevGc(void) {
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
struct fstab_rec *rec = NULL;
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_has_sysfs_path(&fstab->recs[i])) {
rec = &fstab->recs[i];
break;
}
}
if (!rec) {
return;
}
std::string path;
path.append(rec->sysfs_path);
path = path + "/manual_gc";
Timer timer;
LOG(DEBUG) << "Start Dev GC on " << path;
while (1) {
std::string require;
if (!ReadFileToString(path, &require)) {
PLOG(WARNING) << "Reading manual_gc failed in " << path;
break;
}
if (require == "" || require == "off" || require == "disabled") {
LOG(DEBUG) << "No more to do Dev GC";
break;
}
LOG(DEBUG) << "Trigger Dev GC on " << path;
if (!WriteStringToFile("1", path)) {
PLOG(WARNING) << "Start Dev GC failed on " << path;
break;
}
if (timer.duration() >= std::chrono::seconds(DEVGC_TIMEOUT_SEC)) {
LOG(WARNING) << "Dev GC timeout";
break;
}
sleep(2);
}
LOG(DEBUG) << "Stop Dev GC on " << path;
if (!WriteStringToFile("0", path)) {
PLOG(WARNING) << "Stop Dev GC failed on " << path;
}
return;
}
int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
std::unique_lock<std::mutex> lk(cv_m);
if (idle_maint_stat != IdleMaintStats::kStopped) {
LOG(DEBUG) << "idle maintenance is already running";
if (listener) {
android::os::PersistableBundle extras;
listener->onFinished(0, extras);
}
return android::OK;
}
idle_maint_stat = IdleMaintStats::kRunning;
lk.unlock();
LOG(DEBUG) << "idle maintenance started";
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
std::list<std::string> paths;
addFromFstab(&paths, PathTypes::kBlkDevice);
addFromVolumeManager(&paths, PathTypes::kBlkDevice);
startGc(paths);
bool gc_aborted = waitForGc(paths);
stopGc(paths);
lk.lock();
idle_maint_stat = IdleMaintStats::kStopped;
lk.unlock();
cv_stop.notify_one();
if (!gc_aborted) {
Trim(nullptr);
runDevGc();
}
if (listener) {
android::os::PersistableBundle extras;
listener->onFinished(0, extras);
}
LOG(DEBUG) << "idle maintenance completed";
release_wake_lock(kWakeLock);
return android::OK;
}
int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
std::unique_lock<std::mutex> lk(cv_m);
if (idle_maint_stat != IdleMaintStats::kStopped) {
idle_maint_stat = IdleMaintStats::kAbort;
lk.unlock();
cv_abort.notify_one();
lk.lock();
LOG(DEBUG) << "aborting idle maintenance";
cv_stop.wait(lk, []{
return idle_maint_stat == IdleMaintStats::kStopped;});
}
lk.unlock();
if (listener) {
android::os::PersistableBundle extras;
listener->onFinished(0, extras);
}
release_wake_lock(kWakeLock);
LOG(DEBUG) << "idle maintenance stopped";
return android::OK;
}
} // namespace vold
} // namespace android

View file

@ -14,33 +14,17 @@
* limitations under the License.
*/
#ifndef ANDROID_VOLD_MOVE_TASK_H
#define ANDROID_VOLD_MOVE_TASK_H
#ifndef ANDROID_VOLD_IDLE_MAINT_H
#define ANDROID_VOLD_IDLE_MAINT_H
#include "Utils.h"
#include "VolumeBase.h"
#include <thread>
#include "android/os/IVoldTaskListener.h"
namespace android {
namespace vold {
class MoveTask {
public:
MoveTask(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to);
virtual ~MoveTask();
void start();
private:
std::shared_ptr<VolumeBase> mFrom;
std::shared_ptr<VolumeBase> mTo;
std::thread mThread;
void run();
DISALLOW_COPY_AND_ASSIGN(MoveTask);
};
void Trim(const android::sp<android::os::IVoldTaskListener>& listener);
int RunIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
int AbortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
} // namespace vold
} // namespace android

View file

@ -35,13 +35,13 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <hardware/hw_auth_token.h>
#include <keystore/authorization_set.h>
#include <keystore/keystore_hidl_support.h>
#include <keymasterV4_0/authorization_set.h>
#include <keymasterV4_0/keymaster_utils.h>
extern "C" {
@ -50,7 +50,6 @@ extern "C" {
namespace android {
namespace vold {
using namespace keystore;
const KeyAuthentication kEmptyAuthentication{"", ""};
@ -88,7 +87,7 @@ static bool checkSize(const std::string& kind, size_t actual, size_t expected) {
return true;
}
static std::string hashWithPrefix(char const* prefix, const std::string& tohash) {
static void hashWithPrefix(char const* prefix, const std::string& tohash, std::string* res) {
SHA512_CTX c;
SHA512_Init(&c);
@ -99,22 +98,19 @@ static std::string hashWithPrefix(char const* prefix, const std::string& tohash)
hashingPrefix.resize(SHA512_CBLOCK);
SHA512_Update(&c, hashingPrefix.data(), hashingPrefix.size());
SHA512_Update(&c, tohash.data(), tohash.size());
std::string res(SHA512_DIGEST_LENGTH, '\0');
SHA512_Final(reinterpret_cast<uint8_t*>(&res[0]), &c);
return res;
res->assign(SHA512_DIGEST_LENGTH, '\0');
SHA512_Final(reinterpret_cast<uint8_t*>(&(*res)[0]), &c);
}
static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication& auth,
const std::string& appId, std::string* key) {
auto paramBuilder = AuthorizationSetBuilder()
auto paramBuilder = km::AuthorizationSetBuilder()
.AesEncryptionKey(AES_KEY_BYTES * 8)
.Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
.Authorization(TAG_MIN_MAC_LENGTH, GCM_MAC_BYTES * 8)
.Authorization(TAG_PADDING, PaddingMode::NONE)
.Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId));
.GcmModeMinMacLen(GCM_MAC_BYTES * 8)
.Authorization(km::TAG_APPLICATION_ID, km::support::blob2hidlVec(appId));
if (auth.token.empty()) {
LOG(DEBUG) << "Creating key that doesn't need auth token";
paramBuilder.Authorization(TAG_NO_AUTH_REQUIRED);
paramBuilder.Authorization(km::TAG_NO_AUTH_REQUIRED);
} else {
LOG(DEBUG) << "Auth token required for key";
if (auth.token.size() != sizeof(hw_auth_token_t)) {
@ -123,25 +119,24 @@ static bool generateKeymasterKey(Keymaster& keymaster, const KeyAuthentication&
return false;
}
const hw_auth_token_t* at = reinterpret_cast<const hw_auth_token_t*>(auth.token.data());
paramBuilder.Authorization(TAG_USER_SECURE_ID, at->user_id);
paramBuilder.Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD);
paramBuilder.Authorization(TAG_AUTH_TIMEOUT, AUTH_TIMEOUT);
paramBuilder.Authorization(km::TAG_USER_SECURE_ID, at->user_id);
paramBuilder.Authorization(km::TAG_USER_AUTH_TYPE, km::HardwareAuthenticatorType::PASSWORD);
paramBuilder.Authorization(km::TAG_AUTH_TIMEOUT, AUTH_TIMEOUT);
}
return keymaster.generateKey(paramBuilder, key);
}
static AuthorizationSet beginParams(const KeyAuthentication& auth,
const std::string& appId) {
auto paramBuilder = AuthorizationSetBuilder()
.Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
.Authorization(TAG_MAC_LENGTH, GCM_MAC_BYTES * 8)
.Authorization(TAG_PADDING, PaddingMode::NONE)
.Authorization(TAG_APPLICATION_ID, blob2hidlVec(appId));
static std::pair<km::AuthorizationSet, km::HardwareAuthToken> beginParams(
const KeyAuthentication& auth, const std::string& appId) {
auto paramBuilder = km::AuthorizationSetBuilder()
.GcmModeMacLen(GCM_MAC_BYTES * 8)
.Authorization(km::TAG_APPLICATION_ID, km::support::blob2hidlVec(appId));
km::HardwareAuthToken authToken;
if (!auth.token.empty()) {
LOG(DEBUG) << "Supplying auth token to Keymaster";
paramBuilder.Authorization(TAG_AUTH_TOKEN, blob2hidlVec(auth.token));
authToken = km::support::hidlVec2AuthToken(km::support::blob2hidlVec(auth.token));
}
return std::move(paramBuilder);
return {paramBuilder, authToken};
}
static bool readFileToString(const std::string& filename, std::string* result) {
@ -153,29 +148,72 @@ static bool readFileToString(const std::string& filename, std::string* result) {
}
static bool writeStringToFile(const std::string& payload, const std::string& filename) {
if (!android::base::WriteStringToFile(payload, filename)) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(
open(filename.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0666)));
if (fd == -1) {
PLOG(ERROR) << "Failed to open " << filename;
return false;
}
if (!android::base::WriteStringToFd(payload, fd)) {
PLOG(ERROR) << "Failed to write to " << filename;
unlink(filename.c_str());
return false;
}
// fsync as close won't guarantee flush data
// see close(2), fsync(2) and b/68901441
if (fsync(fd) == -1) {
if (errno == EROFS || errno == EINVAL) {
PLOG(WARNING) << "Skip fsync " << filename
<< " on a file system does not support synchronization";
} else {
PLOG(ERROR) << "Failed to fsync " << filename;
unlink(filename.c_str());
return false;
}
}
return true;
}
static bool readRandomBytesOrLog(size_t count, std::string* out) {
auto status = ReadRandomBytes(count, *out);
if (status != OK) {
LOG(ERROR) << "Random read failed with status: " << status;
return false;
}
return true;
}
bool createSecdiscardable(const std::string& filename, std::string* hash) {
std::string secdiscardable;
if (!readRandomBytesOrLog(SECDISCARDABLE_BYTES, &secdiscardable)) return false;
if (!writeStringToFile(secdiscardable, filename)) return false;
hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable, hash);
return true;
}
bool readSecdiscardable(const std::string& filename, std::string* hash) {
std::string secdiscardable;
if (!readFileToString(filename, &secdiscardable)) return false;
hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable, hash);
return true;
}
static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir,
KeyPurpose purpose,
const AuthorizationSet &keyParams,
const AuthorizationSet &opParams,
AuthorizationSet* outParams) {
km::KeyPurpose purpose, const km::AuthorizationSet& keyParams,
const km::AuthorizationSet& opParams,
const km::HardwareAuthToken& authToken,
km::AuthorizationSet* outParams) {
auto kmKeyPath = dir + "/" + kFn_keymaster_key_blob;
std::string kmKey;
if (!readFileToString(kmKeyPath, &kmKey)) return KeymasterOperation();
AuthorizationSet inParams(keyParams);
km::AuthorizationSet inParams(keyParams);
inParams.append(opParams.begin(), opParams.end());
for (;;) {
auto opHandle = keymaster.begin(purpose, kmKey, inParams, outParams);
auto opHandle = keymaster.begin(purpose, kmKey, inParams, authToken, outParams);
if (opHandle) {
return opHandle;
}
if (opHandle.errorCode() != ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle;
if (opHandle.errorCode() != km::ErrorCode::KEY_REQUIRES_UPGRADE) return opHandle;
LOG(DEBUG) << "Upgrading key: " << dir;
std::string newKey;
if (!keymaster.upgradeKey(kmKey, keyParams, &newKey)) return KeymasterOperation();
@ -194,19 +232,22 @@ static KeymasterOperation begin(Keymaster& keymaster, const std::string& dir,
}
static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
const AuthorizationSet &keyParams,
const km::AuthorizationSet& keyParams,
const km::HardwareAuthToken& authToken,
const KeyBuffer& message, std::string* ciphertext) {
AuthorizationSet opParams;
AuthorizationSet outParams;
auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams);
km::AuthorizationSet opParams;
km::AuthorizationSet outParams;
auto opHandle =
begin(keymaster, dir, km::KeyPurpose::ENCRYPT, keyParams, opParams, authToken, &outParams);
if (!opHandle) return false;
auto nonceBlob = outParams.GetTagValue(TAG_NONCE);
auto nonceBlob = outParams.GetTagValue(km::TAG_NONCE);
if (!nonceBlob.isOk()) {
LOG(ERROR) << "GCM encryption but no nonce generated";
return false;
}
// nonceBlob here is just a pointer into existing data, must not be freed
std::string nonce(reinterpret_cast<const char*>(&nonceBlob.value()[0]), nonceBlob.value().size());
std::string nonce(reinterpret_cast<const char*>(&nonceBlob.value()[0]),
nonceBlob.value().size());
if (!checkSize("nonce", nonce.size(), GCM_NONCE_BYTES)) return false;
std::string body;
if (!opHandle.updateCompletely(message, &body)) return false;
@ -219,13 +260,15 @@ static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir
}
static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
const AuthorizationSet &keyParams,
const km::AuthorizationSet& keyParams,
const km::HardwareAuthToken& authToken,
const std::string& ciphertext, KeyBuffer* message) {
auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES);
auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES);
auto opParams = AuthorizationSetBuilder()
.Authorization(TAG_NONCE, blob2hidlVec(nonce));
auto opHandle = begin(keymaster, dir, KeyPurpose::DECRYPT, keyParams, opParams, nullptr);
auto opParams = km::AuthorizationSetBuilder().Authorization(km::TAG_NONCE,
km::support::blob2hidlVec(nonce));
auto opHandle =
begin(keymaster, dir, km::KeyPurpose::DECRYPT, keyParams, opParams, authToken, nullptr);
if (!opHandle) return false;
if (!opHandle.updateCompletely(bodyAndMac, message)) return false;
if (!opHandle.finish(nullptr)) return false;
@ -269,9 +312,9 @@ static bool stretchSecret(const std::string& stretching, const std::string& secr
}
stretched->assign(STRETCHED_BYTES, '\0');
if (crypto_scrypt(reinterpret_cast<const uint8_t*>(secret.data()), secret.size(),
reinterpret_cast<const uint8_t*>(salt.data()), salt.size(),
1 << Nf, 1 << rf, 1 << pf,
reinterpret_cast<uint8_t*>(&(*stretched)[0]), stretched->size()) != 0) {
reinterpret_cast<const uint8_t*>(salt.data()), salt.size(), 1 << Nf,
1 << rf, 1 << pf, reinterpret_cast<uint8_t*>(&(*stretched)[0]),
stretched->size()) != 0) {
LOG(ERROR) << "scrypt failed with params: " << stretching;
return false;
}
@ -283,20 +326,11 @@ static bool stretchSecret(const std::string& stretching, const std::string& secr
}
static bool generateAppId(const KeyAuthentication& auth, const std::string& stretching,
const std::string& salt, const std::string& secdiscardable,
const std::string& salt, const std::string& secdiscardable_hash,
std::string* appId) {
std::string stretched;
if (!stretchSecret(stretching, auth.secret, salt, &stretched)) return false;
*appId = hashWithPrefix(kHashPrefix_secdiscardable, secdiscardable) + stretched;
return true;
}
static bool readRandomBytesOrLog(size_t count, std::string* out) {
auto status = ReadRandomBytes(count, *out);
if (status != OK) {
LOG(ERROR) << "Random read failed with status: " << status;
return false;
}
*appId = secdiscardable_hash + stretched;
return true;
}
@ -304,9 +338,10 @@ static void logOpensslError() {
LOG(ERROR) << "Openssl error: " << ERR_get_error();
}
static bool encryptWithoutKeymaster(const std::string& preKey,
const KeyBuffer& plaintext, std::string* ciphertext) {
auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
static bool encryptWithoutKeymaster(const std::string& preKey, const KeyBuffer& plaintext,
std::string* ciphertext) {
std::string key;
hashWithPrefix(kHashPrefix_keygen, preKey, &key);
key.resize(AES_KEY_BYTES);
if (!readRandomBytesOrLog(GCM_NONCE_BYTES, ciphertext)) return false;
auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
@ -323,9 +358,9 @@ static bool encryptWithoutKeymaster(const std::string& preKey,
}
ciphertext->resize(GCM_NONCE_BYTES + plaintext.size() + GCM_MAC_BYTES);
int outlen;
if (1 != EVP_EncryptUpdate(ctx.get(),
reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES), &outlen,
reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size())) {
if (1 != EVP_EncryptUpdate(
ctx.get(), reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES),
&outlen, reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size())) {
logOpensslError();
return false;
}
@ -333,8 +368,10 @@ static bool encryptWithoutKeymaster(const std::string& preKey,
LOG(ERROR) << "GCM ciphertext length should be " << plaintext.size() << " was " << outlen;
return false;
}
if (1 != EVP_EncryptFinal_ex(ctx.get(),
reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()), &outlen)) {
if (1 != EVP_EncryptFinal_ex(
ctx.get(),
reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()),
&outlen)) {
logOpensslError();
return false;
}
@ -343,20 +380,22 @@ static bool encryptWithoutKeymaster(const std::string& preKey,
return false;
}
if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, GCM_MAC_BYTES,
reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES + plaintext.size()))) {
reinterpret_cast<uint8_t*>(&(*ciphertext)[0] + GCM_NONCE_BYTES +
plaintext.size()))) {
logOpensslError();
return false;
}
return true;
}
static bool decryptWithoutKeymaster(const std::string& preKey,
const std::string& ciphertext, KeyBuffer* plaintext) {
static bool decryptWithoutKeymaster(const std::string& preKey, const std::string& ciphertext,
KeyBuffer* plaintext) {
if (ciphertext.size() < GCM_NONCE_BYTES + GCM_MAC_BYTES) {
LOG(ERROR) << "GCM ciphertext too small: " << ciphertext.size();
return false;
}
auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
std::string key;
hashWithPrefix(kHashPrefix_keygen, preKey, &key);
key.resize(AES_KEY_BYTES);
auto ctx = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>(
EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free);
@ -372,9 +411,9 @@ static bool decryptWithoutKeymaster(const std::string& preKey,
}
*plaintext = KeyBuffer(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES);
int outlen;
if (1 != EVP_DecryptUpdate(ctx.get(),
reinterpret_cast<uint8_t*>(&(*plaintext)[0]), &outlen,
reinterpret_cast<const uint8_t*>(ciphertext.data() + GCM_NONCE_BYTES), plaintext->size())) {
if (1 != EVP_DecryptUpdate(ctx.get(), reinterpret_cast<uint8_t*>(&(*plaintext)[0]), &outlen,
reinterpret_cast<const uint8_t*>(ciphertext.data() + GCM_NONCE_BYTES),
plaintext->size())) {
logOpensslError();
return false;
}
@ -383,13 +422,14 @@ static bool decryptWithoutKeymaster(const std::string& preKey,
return false;
}
if (1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, GCM_MAC_BYTES,
const_cast<void *>(
reinterpret_cast<const void*>(ciphertext.data() + GCM_NONCE_BYTES + plaintext->size())))) {
const_cast<void*>(reinterpret_cast<const void*>(
ciphertext.data() + GCM_NONCE_BYTES + plaintext->size())))) {
logOpensslError();
return false;
}
if (1 != EVP_DecryptFinal_ex(ctx.get(),
reinterpret_cast<uint8_t*>(&(*plaintext)[0] + plaintext->size()), &outlen)) {
reinterpret_cast<uint8_t*>(&(*plaintext)[0] + plaintext->size()),
&outlen)) {
logOpensslError();
return false;
}
@ -410,9 +450,8 @@ bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBu
return false;
}
if (!writeStringToFile(kCurrentVersion, dir + "/" + kFn_version)) return false;
std::string secdiscardable;
if (!readRandomBytesOrLog(SECDISCARDABLE_BYTES, &secdiscardable)) return false;
if (!writeStringToFile(secdiscardable, dir + "/" + kFn_secdiscardable)) return false;
std::string secdiscardable_hash;
if (!createSecdiscardable(dir + "/" + kFn_secdiscardable, &secdiscardable_hash)) return false;
std::string stretching = getStretching(auth);
if (!writeStringToFile(stretching, dir + "/" + kFn_stretching)) return false;
std::string salt;
@ -424,7 +463,7 @@ bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBu
if (!writeStringToFile(salt, dir + "/" + kFn_salt)) return false;
}
std::string appId;
if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
if (!generateAppId(auth, stretching, salt, secdiscardable_hash, &appId)) return false;
std::string encryptedKey;
if (auth.usesKeymaster()) {
Keymaster keymaster;
@ -432,8 +471,11 @@ bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBu
std::string kmKey;
if (!generateKeymasterKey(keymaster, auth, appId, &kmKey)) return false;
if (!writeStringToFile(kmKey, dir + "/" + kFn_keymaster_key_blob)) return false;
auto keyParams = beginParams(auth, appId);
if (!encryptWithKeymasterKey(keymaster, dir, keyParams, key, &encryptedKey)) return false;
km::AuthorizationSet keyParams;
km::HardwareAuthToken authToken;
std::tie(keyParams, authToken) = beginParams(auth, appId);
if (!encryptWithKeymasterKey(keymaster, dir, keyParams, authToken, key, &encryptedKey))
return false;
} else {
if (!encryptWithoutKeymaster(appId, key, &encryptedKey)) return false;
}
@ -467,8 +509,8 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe
LOG(ERROR) << "Version mismatch, expected " << kCurrentVersion << " got " << version;
return false;
}
std::string secdiscardable;
if (!readFileToString(dir + "/" + kFn_secdiscardable, &secdiscardable)) return false;
std::string secdiscardable_hash;
if (!readSecdiscardable(dir + "/" + kFn_secdiscardable, &secdiscardable_hash)) return false;
std::string stretching;
if (!readFileToString(dir + "/" + kFn_stretching, &stretching)) return false;
std::string salt;
@ -476,14 +518,17 @@ bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffe
if (!readFileToString(dir + "/" + kFn_salt, &salt)) return false;
}
std::string appId;
if (!generateAppId(auth, stretching, salt, secdiscardable, &appId)) return false;
if (!generateAppId(auth, stretching, salt, secdiscardable_hash, &appId)) return false;
std::string encryptedMessage;
if (!readFileToString(dir + "/" + kFn_encrypted_key, &encryptedMessage)) return false;
if (auth.usesKeymaster()) {
Keymaster keymaster;
if (!keymaster) return false;
auto keyParams = beginParams(auth, appId);
if (!decryptWithKeymasterKey(keymaster, dir, keyParams, encryptedMessage, key)) return false;
km::AuthorizationSet keyParams;
km::HardwareAuthToken authToken;
std::tie(keyParams, authToken) = beginParams(auth, appId);
if (!decryptWithKeymasterKey(keymaster, dir, keyParams, authToken, encryptedMessage, key))
return false;
} else {
if (!decryptWithoutKeymaster(appId, encryptedMessage, key)) return false;
}
@ -499,23 +544,8 @@ static bool deleteKey(const std::string& dir) {
return true;
}
static bool runSecdiscard(const std::string& dir) {
if (ForkExecvp(
std::vector<std::string>{kSecdiscardPath, "--",
dir + "/" + kFn_encrypted_key,
dir + "/" + kFn_keymaster_key_blob,
dir + "/" + kFn_secdiscardable,
}) != 0) {
LOG(ERROR) << "secdiscard failed";
return false;
}
return true;
}
bool runSecdiscardSingle(const std::string& file) {
if (ForkExecvp(
std::vector<std::string>{kSecdiscardPath, "--",
file}) != 0) {
if (ForkExecvp(std::vector<std::string>{kSecdiscardPath, "--", file}) != 0) {
LOG(ERROR) << "secdiscard failed";
return false;
}
@ -533,8 +563,20 @@ static bool recursiveDeleteKey(const std::string& dir) {
bool destroyKey(const std::string& dir) {
bool success = true;
// Try each thing, even if previous things failed.
bool uses_km = pathExists(dir + "/" + kFn_keymaster_key_blob);
if (uses_km) {
success &= deleteKey(dir);
success &= runSecdiscard(dir);
}
auto secdiscard_cmd = std::vector<std::string>{
kSecdiscardPath, "--", dir + "/" + kFn_encrypted_key, dir + "/" + kFn_secdiscardable,
};
if (uses_km) {
secdiscard_cmd.emplace_back(dir + "/" + kFn_keymaster_key_blob);
}
if (ForkExecvp(secdiscard_cmd) != 0) {
LOG(ERROR) << "secdiscard failed";
success = false;
}
success &= recursiveDeleteKey(dir);
return success;
}

View file

@ -44,6 +44,9 @@ extern const KeyAuthentication kEmptyAuthentication;
// Checks if path "path" exists.
bool pathExists(const std::string& path);
bool createSecdiscardable(const std::string& path, std::string* hash);
bool readSecdiscardable(const std::string& path, std::string* hash);
// Create a directory at the named path, and store "key" in it,
// in such a way that it can only be retrieved via Keymaster and
// can be securely deleted.

View file

@ -161,12 +161,13 @@ bool evictKey(const std::string& raw_ref) {
return success;
}
bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
const std::string& tmp_path, std::string* key_ref) {
bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
const std::string& key_path, const std::string& tmp_path,
std::string* key_ref) {
KeyBuffer key;
if (pathExists(key_path)) {
LOG(DEBUG) << "Key exists, using: " << key_path;
if (!retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
if (!retrieveKey(key_path, key_authentication, &key)) return false;
} else {
if (!create_if_absent) {
LOG(ERROR) << "No key found in " << key_path;
@ -174,8 +175,7 @@ bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
}
LOG(INFO) << "Creating new key in " << key_path;
if (!randomKey(&key)) return false;
if (!storeKeyAtomically(key_path, tmp_path,
kEmptyAuthentication, key)) return false;
if (!storeKeyAtomically(key_path, tmp_path, key_authentication, key)) return false;
}
if (!installKey(key, key_ref)) {

View file

@ -18,6 +18,7 @@
#define ANDROID_VOLD_KEYUTIL_H
#include "KeyBuffer.h"
#include "KeyStorage.h"
#include <string>
#include <memory>
@ -28,8 +29,9 @@ namespace vold {
bool randomKey(KeyBuffer* key);
bool installKey(const KeyBuffer& key, std::string* raw_ref);
bool evictKey(const std::string& raw_ref);
bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
const std::string& tmp_path, std::string* key_ref);
bool retrieveAndInstallKey(bool create_if_absent, const KeyAuthentication& key_authentication,
const std::string& key_path, const std::string& tmp_path,
std::string* key_ref);
bool retrieveKey(bool create_if_absent, const std::string& key_path,
const std::string& tmp_path, KeyBuffer* key);

View file

@ -17,44 +17,46 @@
#include "Keymaster.h"
#include <android-base/logging.h>
#include <keystore/keymaster_tags.h>
#include <keystore/authorization_set.h>
#include <keystore/keystore_hidl_support.h>
using namespace ::keystore;
using android::hardware::hidl_string;
#include <keymasterV4_0/authorization_set.h>
#include <keymasterV4_0/keymaster_utils.h>
namespace android {
namespace vold {
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::keymaster::V4_0::SecurityLevel;
KeymasterOperation::~KeymasterOperation() {
if (mDevice.get()) mDevice->abort(mOpHandle);
if (mDevice) mDevice->abort(mOpHandle);
}
bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen,
const std::function<void(const char*, size_t)> consumer) {
uint32_t inputConsumed = 0;
ErrorCode km_error;
auto hidlCB = [&] (ErrorCode ret, uint32_t inputConsumedDelta,
const hidl_vec<KeyParameter>& /*ignored*/, const hidl_vec<uint8_t>& _output) {
km::ErrorCode km_error;
auto hidlCB = [&](km::ErrorCode ret, uint32_t inputConsumedDelta,
const hidl_vec<km::KeyParameter>& /*ignored*/,
const hidl_vec<uint8_t>& _output) {
km_error = ret;
if (km_error != ErrorCode::OK) return;
if (km_error != km::ErrorCode::OK) return;
inputConsumed += inputConsumedDelta;
consumer(reinterpret_cast<const char*>(&_output[0]), _output.size());
};
while (inputConsumed != inputLen) {
size_t toRead = static_cast<size_t>(inputLen - inputConsumed);
auto inputBlob =
blob2hidlVec(reinterpret_cast<const uint8_t*>(&input[inputConsumed]), toRead);
auto error = mDevice->update(mOpHandle, hidl_vec<KeyParameter>(), inputBlob, hidlCB);
auto inputBlob = km::support::blob2hidlVec(
reinterpret_cast<const uint8_t*>(&input[inputConsumed]), toRead);
auto error = mDevice->update(mOpHandle, hidl_vec<km::KeyParameter>(), inputBlob,
km::HardwareAuthToken(), km::VerificationToken(), hidlCB);
if (!error.isOk()) {
LOG(ERROR) << "update failed: " << error.description();
mDevice = nullptr;
return false;
}
if (km_error != ErrorCode::OK) {
if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "update failed, code " << int32_t(km_error);
mDevice = nullptr;
return false;
@ -69,40 +71,59 @@ bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen,
}
bool KeymasterOperation::finish(std::string* output) {
ErrorCode km_error;
auto hidlCb = [&] (ErrorCode ret, const hidl_vec<KeyParameter>& /*ignored*/,
km::ErrorCode km_error;
auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<km::KeyParameter>& /*ignored*/,
const hidl_vec<uint8_t>& _output) {
km_error = ret;
if (km_error != ErrorCode::OK) return;
if (output)
output->assign(reinterpret_cast<const char*>(&_output[0]), _output.size());
if (km_error != km::ErrorCode::OK) return;
if (output) output->assign(reinterpret_cast<const char*>(&_output[0]), _output.size());
};
auto error = mDevice->finish(mOpHandle, hidl_vec<KeyParameter>(), hidl_vec<uint8_t>(),
hidl_vec<uint8_t>(), hidlCb);
auto error = mDevice->finish(mOpHandle, hidl_vec<km::KeyParameter>(), hidl_vec<uint8_t>(),
hidl_vec<uint8_t>(), km::HardwareAuthToken(),
km::VerificationToken(), hidlCb);
mDevice = nullptr;
if (!error.isOk()) {
LOG(ERROR) << "finish failed: " << error.description();
return false;
}
if (km_error != ErrorCode::OK) {
if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "finish failed, code " << int32_t(km_error);
return false;
}
return true;
}
/* static */ bool Keymaster::hmacKeyGenerated = false;
Keymaster::Keymaster() {
mDevice = ::android::hardware::keymaster::V3_0::IKeymasterDevice::getService();
auto devices = KmDevice::enumerateAvailableDevices();
if (!hmacKeyGenerated) {
KmDevice::performHmacKeyAgreement(devices);
hmacKeyGenerated = true;
}
for (auto& dev : devices) {
// Do not use StrongBox for device encryption / credential encryption. If a security chip
// is present it will have Weaver, which already strengthens CE. We get no additional
// benefit from using StrongBox here, so skip it.
if (dev->halVersion().securityLevel != SecurityLevel::STRONGBOX) {
mDevice = std::move(dev);
break;
}
}
if (!mDevice) return;
auto& version = mDevice->halVersion();
LOG(INFO) << "Using " << version.keymasterName << " from " << version.authorName
<< " for encryption. Security level: " << toString(version.securityLevel)
<< ", HAL: " << mDevice->descriptor() << "/" << mDevice->instanceName();
}
bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key) {
ErrorCode km_error;
auto hidlCb = [&] (ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
const KeyCharacteristics& /*ignored*/) {
bool Keymaster::generateKey(const km::AuthorizationSet& inParams, std::string* key) {
km::ErrorCode km_error;
auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
const km::KeyCharacteristics& /*ignored*/) {
km_error = ret;
if (km_error != ErrorCode::OK) return;
if (key)
key->assign(reinterpret_cast<const char*>(&keyBlob[0]), keyBlob.size());
if (km_error != km::ErrorCode::OK) return;
if (key) key->assign(reinterpret_cast<const char*>(&keyBlob[0]), keyBlob.size());
};
auto error = mDevice->generateKey(inParams.hidl_data(), hidlCb);
@ -110,7 +131,7 @@ bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key)
LOG(ERROR) << "generate_key failed: " << error.description();
return false;
}
if (km_error != ErrorCode::OK) {
if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "generate_key failed, code " << int32_t(km_error);
return false;
}
@ -118,26 +139,26 @@ bool Keymaster::generateKey(const AuthorizationSet& inParams, std::string* key)
}
bool Keymaster::deleteKey(const std::string& key) {
auto keyBlob = blob2hidlVec(key);
auto keyBlob = km::support::blob2hidlVec(key);
auto error = mDevice->deleteKey(keyBlob);
if (!error.isOk()) {
LOG(ERROR) << "delete_key failed: " << error.description();
return false;
}
if (ErrorCode(error) != ErrorCode::OK) {
LOG(ERROR) << "delete_key failed, code " << uint32_t(ErrorCode(error));
if (error != km::ErrorCode::OK) {
LOG(ERROR) << "delete_key failed, code " << int32_t(km::ErrorCode(error));
return false;
}
return true;
}
bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams,
bool Keymaster::upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams,
std::string* newKey) {
auto oldKeyBlob = blob2hidlVec(oldKey);
ErrorCode km_error;
auto hidlCb = [&] (ErrorCode ret, const hidl_vec<uint8_t>& upgradedKeyBlob) {
auto oldKeyBlob = km::support::blob2hidlVec(oldKey);
km::ErrorCode km_error;
auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<uint8_t>& upgradedKeyBlob) {
km_error = ret;
if (km_error != ErrorCode::OK) return;
if (km_error != km::ErrorCode::OK) return;
if (newKey)
newKey->assign(reinterpret_cast<const char*>(&upgradedKeyBlob[0]),
upgradedKeyBlob.size());
@ -147,46 +168,43 @@ bool Keymaster::upgradeKey(const std::string& oldKey, const AuthorizationSet& in
LOG(ERROR) << "upgrade_key failed: " << error.description();
return false;
}
if (km_error != ErrorCode::OK) {
if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "upgrade_key failed, code " << int32_t(km_error);
return false;
}
return true;
}
KeymasterOperation Keymaster::begin(KeyPurpose purpose, const std::string& key,
const AuthorizationSet& inParams,
AuthorizationSet* outParams) {
auto keyBlob = blob2hidlVec(key);
KeymasterOperation Keymaster::begin(km::KeyPurpose purpose, const std::string& key,
const km::AuthorizationSet& inParams,
const km::HardwareAuthToken& authToken,
km::AuthorizationSet* outParams) {
auto keyBlob = km::support::blob2hidlVec(key);
uint64_t mOpHandle;
ErrorCode km_error;
km::ErrorCode km_error;
auto hidlCb = [&] (ErrorCode ret, const hidl_vec<KeyParameter>& _outParams,
auto hidlCb = [&](km::ErrorCode ret, const hidl_vec<km::KeyParameter>& _outParams,
uint64_t operationHandle) {
km_error = ret;
if (km_error != ErrorCode::OK) return;
if (outParams)
*outParams = _outParams;
if (km_error != km::ErrorCode::OK) return;
if (outParams) *outParams = _outParams;
mOpHandle = operationHandle;
};
auto error = mDevice->begin(purpose, keyBlob, inParams.hidl_data(), hidlCb);
auto error = mDevice->begin(purpose, keyBlob, inParams.hidl_data(), authToken, hidlCb);
if (!error.isOk()) {
LOG(ERROR) << "begin failed: " << error.description();
return KeymasterOperation(ErrorCode::UNKNOWN_ERROR);
return KeymasterOperation(km::ErrorCode::UNKNOWN_ERROR);
}
if (km_error != ErrorCode::OK) {
if (km_error != km::ErrorCode::OK) {
LOG(ERROR) << "begin failed, code " << int32_t(km_error);
return KeymasterOperation(km_error);
}
return KeymasterOperation(mDevice, mOpHandle);
return KeymasterOperation(mDevice.get(), mOpHandle);
}
bool Keymaster::isSecure() {
bool _isSecure = false;
auto rc = mDevice->getHardwareFeatures(
[&] (bool isSecure, bool, bool, bool, bool, const hidl_string&, const hidl_string&) {
_isSecure = isSecure; });
return rc.isOk() && _isSecure;
return mDevice->halVersion().securityLevel != km::SecurityLevel::SOFTWARE;
}
} // namespace vold
@ -219,17 +237,14 @@ static bool write_string_to_buf(const std::string& towrite, uint8_t* buffer, uin
return true;
}
static AuthorizationSet keyParams(uint32_t rsa_key_size, uint64_t rsa_exponent, uint32_t ratelimit) {
return AuthorizationSetBuilder()
.Authorization(TAG_ALGORITHM, Algorithm::RSA)
.Authorization(TAG_KEY_SIZE, rsa_key_size)
.Authorization(TAG_RSA_PUBLIC_EXPONENT, rsa_exponent)
.Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
.Authorization(TAG_PADDING, PaddingMode::NONE)
.Authorization(TAG_DIGEST, Digest::NONE)
.Authorization(TAG_BLOB_USAGE_REQUIREMENTS, KeyBlobUsageRequirements::STANDALONE)
.Authorization(TAG_NO_AUTH_REQUIRED)
.Authorization(TAG_MIN_SECONDS_BETWEEN_OPS, ratelimit);
static km::AuthorizationSet keyParams(uint32_t rsa_key_size, uint64_t rsa_exponent,
uint32_t ratelimit) {
return km::AuthorizationSetBuilder()
.RsaSigningKey(rsa_key_size, rsa_exponent)
.NoDigestOrPadding()
.Authorization(km::TAG_BLOB_USAGE_REQUIREMENTS, km::KeyBlobUsageRequirements::STANDALONE)
.Authorization(km::TAG_NO_AUTH_REQUIRED)
.Authorization(km::TAG_MIN_SECONDS_BETWEEN_OPS, ratelimit);
}
int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent,
@ -282,30 +297,28 @@ KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt(
return KeymasterSignResult::error;
}
AuthorizationSet outParams;
km::AuthorizationSet outParams;
std::string key(reinterpret_cast<const char*>(key_blob), key_blob_size);
std::string input(reinterpret_cast<const char*>(object), object_size);
std::string output;
KeymasterOperation op;
auto paramBuilder = AuthorizationSetBuilder()
.Authorization(TAG_PADDING, PaddingMode::NONE)
.Authorization(TAG_DIGEST, Digest::NONE);
auto paramBuilder = km::AuthorizationSetBuilder().NoDigestOrPadding();
while (true) {
op = dev.begin(KeyPurpose::SIGN, key, paramBuilder, &outParams);
if (op.errorCode() == ErrorCode::KEY_RATE_LIMIT_EXCEEDED) {
op = dev.begin(km::KeyPurpose::SIGN, key, paramBuilder, km::HardwareAuthToken(), &outParams);
if (op.errorCode() == km::ErrorCode::KEY_RATE_LIMIT_EXCEEDED) {
sleep(ratelimit);
continue;
} else break;
} else
break;
}
if (op.errorCode() == ErrorCode::KEY_REQUIRES_UPGRADE) {
if (op.errorCode() == km::ErrorCode::KEY_REQUIRES_UPGRADE) {
LOG(ERROR) << "Keymaster key requires upgrade";
return KeymasterSignResult::upgrade;
}
if (op.errorCode() != ErrorCode::OK) {
if (op.errorCode() != km::ErrorCode::OK) {
LOG(ERROR) << "Error starting keymaster signature transaction: " << int32_t(op.errorCode());
return KeymasterSignResult::error;
}
@ -317,7 +330,8 @@ KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt(
}
if (!op.finish(&output)) {
LOG(ERROR) << "Error finalizing keymaster signature transaction: " << int32_t(op.errorCode());
LOG(ERROR) << "Error finalizing keymaster signature transaction: "
<< int32_t(op.errorCode());
return KeymasterSignResult::error;
}

View file

@ -17,24 +17,21 @@
#ifndef ANDROID_VOLD_KEYMASTER_H
#define ANDROID_VOLD_KEYMASTER_H
#ifdef __cplusplus
#include "KeyBuffer.h"
#include <memory>
#include <string>
#include <utility>
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
#include <android-base/macros.h>
#include <keystore/authorization_set.h>
#include <keymasterV4_0/Keymaster.h>
#include <keymasterV4_0/authorization_set.h>
namespace android {
namespace vold {
using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
using ::keystore::ErrorCode;
using ::keystore::KeyPurpose;
using ::keystore::AuthorizationSet;
namespace km = ::android::hardware::keymaster::V4_0;
using KmDevice = km::support::Keymaster;
// C++ wrappers to the Keymaster hidl interface.
// This is tailored to the needs of KeyStorage, but could be extended to be
@ -49,53 +46,49 @@ class KeymasterOperation {
~KeymasterOperation();
// Is this instance valid? This is false if creation fails, and becomes
// false on finish or if an update fails.
explicit operator bool() { return mError == ErrorCode::OK; }
ErrorCode errorCode() { return mError; }
explicit operator bool() { return mError == km::ErrorCode::OK; }
km::ErrorCode errorCode() { return mError; }
// Call "update" repeatedly until all of the input is consumed, and
// concatenate the output. Return true on success.
template <class TI, class TO>
bool updateCompletely(TI& input, TO* output) {
if (output) output->clear();
return updateCompletely(input.data(), input.size(), [&](const char* b, size_t n) {
if (output) std::copy(b, b+n, std::back_inserter(*output));
if (output) std::copy(b, b + n, std::back_inserter(*output));
});
}
// Finish and write the output to this string, unless pointer is null.
bool finish(std::string* output);
// Move constructor
KeymasterOperation(KeymasterOperation&& rhs) {
mDevice = std::move(rhs.mDevice);
mOpHandle = std::move(rhs.mOpHandle);
mError = std::move(rhs.mError);
}
KeymasterOperation(KeymasterOperation&& rhs) { *this = std::move(rhs); }
// Construct an object in an error state for error returns
KeymasterOperation()
: mDevice{nullptr}, mOpHandle{0},
mError {ErrorCode::UNKNOWN_ERROR} {}
KeymasterOperation() : mDevice{nullptr}, mOpHandle{0}, mError{km::ErrorCode::UNKNOWN_ERROR} {}
// Move Assignment
KeymasterOperation& operator= (KeymasterOperation&& rhs) {
mDevice = std::move(rhs.mDevice);
mOpHandle = std::move(rhs.mOpHandle);
mError = std::move(rhs.mError);
rhs.mError = ErrorCode::UNKNOWN_ERROR;
KeymasterOperation& operator=(KeymasterOperation&& rhs) {
mDevice = rhs.mDevice;
rhs.mDevice = nullptr;
mOpHandle = rhs.mOpHandle;
rhs.mOpHandle = 0;
mError = rhs.mError;
rhs.mError = km::ErrorCode::UNKNOWN_ERROR;
return *this;
}
private:
KeymasterOperation(const sp<IKeymasterDevice>& d, uint64_t h)
: mDevice{d}, mOpHandle{h}, mError {ErrorCode::OK} {}
KeymasterOperation(ErrorCode error)
: mDevice{nullptr}, mOpHandle{0},
mError {error} {}
KeymasterOperation(KmDevice* d, uint64_t h)
: mDevice{d}, mOpHandle{h}, mError{km::ErrorCode::OK} {}
KeymasterOperation(km::ErrorCode error) : mDevice{nullptr}, mOpHandle{0}, mError{error} {}
bool updateCompletely(const char* input, size_t inputLen,
const std::function<void(const char*, size_t)> consumer);
sp<IKeymasterDevice> mDevice;
KmDevice* mDevice;
uint64_t mOpHandle;
ErrorCode mError;
km::ErrorCode mError;
DISALLOW_COPY_AND_ASSIGN(KeymasterOperation);
friend class Keymaster;
};
@ -108,27 +101,29 @@ class Keymaster {
// false if we failed to open the keymaster device.
explicit operator bool() { return mDevice.get() != nullptr; }
// Generate a key in the keymaster from the given params.
bool generateKey(const AuthorizationSet& inParams, std::string* key);
bool generateKey(const km::AuthorizationSet& inParams, std::string* key);
// If the keymaster supports it, permanently delete a key.
bool deleteKey(const std::string& key);
// Replace stored key blob in response to KM_ERROR_KEY_REQUIRES_UPGRADE.
bool upgradeKey(const std::string& oldKey, const AuthorizationSet& inParams,
bool upgradeKey(const std::string& oldKey, const km::AuthorizationSet& inParams,
std::string* newKey);
// Begin a new cryptographic operation, collecting output parameters if pointer is non-null
KeymasterOperation begin(KeyPurpose purpose, const std::string& key,
const AuthorizationSet& inParams, AuthorizationSet* outParams);
KeymasterOperation begin(km::KeyPurpose purpose, const std::string& key,
const km::AuthorizationSet& inParams,
const km::HardwareAuthToken& authToken,
km::AuthorizationSet* outParams);
bool isSecure();
private:
sp<hardware::keymaster::V3_0::IKeymasterDevice> mDevice;
std::unique_ptr<KmDevice> mDevice;
DISALLOW_COPY_AND_ASSIGN(Keymaster);
static bool hmacKeyGenerated;
};
} // namespace vold
} // namespace android
#endif // __cplusplus
// FIXME no longer needed now cryptfs is in C++.
/*
* The following functions provide C bindings to keymaster services
@ -138,7 +133,6 @@ class Keymaster {
* The sign_object function signes an object with the given keymaster
* key.
*/
__BEGIN_DECLS
/* Return values for keymaster_sign_object_for_cryptfs_scrypt */
@ -149,12 +143,9 @@ enum class KeymasterSignResult {
};
int keymaster_compatibility_cryptfs_scrypt();
int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size,
uint64_t rsa_exponent,
uint32_t ratelimit,
uint8_t* key_buffer,
uint32_t key_buffer_size,
uint32_t* key_out_size);
int keymaster_create_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent,
uint32_t ratelimit, uint8_t* key_buffer,
uint32_t key_buffer_size, uint32_t* key_out_size);
int keymaster_upgrade_key_for_cryptfs_scrypt(uint32_t rsa_key_size, uint64_t rsa_exponent,
uint32_t ratelimit, const uint8_t* key_blob,
@ -165,6 +156,4 @@ KeymasterSignResult keymaster_sign_object_for_cryptfs_scrypt(
const uint8_t* key_blob, size_t key_blob_size, uint32_t ratelimit, const uint8_t* object,
const size_t object_size, uint8_t** signature_buffer, size_t* signature_buffer_size);
__END_DECLS
#endif

312
Loop.cpp
View file

@ -14,8 +14,11 @@
* limitations under the License.
*/
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
@ -28,213 +31,20 @@
#include <linux/kdev_t.h>
#define LOG_TAG "Vold"
#include <cutils/log.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <utils/Trace.h>
#include <sysutils/SocketClient.h>
#include "Loop.h"
#include "Asec.h"
#include "VoldUtil.h"
#include "sehandle.h"
using android::base::StringPrintf;
using android::base::unique_fd;
int Loop::dumpState(SocketClient *c) {
int i;
int fd;
char filename[256];
for (i = 0; i < LOOP_MAX; i++) {
struct loop_info64 li;
int rc;
snprintf(filename, sizeof(filename), "/dev/block/loop%d", i);
if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
if (errno != ENOENT) {
SLOGE("Unable to open %s (%s)", filename, strerror(errno));
} else {
continue;
}
return -1;
}
rc = ioctl(fd, LOOP_GET_STATUS64, &li);
close(fd);
if (rc < 0 && errno == ENXIO) {
continue;
}
if (rc < 0) {
SLOGE("Unable to get loop status for %s (%s)", filename,
strerror(errno));
return -1;
}
char *tmp = NULL;
asprintf(&tmp, "%s %d %lld:%lld %llu %lld:%lld %lld 0x%x {%s} {%s}", filename, li.lo_number,
MAJOR(li.lo_device), MINOR(li.lo_device), li.lo_inode, MAJOR(li.lo_rdevice),
MINOR(li.lo_rdevice), li.lo_offset, li.lo_flags, li.lo_crypt_name,
li.lo_file_name);
c->sendMsg(0, tmp, false);
free(tmp);
}
return 0;
}
int Loop::lookupActive(const char *id, char *buffer, size_t len) {
int i;
int fd;
char filename[256];
memset(buffer, 0, len);
for (i = 0; i < LOOP_MAX; i++) {
struct loop_info64 li;
int rc;
snprintf(filename, sizeof(filename), "/dev/block/loop%d", i);
if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
if (errno != ENOENT) {
SLOGE("Unable to open %s (%s)", filename, strerror(errno));
} else {
continue;
}
return -1;
}
rc = ioctl(fd, LOOP_GET_STATUS64, &li);
if (rc < 0 && errno == ENXIO) {
close(fd);
continue;
}
close(fd);
if (rc < 0) {
SLOGE("Unable to get loop status for %s (%s)", filename,
strerror(errno));
return -1;
}
if (!strncmp((const char*) li.lo_crypt_name, id, LO_NAME_SIZE)) {
break;
}
}
if (i == LOOP_MAX) {
errno = ENOENT;
return -1;
}
strlcpy(buffer, filename, len);
return 0;
}
int Loop::create(const char *id, const char *loopFile, char *loopDeviceBuffer, size_t len) {
int i;
int fd;
char filename[256];
for (i = 0; i < LOOP_MAX; i++) {
struct loop_info64 li;
int rc;
char *secontext = NULL;
snprintf(filename, sizeof(filename), "/dev/block/loop%d", i);
/*
* The kernel starts us off with 8 loop nodes, but more
* are created on-demand if needed.
*/
mode_t mode = 0660 | S_IFBLK;
unsigned int dev = (0xff & i) | ((i << 12) & 0xfff00000) | (7 << 8);
if (sehandle) {
rc = selabel_lookup(sehandle, &secontext, filename, S_IFBLK);
if (rc == 0)
setfscreatecon(secontext);
}
if (mknod(filename, mode, dev) < 0) {
if (errno != EEXIST) {
int sverrno = errno;
SLOGE("Error creating loop device node (%s)", strerror(errno));
if (secontext) {
freecon(secontext);
setfscreatecon(NULL);
}
errno = sverrno;
return -1;
}
}
if (secontext) {
freecon(secontext);
setfscreatecon(NULL);
}
if ((fd = open(filename, O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Unable to open %s (%s)", filename, strerror(errno));
return -1;
}
rc = ioctl(fd, LOOP_GET_STATUS64, &li);
if (rc < 0 && errno == ENXIO)
break;
close(fd);
if (rc < 0) {
SLOGE("Unable to get loop status for %s (%s)", filename,
strerror(errno));
return -1;
}
}
if (i == LOOP_MAX) {
SLOGE("Exhausted all loop devices");
errno = ENOSPC;
return -1;
}
strlcpy(loopDeviceBuffer, filename, len);
int file_fd;
if ((file_fd = open(loopFile, O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Unable to open %s (%s)", loopFile, strerror(errno));
close(fd);
return -1;
}
if (ioctl(fd, LOOP_SET_FD, file_fd) < 0) {
SLOGE("Error setting up loopback interface (%s)", strerror(errno));
close(file_fd);
close(fd);
return -1;
}
struct loop_info64 li;
memset(&li, 0, sizeof(li));
strlcpy((char*) li.lo_crypt_name, id, LO_NAME_SIZE);
strlcpy((char*) li.lo_file_name, loopFile, LO_NAME_SIZE);
if (ioctl(fd, LOOP_SET_STATUS64, &li) < 0) {
SLOGE("Error setting loopback status (%s)", strerror(errno));
close(file_fd);
close(fd);
return -1;
}
close(fd);
close(file_fd);
return 0;
}
static const char* kVoldPrefix = "vold:";
int Loop::create(const std::string& target, std::string& out_device) {
unique_fd ctl_fd(open("/dev/loop-control", O_RDWR | O_CLOEXEC));
@ -267,6 +77,14 @@ int Loop::create(const std::string& target, std::string& out_device) {
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;
}
@ -275,12 +93,12 @@ int Loop::destroyByDevice(const char *loopDevice) {
device_fd = open(loopDevice, O_RDONLY | O_CLOEXEC);
if (device_fd < 0) {
SLOGE("Failed to open loop (%d)", errno);
PLOG(ERROR) << "Failed to open " << loopDevice;
return -1;
}
if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
SLOGE("Failed to destroy loop (%d)", errno);
PLOG(ERROR) << "Failed to destroy " << loopDevice;
close(device_fd);
return -1;
}
@ -289,9 +107,50 @@ int Loop::destroyByDevice(const char *loopDevice) {
return 0;
}
int Loop::destroyByFile(const char * /*loopFile*/) {
errno = ENOSYS;
int Loop::destroyAll() {
ATRACE_NAME("Loop::destroyAll");
std::string root = "/dev/block/";
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(root.c_str()), closedir);
if (!dirp) {
PLOG(ERROR) << "Failed to opendir";
return -1;
}
// Poke through all devices looking for loops
struct dirent* de;
while ((de = readdir(dirp.get()))) {
auto test = std::string(de->d_name);
if (!android::base::StartsWith(test, "loop")) continue;
auto path = root + de->d_name;
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;
}
auto id = std::string((char*) li.lo_crypt_name);
if (android::base::StartsWith(id, kVoldPrefix)) {
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) {
@ -314,22 +173,22 @@ int Loop::resizeImageFile(const char *file, unsigned long numSectors) {
int fd;
if ((fd = open(file, O_RDWR | O_CLOEXEC)) < 0) {
SLOGE("Error opening imagefile (%s)", strerror(errno));
PLOG(ERROR) << "Failed to open " << file;
return -1;
}
SLOGD("Attempting to increase size of %s to %lu sectors.", file, numSectors);
LOG(DEBUG) << "Attempting to increase " << file << " to " << numSectors;
if (fallocate(fd, 0, 0, numSectors * 512)) {
if (errno == ENOSYS || errno == ENOTSUP) {
SLOGW("fallocate not found. Falling back to ftruncate.");
PLOG(WARNING) << "fallocate not found. Falling back to ftruncate.";
if (ftruncate(fd, numSectors * 512) < 0) {
SLOGE("Error truncating imagefile (%s)", strerror(errno));
PLOG(ERROR) << "Failed to ftruncate";
close(fd);
return -1;
}
} else {
SLOGE("Error allocating space (%s)", strerror(errno));
PLOG(ERROR) << "Failed to fallocate";
close(fd);
return -1;
}
@ -337,46 +196,3 @@ int Loop::resizeImageFile(const char *file, unsigned long numSectors) {
close(fd);
return 0;
}
int Loop::lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned long *nr_sec) {
int fd;
struct asec_superblock buffer;
if ((fd = open(loopDevice, O_RDONLY | O_CLOEXEC)) < 0) {
SLOGE("Failed to open loopdevice (%s)", strerror(errno));
destroyByDevice(loopDevice);
return -1;
}
get_blkdev_size(fd, nr_sec);
if (*nr_sec == 0) {
SLOGE("Failed to get loop size (%s)", strerror(errno));
destroyByDevice(loopDevice);
close(fd);
return -1;
}
/*
* Try to read superblock.
*/
memset(&buffer, 0, sizeof(struct asec_superblock));
if (lseek(fd, ((*nr_sec - 1) * 512), SEEK_SET) < 0) {
SLOGE("lseek failed (%s)", strerror(errno));
close(fd);
destroyByDevice(loopDevice);
return -1;
}
if (read(fd, &buffer, sizeof(struct asec_superblock)) != sizeof(struct asec_superblock)) {
SLOGE("superblock read failed (%s)", strerror(errno));
close(fd);
destroyByDevice(loopDevice);
return -1;
}
close(fd);
/*
* Superblock successfully read. Copy to caller's struct.
*/
memcpy(sb, &buffer, sizeof(struct asec_superblock));
return 0;
}

9
Loop.h
View file

@ -21,22 +21,15 @@
#include <unistd.h>
#include <linux/loop.h>
class SocketClient;
class Loop {
public:
static const int LOOP_MAX = 4096;
public:
static int lookupActive(const char *id, char *buffer, size_t len);
static int lookupInfo(const char *loopDevice, struct asec_superblock *sb, unsigned long *nr_sec);
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);
static int dumpState(SocketClient *c);
};
#endif

View file

@ -31,8 +31,9 @@
#include <linux/dm-ioctl.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
#include <cutils/fs.h>
#include <fs_mgr.h>
#include "EncryptInplace.h"
@ -42,7 +43,6 @@
#include "Utils.h"
#include "VoldUtil.h"
extern struct fstab *fstab;
#define DM_CRYPT_BUF_SIZE 4096
#define TABLE_LOAD_RETRIES 10
#define DEFAULT_KEY_TARGET_TYPE "default-key"
@ -58,7 +58,7 @@ static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
PLOG(ERROR) << "Failed to setexeccon";
return false;
}
auto mount_rc = fs_mgr_do_mount(fstab, const_cast<char*>(mount_point),
auto mount_rc = fs_mgr_do_mount(fstab_default, const_cast<char*>(mount_point),
const_cast<char*>(blk_device), nullptr);
if (setexeccon(nullptr)) {
PLOG(ERROR) << "Failed to clear setexeccon";
@ -72,26 +72,18 @@ static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
return true;
}
static bool read_key(bool create_if_absent, KeyBuffer* key) {
auto data_rec = fs_mgr_get_crypt_entry(fstab);
if (!data_rec) {
LOG(ERROR) << "Failed to get data_rec";
return false;
}
static bool read_key(struct fstab_rec const* data_rec, bool create_if_absent, KeyBuffer* key) {
if (!data_rec->key_dir) {
LOG(ERROR) << "Failed to get key_dir";
return false;
}
LOG(DEBUG) << "key_dir: " << data_rec->key_dir;
if (!android::vold::pathExists(data_rec->key_dir)) {
if (mkdir(data_rec->key_dir, 0777) != 0) {
PLOG(ERROR) << "Unable to create: " << data_rec->key_dir;
return false;
}
LOG(DEBUG) << "Created: " << data_rec->key_dir;
}
std::string key_dir = data_rec->key_dir;
auto dir = key_dir + "/key";
LOG(DEBUG) << "key_dir/key: " << dir;
if (fs_mkdirs(dir.c_str(), 0700)) {
PLOG(ERROR) << "Creating directories: " << dir;
return false;
}
auto temp = key_dir + "/tmp";
if (!android::vold::retrieveKey(create_if_absent, dir, temp, key)) return false;
return true;
@ -104,7 +96,6 @@ static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuf
return KeyBuffer();
}
auto res = KeyBuffer() + "AES-256-XTS " + hex_key + " " + real_blkdev.c_str() + " 0";
LOG(DEBUG) << "crypt_params: " << std::string(res.data(), res.size());
return res;
}
@ -212,93 +203,33 @@ static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
return true;
}
#define DATA_PREP_TIMEOUT 1000
static bool prep_data_fs(void)
{
// NOTE: post_fs_data results in init calling back around to vold, so all
// callers to this method must be async
/* Do the prep of the /data filesystem */
property_set("vold.post_fs_data_done", "0");
property_set("vold.decrypt", "trigger_post_fs_data");
LOG(DEBUG) << "Waiting for post_fs_data_done";
/* Wait a max of 50 seconds, hopefully it takes much less */
for (int i = 0; ; i++) {
char p[PROPERTY_VALUE_MAX];
property_get("vold.post_fs_data_done", p, "0");
if (*p == '1') {
LOG(INFO) << "Successful data prep";
return true;
}
if (i + 1 == DATA_PREP_TIMEOUT) {
LOG(ERROR) << "post_fs_data timed out";
return false;
}
usleep(50000);
}
}
static void async_kick_off() {
LOG(DEBUG) << "Asynchronously restarting framework";
sleep(2); // TODO: this mirrors cryptfs, but can it be made shorter?
property_set("vold.decrypt", "trigger_load_persist_props");
if (!prep_data_fs()) return;
/* startup service classes main and late_start */
property_set("vold.decrypt", "trigger_restart_framework");
}
bool e4crypt_mount_metadata_encrypted() {
LOG(DEBUG) << "e4crypt_mount_default_encrypted";
KeyBuffer key;
if (!read_key(false, &key)) return false;
auto data_rec = fs_mgr_get_crypt_entry(fstab);
if (!data_rec) {
LOG(ERROR) << "Failed to get data_rec";
return false;
}
uint64_t nr_sec;
if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
std::string crypto_blkdev;
if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, DEFAULT_KEY_TARGET_TYPE,
default_key_params(data_rec->blk_device, key), &crypto_blkdev)) return false;
// FIXME handle the corrupt case
LOG(DEBUG) << "Restarting filesystem for metadata encryption";
mount_via_fs_mgr(data_rec->mount_point, crypto_blkdev.c_str());
std::thread(&async_kick_off).detach();
return true;
}
bool e4crypt_enable_crypto() {
LOG(DEBUG) << "e4crypt_enable_crypto";
char encrypted_state[PROPERTY_VALUE_MAX];
property_get("ro.crypto.state", encrypted_state, "");
if (strcmp(encrypted_state, "")) {
bool e4crypt_mount_metadata_encrypted(const std::string& mount_point, bool needs_encrypt) {
LOG(DEBUG) << "e4crypt_mount_metadata_encrypted: " << mount_point << " " << needs_encrypt;
auto encrypted_state = android::base::GetProperty("ro.crypto.state", "");
if (encrypted_state != "") {
LOG(DEBUG) << "e4crypt_enable_crypto got unexpected starting state: " << encrypted_state;
return false;
}
KeyBuffer key_ref;
if (!read_key(true, &key_ref)) return false;
auto data_rec = fs_mgr_get_crypt_entry(fstab);
auto data_rec = fs_mgr_get_entry_for_mount_point(fstab_default, mount_point);
if (!data_rec) {
LOG(ERROR) << "Failed to get data_rec";
return false;
}
KeyBuffer key;
if (!read_key(data_rec, needs_encrypt, &key)) return false;
uint64_t nr_sec;
if (!get_number_of_sectors(data_rec->blk_device, &nr_sec)) return false;
std::string crypto_blkdev;
if (!create_crypto_blk_dev(kDmNameUserdata, nr_sec, DEFAULT_KEY_TARGET_TYPE,
default_key_params(data_rec->blk_device, key_ref), &crypto_blkdev)) return false;
default_key_params(data_rec->blk_device, key), &crypto_blkdev))
return false;
// FIXME handle the corrupt case
if (needs_encrypt) {
LOG(INFO) << "Beginning inplace encryption, nr_sec: " << nr_sec;
off64_t size_already_done = 0;
auto rc = cryptfs_enable_inplace(const_cast<char *>(crypto_blkdev.c_str()),
data_rec->blk_device, nr_sec, &size_already_done, nr_sec, 0);
auto rc =
cryptfs_enable_inplace(const_cast<char*>(crypto_blkdev.c_str()), data_rec->blk_device,
nr_sec, &size_already_done, nr_sec, 0, false);
if (rc != 0) {
LOG(ERROR) << "Inplace crypto failed with code: " << rc;
return false;
@ -308,12 +239,9 @@ bool e4crypt_enable_crypto() {
return false;
}
LOG(INFO) << "Inplace encryption complete";
}
property_set("ro.crypto.state", "encrypted");
property_set("ro.crypto.type", "file");
LOG(DEBUG) << "Mounting metadata-encrypted filesystem:" << mount_point;
mount_via_fs_mgr(data_rec->mount_point, crypto_blkdev.c_str());
property_set("vold.decrypt", "trigger_reset_main");
std::thread(&async_kick_off).detach();
return true;
}

View file

@ -17,7 +17,8 @@
#ifndef _METADATA_CRYPT_H
#define _METADATA_CRYPT_H
bool e4crypt_mount_metadata_encrypted();
bool e4crypt_enable_crypto();
#include <string>
bool e4crypt_mount_metadata_encrypted(const std::string& mount_point, bool needs_encrypt);
#endif

View file

@ -14,22 +14,24 @@
* limitations under the License.
*/
#include "MoveTask.h"
#include "MoveStorage.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <private/android_filesystem_config.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <hardware_legacy/power.h>
#include <private/android_filesystem_config.h>
#include <thread>
#include <dirent.h>
#include <sys/wait.h>
#define CONSTRAIN(amount, low, high) ((amount) < (low) ? (low) : ((amount) > (high) ? (high) : (amount)))
#define EXEC_BLOCKING 0
static const char* kPropBlockingExec = "persist.sys.blocking_exec";
using android::base::StringPrintf;
@ -45,21 +47,12 @@ static const char* kRmPath = "/system/bin/rm";
static const char* kWakeLock = "MoveTask";
MoveTask::MoveTask(const std::shared_ptr<VolumeBase>& from,
const std::shared_ptr<VolumeBase>& to) :
mFrom(from), mTo(to) {
}
MoveTask::~MoveTask() {
}
void MoveTask::start() {
mThread = std::thread(&MoveTask::run, this);
}
static void notifyProgress(int progress) {
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(ResponseCode::MoveStatus,
StringPrintf("%d", progress).c_str(), false);
static void notifyProgress(int progress,
const android::sp<android::os::IVoldTaskListener>& listener) {
if (listener) {
android::os::PersistableBundle extras;
listener->onStatus(progress, extras);
}
}
static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd,
@ -85,8 +78,9 @@ static status_t pushBackContents(const std::string& path, std::vector<std::strin
return found ? OK : -1;
}
static status_t execRm(const std::string& path, int startProgress, int stepProgress) {
notifyProgress(startProgress);
static status_t execRm(const std::string& path, int startProgress, int stepProgress,
const android::sp<android::os::IVoldTaskListener>& listener) {
notifyProgress(startProgress, listener);
uint64_t expectedBytes = GetTreeBytes(path);
uint64_t startFreeBytes = GetFreeBytes(path);
@ -100,9 +94,10 @@ static status_t execRm(const std::string& path, int startProgress, int stepProgr
return OK;
}
#if EXEC_BLOCKING
if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
return ForkExecvp(cmd);
#else
}
pid_t pid = ForkExecvpAsync(cmd);
if (pid == -1) return -1;
@ -120,15 +115,14 @@ static status_t execRm(const std::string& path, int startProgress, int stepProgr
sleep(1);
uint64_t deltaFreeBytes = GetFreeBytes(path) - startFreeBytes;
notifyProgress(startProgress + CONSTRAIN((int)
((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress));
((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
}
return -1;
#endif
}
static status_t execCp(const std::string& fromPath, const std::string& toPath,
int startProgress, int stepProgress) {
notifyProgress(startProgress);
static status_t execCp(const std::string& fromPath, const std::string& toPath, int startProgress,
int stepProgress, const android::sp<android::os::IVoldTaskListener>& listener) {
notifyProgress(startProgress, listener);
uint64_t expectedBytes = GetTreeBytes(fromPath);
uint64_t startFreeBytes = GetFreeBytes(toPath);
@ -151,9 +145,10 @@ static status_t execCp(const std::string& fromPath, const std::string& toPath,
}
cmd.push_back(toPath.c_str());
#if EXEC_BLOCKING
if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
return ForkExecvp(cmd);
#else
}
pid_t pid = ForkExecvpAsync(cmd);
if (pid == -1) return -1;
@ -171,10 +166,9 @@ static status_t execCp(const std::string& fromPath, const std::string& toPath,
sleep(1);
uint64_t deltaFreeBytes = startFreeBytes - GetFreeBytes(toPath);
notifyProgress(startProgress + CONSTRAIN((int)
((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress));
((deltaFreeBytes * stepProgress) / expectedBytes), 0, stepProgress), listener);
}
return -1;
#endif
}
static void bringOffline(const std::shared_ptr<VolumeBase>& vol) {
@ -191,69 +185,80 @@ static void bringOnline(const std::shared_ptr<VolumeBase>& vol) {
vol->create();
}
void MoveTask::run() {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
static status_t moveStorageInternal(const std::shared_ptr<VolumeBase>& from,
const std::shared_ptr<VolumeBase>& to,
const android::sp<android::os::IVoldTaskListener>& listener) {
std::string fromPath;
std::string toPath;
// TODO: add support for public volumes
if (mFrom->getType() != VolumeBase::Type::kEmulated) goto fail;
if (mTo->getType() != VolumeBase::Type::kEmulated) goto fail;
if (from->getType() != VolumeBase::Type::kEmulated) goto fail;
if (to->getType() != VolumeBase::Type::kEmulated) goto fail;
// Step 1: tear down volumes and mount silently without making
// visible to userspace apps
{
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
bringOffline(mFrom);
bringOffline(mTo);
bringOffline(from);
bringOffline(to);
}
fromPath = mFrom->getInternalPath();
toPath = mTo->getInternalPath();
fromPath = from->getInternalPath();
toPath = to->getInternalPath();
// Step 2: clean up any stale data
if (execRm(toPath, 10, 10) != OK) {
if (execRm(toPath, 10, 10, listener) != OK) {
goto fail;
}
// Step 3: perform actual copy
if (execCp(fromPath, toPath, 20, 60) != OK) {
if (execCp(fromPath, toPath, 20, 60, listener) != OK) {
goto copy_fail;
}
// NOTE: MountService watches for this magic value to know
// that move was successful
notifyProgress(82);
notifyProgress(82, listener);
{
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
bringOnline(mFrom);
bringOnline(mTo);
bringOnline(from);
bringOnline(to);
}
// Step 4: clean up old data
if (execRm(fromPath, 85, 15) != OK) {
if (execRm(fromPath, 85, 15, listener) != OK) {
goto fail;
}
notifyProgress(kMoveSucceeded);
release_wake_lock(kWakeLock);
return;
notifyProgress(kMoveSucceeded, listener);
return OK;
copy_fail:
// if we failed to copy the data we should not leave it laying around
// in target location. Do not check return value, we can not do any
// useful anyway.
execRm(toPath, 80, 1);
execRm(toPath, 80, 1, listener);
fail:
{
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getLock());
bringOnline(mFrom);
bringOnline(mTo);
bringOnline(from);
bringOnline(to);
}
notifyProgress(kMoveFailedInternalError);
notifyProgress(kMoveFailedInternalError, listener);
return -1;
}
void MoveStorage(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to,
const android::sp<android::os::IVoldTaskListener>& listener) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
android::os::PersistableBundle extras;
status_t res = moveStorageInternal(from, to, listener);
if (listener) {
listener->onFinished(res, extras);
}
release_wake_lock(kWakeLock);
return;
}
} // namespace vold

View file

@ -14,39 +14,17 @@
* limitations under the License.
*/
#ifndef ANDROID_VOLD_TRIM_TASK_H
#define ANDROID_VOLD_TRIM_TASK_H
#ifndef ANDROID_VOLD_MOVE_STORAGE_H
#define ANDROID_VOLD_MOVE_STORAGE_H
#include "Utils.h"
#include <thread>
#include <list>
#include "android/os/IVoldTaskListener.h"
#include "model/VolumeBase.h"
namespace android {
namespace vold {
class TrimTask {
public:
explicit TrimTask(int flags);
virtual ~TrimTask();
enum Flags {
kDeepTrim = 1 << 0,
kBenchmarkAfter = 1 << 1,
};
void start();
private:
int mFlags;
std::list<std::string> mPaths;
std::thread mThread;
void addFromFstab();
void run();
DISALLOW_COPY_AND_ASSIGN(TrimTask);
};
void MoveStorage(const std::shared_ptr<VolumeBase>& from, const std::shared_ptr<VolumeBase>& to,
const android::sp<android::os::IVoldTaskListener>& listener);
} // namespace vold
} // namespace android

View file

@ -19,9 +19,7 @@
#include <errno.h>
#include <string.h>
#define LOG_TAG "Vold"
#include <cutils/log.h>
#include <android-base/logging.h>
#include <sysutils/NetlinkEvent.h>
#include "NetlinkHandler.h"
@ -47,11 +45,11 @@ void NetlinkHandler::onEvent(NetlinkEvent *evt) {
const char *subsys = evt->getSubsystem();
if (!subsys) {
SLOGW("No subsystem found in netlink event");
LOG(WARNING) << "No subsystem found in netlink event";
return;
}
if (!strcmp(subsys, "block")) {
if (std::string(subsys) == "block") {
vm->handleBlockEvent(evt);
}
}

View file

@ -26,9 +26,7 @@
#include <linux/netlink.h>
#define LOG_TAG "Vold"
#include <cutils/log.h>
#include <android-base/logging.h>
#include "NetlinkManager.h"
#include "NetlinkHandler.h"
@ -60,7 +58,7 @@ int NetlinkManager::start() {
if ((mSock = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT)) < 0) {
SLOGE("Unable to create uevent socket: %s", strerror(errno));
PLOG(ERROR) << "Unable to create uevent socket";
return -1;
}
@ -69,23 +67,23 @@ int NetlinkManager::start() {
// Try using SO_RCVBUF if that fails.
if ((setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) &&
(setsockopt(mSock, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz)) < 0)) {
SLOGE("Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option: %s", strerror(errno));
PLOG(ERROR) << "Unable to set uevent socket SO_RCVBUF/SO_RCVBUFFORCE option";
goto out;
}
if (setsockopt(mSock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) {
SLOGE("Unable to set uevent socket SO_PASSCRED option: %s", strerror(errno));
PLOG(ERROR) << "Unable to set uevent socket SO_PASSCRED option";
goto out;
}
if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
SLOGE("Unable to bind uevent socket: %s", strerror(errno));
PLOG(ERROR) << "Unable to bind uevent socket";
goto out;
}
mHandler = new NetlinkHandler(mSock);
if (mHandler->start()) {
SLOGE("Unable to start NetlinkHandler: %s", strerror(errno));
PLOG(ERROR) << "Unable to start NetlinkHandler";
goto out;
}
@ -100,7 +98,7 @@ int NetlinkManager::stop() {
int status = 0;
if (mHandler->stop()) {
SLOGE("Unable to stop NetlinkHandler: %s", strerror(errno));
PLOG(ERROR) << "Unable to stop NetlinkHandler";
status = -1;
}
delete mHandler;

5
PREUPLOAD.cfg Normal file
View file

@ -0,0 +1,5 @@
[Builtin Hooks]
clang_format = true
[Builtin Hooks Options]
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp

View file

@ -19,6 +19,7 @@
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <fts.h>
#include <dirent.h>
#include <ctype.h>
#include <pwd.h>
@ -27,196 +28,98 @@
#include <sys/stat.h>
#include <signal.h>
#define LOG_TAG "ProcessKiller"
#include <fstream>
#include <unordered_set>
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <cutils/log.h>
#include "Process.h"
using android::base::ReadFileToString;
using android::base::StringPrintf;
int Process::readSymLink(const char *path, char *link, size_t max) {
struct stat s;
int length;
namespace android {
namespace vold {
if (lstat(path, &s) < 0)
return 0;
if ((s.st_mode & S_IFMT) != S_IFLNK)
return 0;
// we have a symlink
length = readlink(path, link, max- 1);
if (length <= 0)
return 0;
link[length] = 0;
return 1;
}
int Process::pathMatchesMountPoint(const char* path, const char* mountPoint) {
int length = strlen(mountPoint);
if (length > 1 && strncmp(path, mountPoint, length) == 0) {
// we need to do extra checking if mountPoint does not end in a '/'
if (mountPoint[length - 1] == '/')
return 1;
// if mountPoint does not have a trailing slash, we need to make sure
// there is one in the path to avoid partial matches.
return (path[length] == 0 || path[length] == '/');
}
return 0;
}
void Process::getProcessName(int pid, std::string& out_name) {
if (!ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &out_name)) {
out_name = "???";
}
}
int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint) {
return checkFileDescriptorSymLinks(pid, mountPoint, NULL, 0);
}
int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max) {
// compute path to process's directory of open files
char path[PATH_MAX];
snprintf(path, sizeof(path), "/proc/%d/fd", pid);
DIR *dir = opendir(path);
if (!dir)
return 0;
// remember length of the path
int parent_length = strlen(path);
// append a trailing '/'
path[parent_length++] = '/';
struct dirent* de;
while ((de = readdir(dir))) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")
|| strlen(de->d_name) + parent_length + 1 >= PATH_MAX)
continue;
// append the file name, after truncating to parent directory
path[parent_length] = 0;
strlcat(path, de->d_name, PATH_MAX);
char link[PATH_MAX];
if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint)) {
if (openFilename) {
memset(openFilename, 0, max);
strlcpy(openFilename, link, max);
}
closedir(dir);
return 1;
static bool checkMaps(const std::string& path, const std::string& prefix) {
bool found = false;
std::ifstream infile(path);
std::string line;
while (std::getline(infile, line)) {
std::string::size_type pos = line.find('/');
if (pos != std::string::npos) {
line = line.substr(pos);
if (android::base::StartsWith(line, prefix)) {
LOG(WARNING) << "Found map " << path << " referencing " << line;
found = true;
}
}
closedir(dir);
return 0;
}
int Process::checkFileMaps(int pid, const char *mountPoint) {
return checkFileMaps(pid, mountPoint, NULL, 0);
}
int Process::checkFileMaps(int pid, const char *mountPoint, char *openFilename, size_t max) {
FILE *file;
char buffer[PATH_MAX + 100];
snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
file = fopen(buffer, "re");
if (!file)
return 0;
while (fgets(buffer, sizeof(buffer), file)) {
// skip to the path
const char* path = strchr(buffer, '/');
if (path && pathMatchesMountPoint(path, mountPoint)) {
if (openFilename) {
memset(openFilename, 0, max);
strlcpy(openFilename, path, max);
}
fclose(file);
return 1;
return found;
}
static bool checkSymlink(const std::string& path, const std::string& prefix) {
std::string res;
if (android::base::Readlink(path, &res)) {
if (android::base::StartsWith(res, prefix)) {
LOG(WARNING) << "Found symlink " << path << " referencing " << res;
return true;
}
}
fclose(file);
return 0;
return false;
}
int Process::checkSymLink(int pid, const char *mountPoint, const char *name) {
char path[PATH_MAX];
char link[PATH_MAX];
int KillProcessesWithOpenFiles(const std::string& prefix, int signal) {
std::unordered_set<pid_t> pids;
snprintf(path, sizeof(path), "/proc/%d/%s", pid, name);
if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint))
return 1;
return 0;
}
int Process::getPid(const char *s) {
int result = 0;
while (*s) {
if (!isdigit(*s)) return -1;
result = 10 * result + (*s++ - '0');
}
return result;
}
extern "C" void vold_killProcessesWithOpenFiles(const char *path, int signal) {
Process::killProcessesWithOpenFiles(path, signal);
}
/*
* Hunt down processes that have files open at the given mount point.
*/
int Process::killProcessesWithOpenFiles(const char *path, int signal) {
int count = 0;
DIR* dir;
struct dirent* de;
if (!(dir = opendir("/proc"))) {
SLOGE("opendir failed (%s)", strerror(errno));
return count;
auto proc_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir("/proc"), closedir);
if (!proc_d) {
PLOG(ERROR) << "Failed to open proc";
return -1;
}
while ((de = readdir(dir))) {
int pid = getPid(de->d_name);
if (pid == -1)
continue;
struct dirent* proc_de;
while ((proc_de = readdir(proc_d.get())) != nullptr) {
// We only care about valid PIDs
pid_t pid;
if (proc_de->d_type != DT_DIR) continue;
if (!android::base::ParseInt(proc_de->d_name, &pid)) continue;
std::string name;
getProcessName(pid, name);
// Look for references to prefix
bool found = false;
auto path = StringPrintf("/proc/%d", pid);
found |= checkMaps(path + "/maps", prefix);
found |= checkSymlink(path + "/cwd", prefix);
found |= checkSymlink(path + "/root", prefix);
found |= checkSymlink(path + "/exe", prefix);
char openfile[PATH_MAX];
if (checkFileDescriptorSymLinks(pid, path, openfile, sizeof(openfile))) {
SLOGE("Process %s (%d) has open file %s", name.c_str(), pid, openfile);
} else if (checkFileMaps(pid, path, openfile, sizeof(openfile))) {
SLOGE("Process %s (%d) has open filemap for %s", name.c_str(), pid, openfile);
} else if (checkSymLink(pid, path, "cwd")) {
SLOGE("Process %s (%d) has cwd within %s", name.c_str(), pid, path);
} else if (checkSymLink(pid, path, "root")) {
SLOGE("Process %s (%d) has chroot within %s", name.c_str(), pid, path);
} else if (checkSymLink(pid, path, "exe")) {
SLOGE("Process %s (%d) has executable path within %s", name.c_str(), pid, path);
auto fd_path = path + "/fd";
auto fd_d = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(fd_path.c_str()), closedir);
if (!fd_d) {
PLOG(WARNING) << "Failed to open " << fd_path;
} else {
continue;
struct dirent* fd_de;
while ((fd_de = readdir(fd_d.get())) != nullptr) {
if (fd_de->d_type != DT_LNK) continue;
found |= checkSymlink(fd_path + "/" + fd_de->d_name, prefix);
}
}
if (found) {
pids.insert(pid);
}
}
if (signal != 0) {
SLOGW("Sending %s to process %d", strsignal(signal), pid);
for (const auto& pid : pids) {
LOG(WARNING) << "Sending " << strsignal(signal) << " to " << pid;
kill(pid, signal);
count++;
}
}
closedir(dir);
return count;
return pids.size();
}
} // namespace vold
} // namespace android

View file

@ -17,28 +17,12 @@
#ifndef _PROCESS_H
#define _PROCESS_H
#ifdef __cplusplus
namespace android {
namespace vold {
class Process {
public:
static int killProcessesWithOpenFiles(const char *path, int signal);
static int getPid(const char *s);
static int checkSymLink(int pid, const char *path, const char *name);
static int checkFileMaps(int pid, const char *path);
static int checkFileMaps(int pid, const char *path, char *openFilename, size_t max);
static int checkFileDescriptorSymLinks(int pid, const char *mountPoint);
static int checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max);
static void getProcessName(int pid, std::string& out_name);
private:
static int readSymLink(const char *path, char *link, size_t max);
static int pathMatchesMountPoint(const char *path, const char *mountPoint);
};
int KillProcessesWithOpenFiles(const std::string& path, int signal);
extern "C" {
#endif /* __cplusplus */
void vold_killProcessesWithOpenFiles(const char *path, int signal);
#ifdef __cplusplus
}
#endif
} // namespace vold
} // namespace android
#endif

View file

@ -1,42 +0,0 @@
/*
* Copyright (C) 2008 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 <stdio.h>
#include <errno.h>
#include <string.h>
#define LOG_TAG "Vold"
#include <cutils/log.h>
#include "ResponseCode.h"
int ResponseCode::convertFromErrno() {
if (errno == ENODEV) {
return(ResponseCode::OpFailedNoMedia);
} else if (errno == ENODATA) {
return(ResponseCode::OpFailedMediaBlank);
} else if (errno == EIO) {
return(ResponseCode::OpFailedMediaCorrupt);
} else if (errno == EBUSY) {
return(ResponseCode::OpFailedStorageBusy);
} else if (errno == ENOENT) {
return(ResponseCode::OpFailedStorageNotFound);
}
SLOGW("Returning OperationFailed - no handler for errno %d", errno);
return(ResponseCode::OperationFailed);
}

View file

@ -1,91 +0,0 @@
/*
* Copyright (C) 2008 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 _RESPONSECODE_H
#define _RESPONSECODE_H
class ResponseCode {
public:
// 100 series - Requestion action was initiated; expect another reply
// before proceeding with a new command.
static const int ActionInitiated = 100;
static const int VolumeListResult = 110;
static const int AsecListResult = 111;
static const int StorageUsersListResult = 112;
static const int CryptfsGetfieldResult = 113;
// 200 series - Requested action has been successfully completed
static const int CommandOkay = 200;
static const int ShareStatusResult = 210;
static const int AsecPathResult = 211;
static const int ShareEnabledResult = 212;
static const int PasswordTypeResult = 213;
// 400 series - The command was accepted but the requested action
// did not take place.
static const int OperationFailed = 400;
static const int OpFailedNoMedia = 401;
static const int OpFailedMediaBlank = 402;
static const int OpFailedMediaCorrupt = 403;
static const int OpFailedVolNotMounted = 404;
static const int OpFailedStorageBusy = 405;
static const int OpFailedStorageNotFound = 406;
// 500 series - The command was not accepted and the requested
// action did not take place.
static const int CommandSyntaxError = 500;
static const int CommandParameterError = 501;
static const int CommandNoPermission = 502;
// 600 series - Unsolicited broadcasts
static const int UnsolicitedInformational = 600;
static const int VolumeStateChange = 605;
static const int VolumeMountFailedBlank = 610;
static const int VolumeMountFailedDamaged = 611;
static const int VolumeMountFailedNoMedia = 612;
static const int VolumeUuidChange = 613;
static const int VolumeUserLabelChange = 614;
static const int ShareAvailabilityChange = 620;
static const int VolumeDiskInserted = 630;
static const int VolumeDiskRemoved = 631;
static const int VolumeBadRemoval = 632;
static const int DiskCreated = 640;
static const int DiskSizeChanged = 641;
static const int DiskLabelChanged = 642;
static const int DiskScanned = 643;
static const int DiskSysPathChanged = 644;
static const int DiskDestroyed = 649;
static const int VolumeCreated = 650;
static const int VolumeStateChanged = 651;
static const int VolumeFsTypeChanged = 652;
static const int VolumeFsUuidChanged = 653;
static const int VolumeFsLabelChanged = 654;
static const int VolumePathChanged = 655;
static const int VolumeInternalPathChanged = 656;
static const int VolumeDestroyed = 659;
static const int MoveStatus = 660;
static const int BenchmarkResult = 661;
static const int TrimResult = 662;
static int convertFromErrno();
};
#endif

View file

@ -23,10 +23,6 @@
#define SCRYPT_PROP "ro.crypto.scrypt_params"
#define SCRYPT_DEFAULTS "15:3:1"
__BEGIN_DECLS
bool parse_scrypt_parameters(const char* paramstr, int *Nf, int *rf, int *pf);
__END_DECLS
#endif

View file

@ -1,151 +0,0 @@
/*
* Copyright (C) 2015 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 "TrimTask.h"
#include "Benchmark.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <cutils/properties.h>
#include <fs_mgr.h>
#include <private/android_filesystem_config.h>
#include <hardware_legacy/power.h>
#include <dirent.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#define BENCHMARK_ENABLED 1
using android::base::StringPrintf;
namespace android {
namespace vold {
static const char* kWakeLock = "TrimTask";
TrimTask::TrimTask(int flags) : mFlags(flags) {
// Collect both fstab and vold volumes
addFromFstab();
VolumeManager* vm = VolumeManager::Instance();
std::list<std::string> privateIds;
vm->listVolumes(VolumeBase::Type::kPrivate, privateIds);
for (const auto& id : privateIds) {
auto vol = vm->findVolume(id);
if (vol != nullptr && vol->getState() == VolumeBase::State::kMounted) {
mPaths.push_back(vol->getPath());
}
}
}
TrimTask::~TrimTask() {
}
void TrimTask::addFromFstab() {
std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
fs_mgr_free_fstab);
struct fstab_rec *prev_rec = NULL;
for (int i = 0; i < fstab->num_entries; i++) {
/* Skip raw partitions */
if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
!strcmp(fstab->recs[i].fs_type, "mtd")) {
continue;
}
/* Skip read-only filesystems */
if (fstab->recs[i].flags & MS_RDONLY) {
continue;
}
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
continue; /* Should we trim fat32 filesystems? */
}
if (fs_mgr_is_notrim(&fstab->recs[i])) {
continue;
}
/* Skip the multi-type partitions, which are required to be following each other.
* See fs_mgr.c's mount_with_alternatives().
*/
if (prev_rec && !strcmp(prev_rec->mount_point, fstab->recs[i].mount_point)) {
continue;
}
mPaths.push_back(fstab->recs[i].mount_point);
prev_rec = &fstab->recs[i];
}
}
void TrimTask::start() {
mThread = std::thread(&TrimTask::run, this);
}
static void notifyResult(const std::string& path, int64_t bytes, int64_t delta) {
std::string res(path
+ " " + std::to_string(bytes)
+ " " + std::to_string(delta));
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(
ResponseCode::TrimResult, res.c_str(), false);
}
void TrimTask::run() {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock);
for (const auto& path : mPaths) {
LOG(DEBUG) << "Starting trim of " << path;
int fd = open(path.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
if (fd < 0) {
PLOG(WARNING) << "Failed to open " << path;
continue;
}
struct fstrim_range range;
memset(&range, 0, sizeof(range));
range.len = ULLONG_MAX;
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
if (ioctl(fd, FITRIM, &range)) {
PLOG(WARNING) << "Trim failed on " << path;
notifyResult(path, -1, -1);
} else {
nsecs_t delta = systemTime(SYSTEM_TIME_BOOTTIME) - start;
LOG(INFO) << "Trimmed " << range.len << " bytes on " << path
<< " in " << nanoseconds_to_milliseconds(delta) << "ms";
notifyResult(path, range.len, delta);
}
close(fd);
if (mFlags & Flags::kBenchmarkAfter) {
#if BENCHMARK_ENABLED
BenchmarkPrivate(path);
#else
LOG(DEBUG) << "Benchmark disabled";
#endif
}
}
release_wake_lock(kWakeLock);
}
} // namespace vold
} // namespace android

172
Utils.cpp
View file

@ -14,14 +14,15 @@
* limitations under the License.
*/
#include "sehandle.h"
#include "Utils.h"
#include "Process.h"
#include "VolumeManager.h"
#include "sehandle.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <logwrap/logwrap.h>
@ -54,12 +55,19 @@ security_context_t sBlkidUntrustedContext = nullptr;
security_context_t sFsckContext = nullptr;
security_context_t sFsckUntrustedContext = nullptr;
bool sSleepOnUnmount = true;
static const char* kBlkidPath = "/system/bin/blkid";
static const char* kKeyPath = "/data/misc/vold";
static const char* kProcFilesystems = "/proc/filesystems";
// Lock used to protect process-level SELinux changes from racing with each
// other between multiple threads.
static std::mutex kSecurityLock;
status_t CreateDeviceNode(const std::string& path, dev_t dev) {
std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
status_t res = 0;
@ -97,6 +105,7 @@ status_t DestroyDeviceNode(const std::string& path) {
}
status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
char* secontext = nullptr;
@ -127,22 +136,22 @@ status_t ForceUnmount(const std::string& path) {
}
// Apps might still be handling eject request, so wait before
// we start sending signals
if (!VolumeManager::shutting_down) sleep(5);
if (sSleepOnUnmount) sleep(5);
Process::killProcessesWithOpenFiles(cpath, SIGINT);
if (!VolumeManager::shutting_down) sleep(5);
KillProcessesWithOpenFiles(path, SIGINT);
if (sSleepOnUnmount) sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
Process::killProcessesWithOpenFiles(cpath, SIGTERM);
if (!VolumeManager::shutting_down) sleep(5);
KillProcessesWithOpenFiles(path, SIGTERM);
if (sSleepOnUnmount) sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
Process::killProcessesWithOpenFiles(cpath, SIGKILL);
if (!VolumeManager::shutting_down) sleep(5);
KillProcessesWithOpenFiles(path, SIGKILL);
if (sSleepOnUnmount) sleep(5);
if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) {
return OK;
}
@ -151,25 +160,24 @@ status_t ForceUnmount(const std::string& path) {
}
status_t KillProcessesUsingPath(const std::string& path) {
const char* cpath = path.c_str();
if (Process::killProcessesWithOpenFiles(cpath, SIGINT) == 0) {
if (KillProcessesWithOpenFiles(path, SIGINT) == 0) {
return OK;
}
if (!VolumeManager::shutting_down) sleep(5);
if (sSleepOnUnmount) sleep(5);
if (Process::killProcessesWithOpenFiles(cpath, SIGTERM) == 0) {
if (KillProcessesWithOpenFiles(path, SIGTERM) == 0) {
return OK;
}
if (!VolumeManager::shutting_down) sleep(5);
if (sSleepOnUnmount) sleep(5);
if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
return OK;
}
if (!VolumeManager::shutting_down) sleep(5);
if (sSleepOnUnmount) sleep(5);
// Send SIGKILL a second time to determine if we've
// actually killed everyone with open files
if (Process::killProcessesWithOpenFiles(cpath, SIGKILL) == 0) {
if (KillProcessesWithOpenFiles(path, SIGKILL) == 0) {
return OK;
}
PLOG(ERROR) << "Failed to kill processes using " << path;
@ -184,11 +192,28 @@ status_t BindMount(const std::string& source, const std::string& target) {
return OK;
}
static status_t readMetadata(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel, bool untrusted) {
fsType.clear();
fsUuid.clear();
fsLabel.clear();
bool FindValue(const std::string& raw, const std::string& key, std::string* value) {
auto qual = key + "=\"";
auto start = raw.find(qual);
if (start > 0 && raw[start - 1] != ' ') {
start = raw.find(qual, start + 1);
}
if (start == std::string::npos) return false;
start += qual.length();
auto end = raw.find("\"", start);
if (end == std::string::npos) return false;
*value = raw.substr(start, end - start);
return true;
}
static status_t readMetadata(const std::string& path, std::string* fsType,
std::string* fsUuid, std::string* fsLabel, bool untrusted) {
fsType->clear();
fsUuid->clear();
fsLabel->clear();
std::vector<std::string> cmd;
cmd.push_back(kBlkidPath);
@ -209,36 +234,23 @@ static status_t readMetadata(const std::string& path, std::string& fsType,
return res;
}
char value[128];
for (const auto& line : output) {
// Extract values from blkid output, if defined
const char* cline = line.c_str();
const char* start = strstr(cline, "TYPE=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsType = value;
}
start = strstr(cline, "UUID=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsUuid = value;
}
start = strstr(cline, "LABEL=");
if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
fsLabel = value;
}
FindValue(line, "TYPE", fsType);
FindValue(line, "UUID", fsUuid);
FindValue(line, "LABEL", fsLabel);
}
return OK;
}
status_t ReadMetadata(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel) {
status_t ReadMetadata(const std::string& path, std::string* fsType,
std::string* fsUuid, std::string* fsLabel) {
return readMetadata(path, fsType, fsUuid, fsLabel, false);
}
status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel) {
status_t ReadMetadataUntrusted(const std::string& path, std::string* fsType,
std::string* fsUuid, std::string* fsLabel) {
return readMetadata(path, fsType, fsUuid, fsLabel, true);
}
@ -247,6 +259,7 @@ status_t ForkExecvp(const std::vector<std::string>& args) {
}
status_t ForkExecvp(const std::vector<std::string>& args, security_context_t context) {
std::lock_guard<std::mutex> lock(kSecurityLock);
size_t argc = args.size();
char** argv = (char**) calloc(argc, sizeof(char*));
for (size_t i = 0; i < argc; i++) {
@ -258,15 +271,19 @@ status_t ForkExecvp(const std::vector<std::string>& args, security_context_t con
}
}
if (context) {
if (setexeccon(context)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
}
status_t res = android_fork_execvp(argc, argv, NULL, false, true);
if (context) {
if (setexeccon(nullptr)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
}
free(argv);
return res;
@ -279,6 +296,7 @@ status_t ForkExecvp(const std::vector<std::string>& args,
status_t ForkExecvp(const std::vector<std::string>& args,
std::vector<std::string>& output, security_context_t context) {
std::lock_guard<std::mutex> lock(kSecurityLock);
std::string cmd;
for (size_t i = 0; i < args.size(); i++) {
cmd += args[i] + " ";
@ -290,15 +308,19 @@ status_t ForkExecvp(const std::vector<std::string>& args,
}
output.clear();
if (context) {
if (setexeccon(context)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
}
FILE* fp = popen(cmd.c_str(), "r"); // NOLINT
if (context) {
if (setexeccon(nullptr)) {
LOG(ERROR) << "Failed to setexeccon";
abort();
}
}
if (!fp) {
PLOG(ERROR) << "Failed to popen " << cmd;
@ -583,54 +605,62 @@ std::string BuildKeyPath(const std::string& partGuid) {
}
std::string BuildDataSystemLegacyPath(userid_t userId) {
return StringPrintf("%s/system/users/%u", BuildDataPath(nullptr).c_str(), userId);
return StringPrintf("%s/system/users/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataSystemCePath(userid_t userId) {
return StringPrintf("%s/system_ce/%u", BuildDataPath(nullptr).c_str(), userId);
return StringPrintf("%s/system_ce/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataSystemDePath(userid_t userId) {
return StringPrintf("%s/system_de/%u", BuildDataPath(nullptr).c_str(), userId);
return StringPrintf("%s/system_de/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataMiscLegacyPath(userid_t userId) {
return StringPrintf("%s/misc/user/%u", BuildDataPath(nullptr).c_str(), userId);
return StringPrintf("%s/misc/user/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataMiscCePath(userid_t userId) {
return StringPrintf("%s/misc_ce/%u", BuildDataPath(nullptr).c_str(), userId);
return StringPrintf("%s/misc_ce/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataMiscDePath(userid_t userId) {
return StringPrintf("%s/misc_de/%u", BuildDataPath(nullptr).c_str(), userId);
return StringPrintf("%s/misc_de/%u", BuildDataPath("").c_str(), userId);
}
// Keep in sync with installd (frameworks/native/cmds/installd/utils.h)
std::string BuildDataProfilesDePath(userid_t userId) {
return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath(nullptr).c_str(), userId);
return StringPrintf("%s/misc/profiles/cur/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataPath(const char* volumeUuid) {
std::string BuildDataVendorCePath(userid_t userId) {
return StringPrintf("%s/vendor_ce/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataVendorDePath(userid_t userId) {
return StringPrintf("%s/vendor_de/%u", BuildDataPath("").c_str(), userId);
}
std::string BuildDataPath(const std::string& volumeUuid) {
// TODO: unify with installd path generation logic
if (volumeUuid == nullptr) {
if (volumeUuid.empty()) {
return "/data";
} else {
CHECK(isValidFilename(volumeUuid));
return StringPrintf("/mnt/expand/%s", volumeUuid);
return StringPrintf("/mnt/expand/%s", volumeUuid.c_str());
}
}
std::string BuildDataMediaCePath(const char* volumeUuid, userid_t userId) {
std::string BuildDataMediaCePath(const std::string& volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
return StringPrintf("%s/media/%u", data.c_str(), userId);
}
std::string BuildDataUserCePath(const char* volumeUuid, userid_t userId) {
std::string BuildDataUserCePath(const std::string& volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
if (volumeUuid == nullptr && userId == 0) {
if (volumeUuid.empty() && userId == 0) {
std::string legacy = StringPrintf("%s/data", data.c_str());
struct stat sb;
if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
@ -641,7 +671,7 @@ std::string BuildDataUserCePath(const char* volumeUuid, userid_t userId) {
return StringPrintf("%s/user/%u", data.c_str(), userId);
}
std::string BuildDataUserDePath(const char* volumeUuid, userid_t userId) {
std::string BuildDataUserDePath(const std::string& volumeUuid, userid_t userId) {
// TODO: unify with installd path generation logic
std::string data(BuildDataPath(volumeUuid));
return StringPrintf("%s/user_de/%u", data.c_str(), userId);
@ -671,15 +701,27 @@ status_t RestoreconRecursive(const std::string& path) {
return OK;
}
status_t SaneReadLinkAt(int dirfd, const char* path, char* buf, size_t bufsiz) {
ssize_t len = readlinkat(dirfd, path, buf, bufsiz);
if (len < 0) {
return -1;
} else if (len == (ssize_t) bufsiz) {
return -1;
} else {
buf[len] = '\0';
return 0;
bool Readlinkat(int dirfd, const std::string& path, std::string* result) {
// Shamelessly borrowed from android::base::Readlink()
result->clear();
// Most Linux file systems (ext2 and ext4, say) limit symbolic links to
// 4095 bytes. Since we'll copy out into the string anyway, it doesn't
// waste memory to just start there. We add 1 so that we can recognize
// whether it actually fit (rather than being truncated to 4095).
std::vector<char> buf(4095 + 1);
while (true) {
ssize_t size = readlinkat(dirfd, path.c_str(), &buf[0], buf.size());
// Unrecoverable error?
if (size == -1)
return false;
// It fit! (If size == buf.size(), it may have been truncated.)
if (static_cast<size_t>(size) < buf.size()) {
result->assign(&buf[0], size);
return true;
}
// Double our buffer and try again.
buf.resize(buf.size() * 2);
}
}

35
Utils.h
View file

@ -19,6 +19,7 @@
#include "KeyBuffer.h"
#include <android-base/macros.h>
#include <utils/Errors.h>
#include <cutils/multiuser.h>
#include <selinux/selinux.h>
@ -26,14 +27,6 @@
#include <vector>
#include <string>
// DISALLOW_COPY_AND_ASSIGN disallows the copy and operator= functions. It goes in the private:
// declarations in a class.
#if !defined(DISALLOW_COPY_AND_ASSIGN)
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#endif
struct DIR;
namespace android {
@ -45,6 +38,9 @@ extern security_context_t sBlkidUntrustedContext;
extern security_context_t sFsckContext;
extern security_context_t sFsckUntrustedContext;
// TODO remove this with better solution, b/64143519
extern bool sSleepOnUnmount;
status_t CreateDeviceNode(const std::string& path, dev_t dev);
status_t DestroyDeviceNode(const std::string& path);
@ -60,13 +56,15 @@ status_t KillProcessesUsingPath(const std::string& path);
/* Creates bind mount from source to target */
status_t BindMount(const std::string& source, const std::string& target);
bool FindValue(const std::string& raw, const std::string& key, std::string* value);
/* Reads filesystem metadata from device at path */
status_t ReadMetadata(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel);
status_t ReadMetadata(const std::string& path, std::string* fsType,
std::string* fsUuid, std::string* fsLabel);
/* Reads filesystem metadata from untrusted device at path */
status_t ReadMetadataUntrusted(const std::string& path, std::string& fsType,
std::string& fsUuid, std::string& fsLabel);
status_t ReadMetadataUntrusted(const std::string& path, std::string* fsType,
std::string* fsUuid, std::string* fsLabel);
/* Returns either WEXITSTATUS() status, or a negative errno */
status_t ForkExecvp(const std::vector<std::string>& args);
@ -109,17 +107,20 @@ std::string BuildDataMiscLegacyPath(userid_t userid);
std::string BuildDataMiscCePath(userid_t userid);
std::string BuildDataMiscDePath(userid_t userid);
std::string BuildDataProfilesDePath(userid_t userid);
std::string BuildDataVendorCePath(userid_t userid);
std::string BuildDataVendorDePath(userid_t userid);
std::string BuildDataPath(const char* volumeUuid);
std::string BuildDataMediaCePath(const char* volumeUuid, userid_t userid);
std::string BuildDataUserCePath(const char* volumeUuid, userid_t userid);
std::string BuildDataUserDePath(const char* volumeUuid, userid_t userid);
std::string BuildDataPath(const std::string& volumeUuid);
std::string BuildDataMediaCePath(const std::string& volumeUuid, userid_t userid);
std::string BuildDataUserCePath(const std::string& volumeUuid, userid_t userid);
std::string BuildDataUserDePath(const std::string& volumeUuid, userid_t userid);
dev_t GetDevice(const std::string& path);
status_t RestoreconRecursive(const std::string& path);
status_t SaneReadLinkAt(int dirfd, const char* path, char* buf, size_t bufsiz);
// TODO: promote to android::base
bool Readlinkat(int dirfd, const std::string& path, std::string* result);
/* Checks if Android is running in QEMU */
bool IsRunningInEmulator();

763
VoldNativeService.cpp Normal file
View file

@ -0,0 +1,763 @@
/*
* 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.
*/
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
#include "VoldNativeService.h"
#include "Benchmark.h"
#include "CheckEncryption.h"
#include "IdleMaint.h"
#include "MoveStorage.h"
#include "Process.h"
#include "VolumeManager.h"
#include "cryptfs.h"
#include "Ext4Crypt.h"
#include "MetadataCrypt.h"
#include <fstream>
#include <thread>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <ext4_utils/ext4_crypt.h>
#include <fs_mgr.h>
#include <private/android_filesystem_config.h>
#include <utils/Trace.h>
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()));
}
if ((path + '/').find("/../") != std::string::npos) {
return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
StringPrintf("Path %s is shady", 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()); \
ATRACE_CALL();
#define ACQUIRE_CRYPT_LOCK \
std::lock_guard<std::mutex> lock(VolumeManager::Instance()->getCryptLock()); \
ATRACE_CALL();
} // 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::setListener(
const android::sp<android::os::IVoldListener>& listener) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
VolumeManager::Instance()->setListener(listener);
return ok();
}
binder::Status VoldNativeService::monitor() {
ENFORCE_UID(AID_SYSTEM);
// Simply acquire/release each lock for watchdog
{
ACQUIRE_LOCK;
}
{
ACQUIRE_CRYPT_LOCK;
}
return ok();
}
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::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::onSecureKeyguardStateChanged(bool isShowing) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
return translate(VolumeManager::Instance()->onSecureKeyguardStateChanged(isShowing));
}
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,
const std::string& fsUuid) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_HEX(partGuid);
CHECK_ARGUMENT_HEX(fsUuid);
ACQUIRE_LOCK;
return translate(VolumeManager::Instance()->forgetPartition(partGuid, fsUuid));
}
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));
}
static binder::Status pathForVolId(const std::string& volId, std::string* path) {
if (volId == "private" || volId == "null") {
*path = "/data";
} else {
auto vol = VolumeManager::Instance()->findVolume(volId);
if (vol == nullptr) {
return error("Failed to find volume " + volId);
}
if (vol->getType() != VolumeBase::Type::kPrivate) {
return error("Volume " + volId + " not private");
}
if (vol->getState() != VolumeBase::State::kMounted) {
return error("Volume " + volId + " not mounted");
}
*path = vol->getPath();
if (path->empty()) {
return error("Volume " + volId + " missing path");
}
}
return ok();
}
binder::Status VoldNativeService::benchmark(
const std::string& volId, const android::sp<android::os::IVoldTaskListener>& listener) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_ID(volId);
ACQUIRE_LOCK;
std::string path;
auto status = pathForVolId(volId, &path);
if (!status.isOk()) return status;
std::thread([=]() {
android::vold::Benchmark(path, listener);
}).detach();
return ok();
}
binder::Status VoldNativeService::checkEncryption(const std::string& volId) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_ID(volId);
ACQUIRE_LOCK;
std::string path;
auto status = pathForVolId(volId, &path);
if (!status.isOk()) return status;
return translate(android::vold::CheckEncryption(path));
}
binder::Status VoldNativeService::moveStorage(const std::string& fromVolId,
const std::string& toVolId, const android::sp<android::os::IVoldTaskListener>& listener) {
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);
}
std::thread([=]() {
android::vold::MoveStorage(fromVol, toVol, listener);
}).detach();
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));
}
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,
const android::sp<android::os::IVoldTaskListener>& listener) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
std::thread([=]() {
android::vold::Trim(listener);
}).detach();
return ok();
}
binder::Status VoldNativeService::runIdleMaint(
const android::sp<android::os::IVoldTaskListener>& listener) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
std::thread([=]() {
android::vold::RunIdleMaint(listener);
}).detach();
return ok();
}
binder::Status VoldNativeService::abortIdleMaint(
const android::sp<android::os::IVoldTaskListener>& listener) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
std::thread([=]() {
android::vold::AbortIdleMaint(listener);
}).detach();
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;
for (int tries = 0; tries < 2; ++tries) {
int rc;
if (passwordType == VoldNativeService::PASSWORD_TYPE_DEFAULT) {
rc = cryptfs_enable_default(noUi);
} else {
rc = cryptfs_enable(passwordType, password.c_str(), noUi);
}
if (rc == 0) {
return 0;
} else if (tries == 0) {
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;
LOG(DEBUG) << "fdeEnable(" << passwordType << ", *, " << encryptionFlags << ")";
if (e4crypt_is_native()) {
LOG(ERROR) << "e4crypt_is_native, fdeEnable invalid";
return error("e4crypt_is_native, fdeEnable invalid");
}
LOG(DEBUG) << "!e4crypt_is_native, spawning fdeEnableInternal";
// 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()) {
// 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::mountFstab(const std::string& mountPoint) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
return translateBool(e4crypt_mount_metadata_encrypted(mountPoint, false));
}
binder::Status VoldNativeService::encryptFstab(const std::string& mountPoint) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
return translateBool(e4crypt_mount_metadata_encrypted(mountPoint, true));
}
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, secret));
}
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, secret));
}
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);
std::string empty_string = "";
auto uuid_ = uuid ? *uuid : empty_string;
CHECK_ARGUMENT_HEX(uuid_);
ACQUIRE_CRYPT_LOCK;
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);
std::string empty_string = "";
auto uuid_ = uuid ? *uuid : empty_string;
CHECK_ARGUMENT_HEX(uuid_);
ACQUIRE_CRYPT_LOCK;
return translateBool(e4crypt_destroy_user_storage(uuid_, userId, flags));
}
} // namespace vold
} // namespace android

121
VoldNativeService.h Normal file
View file

@ -0,0 +1,121 @@
/*
* 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 setListener(const android::sp<android::os::IVoldListener>& listener);
binder::Status monitor();
binder::Status reset();
binder::Status shutdown();
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 onSecureKeyguardStateChanged(bool isShowing);
binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio);
binder::Status forgetPartition(const std::string& partGuid, const std::string& fsUuid);
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,
const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status checkEncryption(const std::string& volId);
binder::Status moveStorage(const std::string& fromVolId, const std::string& toVolId,
const android::sp<android::os::IVoldTaskListener>& listener);
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,
const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status runIdleMaint(
const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status abortIdleMaint(
const android::sp<android::os::IVoldTaskListener>& listener);
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 mountFstab(const std::string& mountPoint);
binder::Status encryptFstab(const std::string& mountPoint);
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);
};
} // namespace vold
} // namespace android
#endif // _VOLD_NATIVE_SERVICE_H_

View file

@ -17,6 +17,8 @@
#include <sys/ioctl.h>
#include <linux/fs.h>
struct fstab *fstab_default;
void get_blkdev_size(int fd, unsigned long* nr_sec) {
if ((ioctl(fd, BLKGETSIZE, nr_sec)) == -1) {
*nr_sec = 0;

View file

@ -17,12 +17,13 @@
#ifndef _VOLDUTIL_H
#define _VOLDUTIL_H
#include <fstab/fstab.h>
#include <sys/cdefs.h>
extern struct fstab *fstab_default;
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
__BEGIN_DECLS
void get_blkdev_size(int fd, unsigned long* nr_sec);
__END_DECLS
#endif

File diff suppressed because it is too large Load diff

View file

@ -21,76 +21,40 @@
#include <fnmatch.h>
#include <stdlib.h>
#ifdef __cplusplus
#include <list>
#include <mutex>
#include <string>
#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 "android/os/IVoldListener.h"
/* The length of an MD5 hash when encoded into ASCII hex characters */
#define MD5_ASCII_LENGTH_PLUS_NULL ((MD5_DIGEST_LENGTH*2)+1)
#include "model/Disk.h"
#include "model/VolumeBase.h"
typedef enum { ASEC, OBB } container_type_t;
class ContainerData {
public:
ContainerData(char* _id, container_type_t _type)
: id(_id)
, type(_type)
{}
~ContainerData() {
if (id != NULL) {
free(id);
id = NULL;
}
}
char *id;
container_type_t type;
};
typedef android::List<ContainerData*> AsecIdCollection;
#define DEBUG_APPFUSE 0
class VolumeManager {
public:
static const char *SEC_ASECDIR_EXT;
static const char *SEC_ASECDIR_INT;
static const char *ASECDIR;
static const char *LOOPDIR;
//TODO remove this with better solution, b/64143519
static bool shutting_down;
private:
static VolumeManager *sInstance;
SocketListener *mBroadcaster;
AsecIdCollection *mActiveContainers;
bool mDebug;
// for adjusting /proc/sys/vm/dirty_ratio when UMS is active
int mUmsSharingCount;
int mSavedDirtyRatio;
int mUmsDirtyRatio;
public:
virtual ~VolumeManager();
// TODO: pipe all requests through VM to avoid exposing this lock
std::mutex& getLock() { return mLock; }
std::mutex& getCryptLock() { return mCryptLock; }
void setListener(android::sp<android::os::IVoldListener> listener) { mListener = listener; }
android::sp<android::os::IVoldListener> getListener() { return mListener; }
int start();
int stop();
@ -123,15 +87,15 @@ public:
void listVolumes(android::vold::VolumeBase::Type type, std::list<std::string>& list);
nsecs_t benchmarkPrivate(const std::string& id);
int forgetPartition(const std::string& partGuid);
int forgetPartition(const std::string& partGuid, const std::string& fsUuid);
int onUserAdded(userid_t userId, int userSerialNumber);
int onUserRemoved(userid_t userId);
int onUserStarted(userid_t userId);
int onUserStopped(userid_t userId);
int onSecureKeyguardStateChanged(bool isShowing);
int setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol);
int remountUid(uid_t uid, const std::string& mode);
@ -143,52 +107,11 @@ public:
/* Unmount all volumes, usually for encryption */
int unmountAll();
/* ASEC */
int findAsec(const char *id, char *asecPath = NULL, size_t asecPathLen = 0,
const char **directory = NULL) const;
int createAsec(const char *id, unsigned long numSectors, const char *fstype,
const char *key, const int ownerUid, bool isExternal);
int resizeAsec(const char *id, unsigned long numSectors, const char *key);
int finalizeAsec(const char *id);
/**
* Fixes ASEC permissions on a filesystem that has owners and permissions.
* This currently means EXT4-based ASEC containers.
*
* There is a single file that can be marked as "private" and will not have
* world-readable permission. The group for that file will be set to the gid
* supplied.
*
* Returns 0 on success.
*/
int fixupAsecPermissions(const char *id, gid_t gid, const char* privateFilename);
int destroyAsec(const char *id, bool force);
int mountAsec(const char *id, const char *key, int ownerUid, bool readOnly);
int unmountAsec(const char *id, bool force);
int renameAsec(const char *id1, const char *id2);
int getAsecMountPath(const char *id, char *buffer, int maxlen);
int getAsecFilesystemPath(const char *id, char *buffer, int maxlen);
/* Loopback images */
int listMountedObbs(SocketClient* cli);
int mountObb(const char *fileName, const char *key, int ownerUid);
int unmountObb(const char *fileName, bool force);
int getObbMountPath(const char *id, char *buffer, int maxlen);
/* Shared between ASEC and Loopback images */
int unmountLoopImage(const char *containerId, const char *loopId,
const char *fileName, const char *mountPoint, bool force);
int updateVirtualDisk();
int setDebug(bool enable);
void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; }
SocketListener *getBroadcaster() { return mBroadcaster; }
static VolumeManager *Instance();
static char *asecHash(const char *id, char *buffer, size_t len);
/*
* Ensure that all directories along given path exist, creating parent
* directories as needed. Validates that given path is absolute and that
@ -196,21 +119,34 @@ public:
* 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 std::string& 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();
void readInitialState();
bool isMountpointMounted(const char *mp);
bool isAsecInDirectory(const char *dir, const char *asec) const;
bool isLegalAsecId(const char *id) const;
int linkPrimary(userid_t userId);
void handleDiskAdded(const std::shared_ptr<android::vold::Disk>& disk);
void handleDiskChanged(dev_t device);
void handleDiskRemoved(dev_t device);
std::mutex mLock;
std::mutex mCryptLock;
android::sp<android::os::IVoldListener> mListener;
std::list<std::shared_ptr<DiskSource>> mDiskSources;
std::list<std::shared_ptr<android::vold::Disk>> mDisks;
std::list<std::shared_ptr<android::vold::Disk>> mPendingDisks;
std::list<std::shared_ptr<android::vold::VolumeBase>> mObbVolumes;
std::unordered_map<userid_t, int> mAddedUsers;
std::unordered_set<userid_t> mStartedUsers;
@ -219,14 +155,9 @@ private:
std::shared_ptr<android::vold::Disk> mVirtualDisk;
std::shared_ptr<android::vold::VolumeBase> mInternalEmulated;
std::shared_ptr<android::vold::VolumeBase> mPrimary;
int mNextObbId;
bool mSecureKeyguardShowing;
};
extern "C" {
#endif /* __cplusplus */
#define UNMOUNT_NOT_MOUNTED_ERR (-2)
int vold_unmountAll(void);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -157,6 +157,7 @@ with open("BenchmarkGen.h", 'w') as bench:
#include <fcntl.h>
#include <algorithm>
#include <functional>
#include <string>
#include <Utils.h>
@ -164,7 +165,8 @@ with open("BenchmarkGen.h", 'w') as bench:
namespace android {
namespace vold {
static status_t BenchmarkRun() {
static status_t BenchmarkRun(std::function<bool(int)> checkpoint) {
"""
print >>bench, "char* buf = (char*) malloc(%d);" % (bufsize)
@ -175,13 +177,19 @@ static status_t BenchmarkRun() {
events = sorted(events, key=lambda e: e.time)
active = set()
defined = set()
i = 0
total = len(events)
for e in events:
i += 1
if i % 256 == 0:
print >>bench, "if (!checkpoint(%d)) return -1;" % (50 + ((i * 50) / total))
if e.call == "openat":
fd, f, handle = extract_file(e, e.ret)
if f:
active.add(handle)
if handle not in defined:
print >>bench, "int ",
print >>bench, "int",
defined.add(handle)
create_mode = ''
if 'O_CREAT' in e.args[2]:
@ -297,11 +305,17 @@ static status_t CreateFile(const char* name, int len) {
return OK;
}
static status_t BenchmarkCreate() {
static status_t BenchmarkCreate(std::function<bool(int)> checkpoint) {
status_t res = 0;
res |= CreateFile("stub", 0);
"""
i = 0
total = len(files.values())
for f in files.values():
i += 1
if i % 12 == 0:
print >>bench, "if (!checkpoint(%d)) return -1;" % ((i * 50) / total)
print >>bench, 'res |= CreateFile("file%s", %d);' % (f.ident, f.size)
print >>bench, """

View file

@ -0,0 +1,142 @@
/*
* 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;
import android.os.IVoldListener;
import android.os.IVoldTaskListener;
/** {@hide} */
interface IVold {
void setListener(IVoldListener listener);
void monitor();
void reset();
void shutdown();
void onUserAdded(int userId, int userSerial);
void onUserRemoved(int userId);
void onUserStarted(int userId);
void onUserStopped(int userId);
void onSecureKeyguardStateChanged(boolean isShowing);
void partition(@utf8InCpp String diskId, int partitionType, int ratio);
void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid);
void mount(@utf8InCpp String volId, int mountFlags, int mountUserId);
void unmount(@utf8InCpp String volId);
void format(@utf8InCpp String volId, @utf8InCpp String fsType);
void benchmark(@utf8InCpp String volId, IVoldTaskListener listener);
void checkEncryption(@utf8InCpp String volId);
void moveStorage(@utf8InCpp String fromVolId, @utf8InCpp String toVolId,
IVoldTaskListener listener);
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, IVoldTaskListener listener);
void runIdleMaint(IVoldTaskListener listener);
void abortIdleMaint(IVoldTaskListener listener);
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 mountFstab(@utf8InCpp String mountPoint);
void encryptFstab(@utf8InCpp String mountPoint);
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);
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 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 VOLUME_STATE_UNMOUNTED = 0;
const int VOLUME_STATE_CHECKING = 1;
const int VOLUME_STATE_MOUNTED = 2;
const int VOLUME_STATE_MOUNTED_READ_ONLY = 3;
const int VOLUME_STATE_FORMATTING = 4;
const int VOLUME_STATE_EJECTING = 5;
const int VOLUME_STATE_UNMOUNTABLE = 6;
const int VOLUME_STATE_REMOVED = 7;
const int VOLUME_STATE_BAD_REMOVAL = 8;
const int VOLUME_TYPE_PUBLIC = 0;
const int VOLUME_TYPE_PRIVATE = 1;
const int VOLUME_TYPE_EMULATED = 2;
const int VOLUME_TYPE_ASEC = 3;
const int VOLUME_TYPE_OBB = 4;
}

View file

@ -0,0 +1,37 @@
/*
* 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} */
oneway interface IVoldListener {
void onDiskCreated(@utf8InCpp String diskId, int flags);
void onDiskScanned(@utf8InCpp String diskId);
void onDiskMetadataChanged(@utf8InCpp String diskId,
long sizeBytes, @utf8InCpp String label, @utf8InCpp String sysPath);
void onDiskDestroyed(@utf8InCpp String diskId);
void onVolumeCreated(@utf8InCpp String volId,
int type, @utf8InCpp String diskId, @utf8InCpp String partGuid);
void onVolumeStateChanged(@utf8InCpp String volId, int state);
void onVolumeMetadataChanged(@utf8InCpp String volId,
@utf8InCpp String fsType, @utf8InCpp String fsUuid, @utf8InCpp String fsLabel);
void onVolumePathChanged(@utf8InCpp String volId,
@utf8InCpp String path);
void onVolumeInternalPathChanged(@utf8InCpp String volId,
@utf8InCpp String internalPath);
void onVolumeDestroyed(@utf8InCpp String volId);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* 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.
@ -14,8 +14,12 @@
* limitations under the License.
*/
#include "VoldCommand.h"
package android.os;
VoldCommand::VoldCommand(const char *cmd) :
FrameworkCommand(cmd) {
import android.os.PersistableBundle;
/** {@hide} */
oneway interface IVoldTaskListener {
void onStatus(int status, in PersistableBundle extras);
void onFinished(int status, in PersistableBundle extras);
}

File diff suppressed because it is too large Load diff

View file

@ -14,6 +14,9 @@
* limitations under the License.
*/
#ifndef ANDROID_VOLD_CRYPTFS_H
#define ANDROID_VOLD_CRYPTFS_H
/* This structure starts 16,384 bytes before the end of a hardware
* partition that is encrypted, or in a separate partition. It's location
* is specified by a property set in init.<device>.rc.
@ -221,42 +224,31 @@ struct crypt_persist_data {
#define PERSIST_DEL_KEY_ERROR_OTHER (-1)
#define PERSIST_DEL_KEY_ERROR_NO_FIELD (-2)
#ifdef __cplusplus
extern "C" {
#endif
int match_multi_entry(const char* key, const char* field, unsigned index);
int wait_and_unmount(const char* mountpoint, bool kill);
int wait_and_unmount(const char *mountpoint, bool kill);
typedef int (*kdf_func)(const char* passwd, const unsigned char* salt, unsigned char* ikey,
void* params);
typedef int (*kdf_func)(const char *passwd, const unsigned char *salt,
unsigned char *ikey, void *params);
int cryptfs_crypto_complete(void);
int cryptfs_check_passwd(const char* pw);
int cryptfs_verify_passwd(const char* pw);
int cryptfs_restart(void);
int cryptfs_enable(int type, const char* passwd, int no_ui);
int cryptfs_changepw(int type, const char* newpw);
int cryptfs_enable_default(int no_ui);
int cryptfs_setup_ext_volume(const char* label, const char* real_blkdev, const unsigned char* key,
char* out_crypto_blkdev);
int cryptfs_revert_ext_volume(const char* label);
int cryptfs_getfield(const char* fieldname, char* value, int len);
int cryptfs_setfield(const char* fieldname, const char* value);
int cryptfs_mount_default_encrypted(void);
int cryptfs_get_password_type(void);
const char* cryptfs_get_password(void);
void cryptfs_clear_password(void);
int cryptfs_isConvertibleToFBE(void);
int cryptfs_crypto_complete(void);
int cryptfs_check_passwd(const char *pw);
int cryptfs_verify_passwd(char *newpw);
int cryptfs_restart(void);
int cryptfs_enable(char *flag, int type, char *passwd, int no_ui);
int cryptfs_changepw(int type, const char *newpw);
int cryptfs_enable_default(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);
int cryptfs_getfield(const char *fieldname, char *value, int len);
int cryptfs_setfield(const char *fieldname, const char *value);
int cryptfs_mount_default_encrypted(void);
int cryptfs_get_password_type(void);
const char* cryptfs_get_password(void);
void cryptfs_clear_password(void);
int cryptfs_isConvertibleToFBE(void);
uint32_t cryptfs_get_keysize();
const char* cryptfs_get_crypto_name();
// Functions for file encryption to use to inherit our encryption logic
int cryptfs_create_default_ftr(struct crypt_mnt_ftr* ftr, int key_length);
int cryptfs_get_master_key(struct crypt_mnt_ftr* ftr, const char* password,
unsigned char* master_key);
int cryptfs_set_password(struct crypt_mnt_ftr* ftr, const char* password,
const unsigned char* master_key);
void cryptfs_get_file_encryption_modes(const char **contents_mode_ret,
const char **filenames_mode_ret);
#ifdef __cplusplus
}
#endif
#endif /* ANDROID_VOLD_CRYPTFS_H */

97
fs/Exfat.cpp Normal file
View file

@ -0,0 +1,97 @@
/*
* Copyright (C) 2018 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 <sys/mount.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <logwrap/logwrap.h>
#include "Exfat.h"
#include "Utils.h"
using android::base::StringPrintf;
namespace android {
namespace vold {
namespace exfat {
static const char* kMkfsPath = "/system/bin/mkfs.exfat";
static const char* kFsckPath = "/system/bin/fsck.exfat";
bool IsSupported() {
return access(kMkfsPath, X_OK) == 0 && access(kFsckPath, X_OK) == 0 &&
IsFilesystemSupported("exfat");
}
status_t Check(const std::string& source) {
std::vector<std::string> cmd;
cmd.push_back(kFsckPath);
cmd.push_back(source);
int rc = ForkExecvp(cmd, sFsckUntrustedContext);
if (rc == 0) {
LOG(INFO) << "Check OK";
return 0;
} else {
LOG(ERROR) << "Check failed (code " << rc << ")";
errno = EIO;
return -1;
}
}
status_t Mount(const std::string& source, const std::string& target, int ownerUid, int ownerGid,
int permMask) {
int mountFlags = MS_NODEV | MS_NOSUID | MS_DIRSYNC | MS_NOATIME | MS_NOEXEC;
auto mountData = android::base::StringPrintf("uid=%d,gid=%d,fmask=%o,dmask=%o", ownerUid,
ownerGid, permMask, permMask);
if (mount(source.c_str(), target.c_str(), "exfat", mountFlags, mountData.c_str()) == 0) {
return 0;
}
PLOG(ERROR) << "Mount failed; attempting read-only";
mountFlags |= MS_RDONLY;
if (mount(source.c_str(), target.c_str(), "exfat", mountFlags, mountData.c_str()) == 0) {
return 0;
}
return -1;
}
status_t Format(const std::string& source) {
std::vector<std::string> cmd;
cmd.push_back(kMkfsPath);
cmd.push_back("-n");
cmd.push_back("android");
cmd.push_back(source);
int rc = ForkExecvp(cmd);
if (rc == 0) {
LOG(INFO) << "Format OK";
return 0;
} else {
LOG(ERROR) << "Format failed (code " << rc << ")";
errno = EIO;
return -1;
}
return 0;
}
} // namespace exfat
} // namespace vold
} // namespace android

39
fs/Exfat.h Normal file
View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 2018 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_EXFAT_H
#define ANDROID_VOLD_EXFAT_H
#include <utils/Errors.h>
#include <string>
namespace android {
namespace vold {
namespace exfat {
bool IsSupported();
status_t Check(const std::string& source);
status_t Mount(const std::string& source, const std::string& target, int ownerUid, int ownerGid,
int permMask);
status_t Format(const std::string& source);
} // namespace exfat
} // namespace vold
} // namespace android
#endif

View file

@ -39,6 +39,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <ext4_utils/ext4_crypt.h>
#include <logwrap/logwrap.h>
#include <selinux/selinux.h>

View file

@ -18,7 +18,9 @@
#include "Utils.h"
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <ext4_utils/ext4_crypt.h>
#include <vector>
#include <string>
@ -72,8 +74,23 @@ status_t Mount(const std::string& source, const std::string& target) {
status_t Format(const std::string& source) {
std::vector<std::string> cmd;
cmd.push_back(kMkfsPath);
cmd.push_back(source);
cmd.push_back("-f");
cmd.push_back("-d1");
if (android::base::GetBoolProperty("vold.has_quota", false)) {
cmd.push_back("-O");
cmd.push_back("quota");
}
if (e4crypt_is_native()) {
cmd.push_back("-O");
cmd.push_back("encrypt");
}
cmd.push_back("-O");
cmd.push_back("verity");
cmd.push_back(source);
return ForkExecvp(cmd);
}

View file

@ -61,11 +61,6 @@ bool IsSupported() {
}
status_t Check(const std::string& source) {
if (access(kFsckPath, X_OK)) {
LOG(WARNING) << "Skipping fs checks";
return 0;
}
int pass = 1;
int rc = 0;
do {
@ -123,7 +118,6 @@ status_t Mount(const std::string& source, const std::string& target, bool ro,
bool createLost) {
int rc;
unsigned long flags;
char mountData[255];
const char* c_source = source.c_str();
const char* c_target = target.c_str();
@ -134,31 +128,29 @@ status_t Mount(const std::string& source, const std::string& target, bool ro,
flags |= (ro ? MS_RDONLY : 0);
flags |= (remount ? MS_REMOUNT : 0);
snprintf(mountData, sizeof(mountData),
auto mountData = android::base::StringPrintf(
"utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
ownerUid, ownerGid, permMask, permMask);
rc = mount(c_source, c_target, "vfat", flags, mountData);
rc = mount(c_source, c_target, "vfat", flags, mountData.c_str());
if (rc && errno == EROFS) {
LOG(ERROR) << source << " appears to be a read only filesystem - retrying mount RO";
flags |= MS_RDONLY;
rc = mount(c_source, c_target, "vfat", flags, mountData);
rc = mount(c_source, c_target, "vfat", flags, mountData.c_str());
}
if (rc == 0 && createLost) {
char *lost_path;
asprintf(&lost_path, "%s/LOST.DIR", c_target);
if (access(lost_path, F_OK)) {
auto lost_path = android::base::StringPrintf("%s/LOST.DIR", target.c_str());
if (access(lost_path.c_str(), F_OK)) {
/*
* Create a LOST.DIR in the root so we have somewhere to put
* lost cluster chains (fsck_msdos doesn't currently do this)
*/
if (mkdir(lost_path, 0755)) {
if (mkdir(lost_path.c_str(), 0755)) {
PLOG(ERROR) << "Unable to create LOST.DIR";
}
}
free(lost_path);
}
return rc;

109
main.cpp
View file

@ -14,19 +14,21 @@
* limitations under the License.
*/
#include "Disk.h"
#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
#include "model/Disk.h"
#include "VolumeManager.h"
#include "CommandListener.h"
#include "CryptCommandListener.h"
#include "NetlinkManager.h"
#include "VoldNativeService.h"
#include "VoldUtil.h"
#include "cryptfs.h"
#include "sehandle.h"
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <cutils/klog.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <utils/Trace.h>
#include <stdio.h>
#include <stdlib.h>
@ -39,30 +41,31 @@
#include <dirent.h>
#include <fs_mgr.h>
static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota);
static int process_config(VolumeManager* vm, bool* has_adoptable, bool* has_quota,
bool* has_reserved);
static void coldboot(const char *path);
static void parse_args(int argc, char** argv);
struct fstab *fstab;
struct selabel_handle *sehandle;
using android::base::StringPrintf;
int main(int argc, char** argv) {
atrace_set_tracing_enabled(false);
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
LOG(INFO) << "Vold 3.0 (the awakening) firing up";
ATRACE_BEGIN("main");
LOG(VERBOSE) << "Detected support for:"
<< (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
<< (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
<< (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
VolumeManager *vm;
CommandListener *cl;
CryptCommandListener *ccl;
NetlinkManager *nm;
parse_args(argc, argv);
@ -72,10 +75,6 @@ int main(int argc, char** argv) {
selinux_android_set_sehandle(sehandle);
}
// Quickly throw a CLOEXEC on the socket we just inherited from init
fcntl(android_get_control_socket("vold"), F_SETFD, FD_CLOEXEC);
fcntl(android_get_control_socket("cryptd"), F_SETFD, FD_CLOEXEC);
mkdir("/dev/block/vold", 0755);
/* For when cryptfs checks and mounts an encrypted filesystem */
@ -92,15 +91,10 @@ int main(int argc, char** argv) {
exit(1);
}
if (property_get_bool("vold.debug", false)) {
if (android::base::GetBoolProperty("vold.debug", false)) {
vm->setDebug(true);
}
cl = new CommandListener();
ccl = new CryptCommandListener();
vm->setBroadcaster((SocketListener *) cl);
nm->setBroadcaster((SocketListener *) cl);
if (vm->start()) {
PLOG(ERROR) << "Unable to start VolumeManager";
exit(1);
@ -108,44 +102,44 @@ int main(int argc, char** argv) {
bool has_adoptable;
bool has_quota;
bool has_reserved;
if (process_config(vm, &has_adoptable, &has_quota)) {
if (process_config(vm, &has_adoptable, &has_quota, &has_reserved)) {
PLOG(ERROR) << "Error reading configuration... continuing anyways";
}
ATRACE_BEGIN("VoldNativeService::start");
if (android::vold::VoldNativeService::start() != android::OK) {
LOG(ERROR) << "Unable to start VoldNativeService";
exit(1);
}
ATRACE_END();
LOG(DEBUG) << "VoldNativeService::start() completed OK";
ATRACE_BEGIN("NetlinkManager::start");
if (nm->start()) {
PLOG(ERROR) << "Unable to start NetlinkManager";
exit(1);
}
/*
* Now that we're up, we can respond to commands
*/
if (cl->startListener()) {
PLOG(ERROR) << "Unable to start CommandListener";
exit(1);
}
if (ccl->startListener()) {
PLOG(ERROR) << "Unable to start CryptCommandListener";
exit(1);
}
ATRACE_END();
// This call should go after listeners are started to avoid
// a deadlock between vold and init (see b/34278978 for details)
property_set("vold.has_adoptable", has_adoptable ? "1" : "0");
property_set("vold.has_quota", has_quota ? "1" : "0");
android::base::SetProperty("vold.has_adoptable", has_adoptable ? "1" : "0");
android::base::SetProperty("vold.has_quota", has_quota ? "1" : "0");
android::base::SetProperty("vold.has_reserved", has_reserved ? "1" : "0");
// Do coldboot here so it won't block booting,
// also the cold boot is needed in case we have flash drive
// connected before Vold launched
coldboot("/sys/block");
// Eventually we'll become the monitoring thread
while(1) {
pause();
}
LOG(ERROR) << "Vold exiting";
ATRACE_END();
android::IPCThreadState::self()->joinThreadPool();
LOG(INFO) << "vold shutting down";
exit(0);
}
@ -209,6 +203,7 @@ static void do_coldboot(DIR *d, int lvl) {
}
static void coldboot(const char *path) {
ATRACE_NAME("coldboot");
DIR *d = opendir(path);
if(d) {
do_coldboot(d, 0);
@ -216,9 +211,12 @@ static void coldboot(const char *path) {
}
}
static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) {
fstab = fs_mgr_read_fstab_default();
if (!fstab) {
static int process_config(VolumeManager* vm, bool* has_adoptable, bool* has_quota,
bool* has_reserved) {
ATRACE_NAME("process_config");
fstab_default = fs_mgr_read_fstab_default();
if (!fstab_default) {
PLOG(ERROR) << "Failed to open default fstab";
return -1;
}
@ -226,27 +224,32 @@ static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quot
/* Loop through entries looking for ones that vold manages */
*has_adoptable = false;
*has_quota = false;
for (int i = 0; i < fstab->num_entries; i++) {
if (fs_mgr_is_quota(&fstab->recs[i])) {
*has_reserved = false;
for (int i = 0; i < fstab_default->num_entries; i++) {
auto rec = &fstab_default->recs[i];
if (fs_mgr_is_quota(rec)) {
*has_quota = true;
}
if (rec->reserved_size > 0) {
*has_reserved = true;
}
if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
if (fs_mgr_is_voldmanaged(rec)) {
if (fs_mgr_is_nonremovable(rec)) {
LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
continue;
}
std::string sysPattern(fstab->recs[i].blk_device);
std::string nickname(fstab->recs[i].label);
std::string sysPattern(rec->blk_device);
std::string nickname(rec->label);
int flags = 0;
if (fs_mgr_is_encryptable(&fstab->recs[i])) {
if (fs_mgr_is_encryptable(rec)) {
flags |= android::vold::Disk::Flags::kAdoptable;
*has_adoptable = true;
}
if (fs_mgr_is_noemulatedsd(&fstab->recs[i])
|| property_get_bool("vold.debug.default_primary", false)) {
if (fs_mgr_is_noemulatedsd(rec)
|| android::base::GetBoolProperty("vold.debug.default_primary", false)) {
flags |= android::vold::Disk::Flags::kDefaultPrimary;
}

View file

@ -20,14 +20,17 @@
#include "Utils.h"
#include "VolumeBase.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include "Ext4Crypt.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <diskconfig/diskconfig.h>
#include <android-base/strings.h>
#include <android-base/parseint.h>
#include <ext4_utils/ext4_crypt.h>
#include "cryptfs.h"
#include <vector>
#include <fcntl.h>
@ -160,7 +163,10 @@ void Disk::listVolumes(VolumeBase::Type type, std::list<std::string>& list) {
status_t Disk::create() {
CHECK(!mCreated);
mCreated = true;
notifyEvent(ResponseCode::DiskCreated, StringPrintf("%d", mFlags));
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskCreated(getId(), mFlags);
readMetadata();
readPartitions();
return OK;
@ -170,7 +176,10 @@ status_t Disk::destroy() {
CHECK(mCreated);
destroyAllVolumes();
mCreated = false;
notifyEvent(ResponseCode::DiskDestroyed);
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskDestroyed(getId());
return OK;
}
@ -256,6 +265,7 @@ status_t Disk::readMetadata() {
PLOG(WARNING) << "Failed to read vendor from " << path;
return -errno;
}
tmp = android::base::Trim(tmp);
mLabel = tmp;
break;
}
@ -266,7 +276,12 @@ status_t Disk::readMetadata() {
PLOG(WARNING) << "Failed to read manufacturer from " << path;
return -errno;
}
uint64_t manfid = strtoll(tmp.c_str(), nullptr, 16);
tmp = android::base::Trim(tmp);
int64_t manfid;
if (!android::base::ParseInt(tmp, &manfid)) {
PLOG(WARNING) << "Failed to parse manufacturer " << tmp;
return -EINVAL;
}
// Our goal here is to give the user a meaningful label, ideally
// matching whatever is silk-screened on the card. To reduce
// user confusion, this list doesn't contain white-label manfid.
@ -300,14 +315,15 @@ status_t Disk::readMetadata() {
}
}
notifyEvent(ResponseCode::DiskSizeChanged, StringPrintf("%" PRIu64, mSize));
notifyEvent(ResponseCode::DiskLabelChanged, mLabel);
notifyEvent(ResponseCode::DiskSysPathChanged, mSysPath);
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskMetadataChanged(getId(),
mSize, mLabel, mSysPath);
return OK;
}
status_t Disk::readPartitions() {
int8_t maxMinors = getMaxMinors();
int maxMinors = getMaxMinors();
if (maxMinors < 0) {
return -ENOTSUP;
}
@ -325,7 +341,10 @@ status_t Disk::readPartitions() {
status_t res = ForkExecvp(cmd, output);
if (res != OK) {
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
notifyEvent(ResponseCode::DiskScanned);
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskScanned(getId());
mJustPartitioned = false;
return res;
}
@ -333,32 +352,42 @@ status_t Disk::readPartitions() {
Table table = Table::kUnknown;
bool foundParts = false;
for (const auto& line : output) {
char* cline = (char*) line.c_str();
char* token = strtok(cline, kSgdiskToken);
if (token == nullptr) continue;
auto split = android::base::Split(line, kSgdiskToken);
auto it = split.begin();
if (it == split.end()) continue;
if (!strcmp(token, "DISK")) {
const char* type = strtok(nullptr, kSgdiskToken);
if (!strcmp(type, "mbr")) {
if (*it == "DISK") {
if (++it == split.end()) continue;
if (*it == "mbr") {
table = Table::kMbr;
} else if (!strcmp(type, "gpt")) {
} else if (*it == "gpt") {
table = Table::kGpt;
} else {
LOG(WARNING) << "Invalid partition table " << *it;
continue;
}
} else if (!strcmp(token, "PART")) {
} else if (*it == "PART") {
foundParts = true;
int i = strtol(strtok(nullptr, kSgdiskToken), nullptr, 10);
if (i <= 0 || i > maxMinors) {
LOG(WARNING) << mId << " is ignoring partition " << i
<< " beyond max supported devices";
if (++it == split.end()) continue;
int i = 0;
if (!android::base::ParseInt(*it, &i, 1, maxMinors)) {
LOG(WARNING) << "Invalid partition number " << *it;
continue;
}
dev_t partDevice = makedev(major(mDevice), minor(mDevice) + i);
if (table == Table::kMbr) {
const char* type = strtok(nullptr, kSgdiskToken);
if (++it == split.end()) continue;
int type = 0;
if (!android::base::ParseInt("0x" + *it, &type)) {
LOG(WARNING) << "Invalid partition type " << *it;
continue;
}
switch (strtol(type, nullptr, 16)) {
switch (type) {
case 0x06: // FAT16
case 0x07: // HPFS/NTFS/exFAT
case 0x0b: // W95 FAT32 (LBA)
case 0x0c: // W95 FAT32 (LBA)
case 0x0e: // W95 FAT16 (LBA)
@ -366,12 +395,14 @@ status_t Disk::readPartitions() {
break;
}
} else if (table == Table::kGpt) {
const char* typeGuid = strtok(nullptr, kSgdiskToken);
const char* partGuid = strtok(nullptr, kSgdiskToken);
if (++it == split.end()) continue;
auto typeGuid = *it;
if (++it == split.end()) continue;
auto partGuid = *it;
if (!strcasecmp(typeGuid, kGptBasicData)) {
if (android::base::EqualsIgnoreCase(typeGuid, kGptBasicData)) {
createPublicVolume(partDevice);
} else if (!strcasecmp(typeGuid, kGptAndroidExpand)) {
} else if (android::base::EqualsIgnoreCase(typeGuid, kGptAndroidExpand)) {
createPrivateVolume(partDevice, partGuid);
}
}
@ -384,14 +415,16 @@ status_t Disk::readPartitions() {
std::string fsType;
std::string unused;
if (ReadMetadataUntrusted(mDevPath, fsType, unused, unused) == OK) {
if (ReadMetadataUntrusted(mDevPath, &fsType, &unused, &unused) == OK) {
createPublicVolume(mDevice);
} else {
LOG(WARNING) << mId << " failed to identify, giving up";
}
}
notifyEvent(ResponseCode::DiskScanned);
auto listener = VolumeManager::Instance()->getListener();
if (listener) listener->onDiskScanned(getId());
mJustPartitioned = false;
return OK;
}
@ -406,7 +439,6 @@ status_t Disk::unmountAll() {
status_t Disk::partitionPublic() {
int res;
// TODO: improve this code
destroyAllVolumes();
mJustPartitioned = true;
@ -422,41 +454,21 @@ status_t Disk::partitionPublic() {
LOG(WARNING) << "Failed to zap; status " << res;
}
struct disk_info dinfo;
memset(&dinfo, 0, sizeof(dinfo));
// Now let's build the new MBR table. We heavily rely on sgdisk to
// force optimal alignment on the created partitions.
cmd.clear();
cmd.push_back(kSgdiskPath);
cmd.push_back("--new=0:0:-0");
cmd.push_back("--typecode=0:0c00");
cmd.push_back("--gpttombr=1");
cmd.push_back(mDevPath);
if (!(dinfo.part_lst = (struct part_info *) malloc(
MAX_NUM_PARTS * sizeof(struct part_info)))) {
return -1;
if ((res = ForkExecvp(cmd)) != 0) {
LOG(ERROR) << "Failed to partition; status " << res;
return res;
}
memset(dinfo.part_lst, 0, MAX_NUM_PARTS * sizeof(struct part_info));
dinfo.device = strdup(mDevPath.c_str());
dinfo.scheme = PART_SCHEME_MBR;
dinfo.sect_size = 512;
dinfo.skip_lba = 2048;
dinfo.num_lba = 0;
dinfo.num_parts = 1;
struct part_info *pinfo = &dinfo.part_lst[0];
pinfo->name = strdup("android_sdcard");
pinfo->flags |= PART_ACTIVE_FLAG;
pinfo->type = PC_PART_TYPE_FAT32;
pinfo->len_kb = -1;
int rc = apply_disk_config(&dinfo, 0);
if (rc) {
LOG(ERROR) << "Failed to apply disk configuration: " << rc;
goto out;
}
out:
free(pinfo->name);
free(dinfo.device);
free(dinfo.part_lst);
return rc;
return OK;
}
status_t Disk::partitionPrivate() {
@ -466,12 +478,6 @@ status_t Disk::partitionPrivate() {
status_t Disk::partitionMixed(int8_t ratio) {
int res;
if (e4crypt_is_native()
&& !android::base::GetBoolProperty("persist.sys.adoptable_fbe", false)) {
LOG(ERROR) << "Private volumes not yet supported on FBE devices";
return -EINVAL;
}
destroyAllVolumes();
mJustPartitioned = true;
@ -496,7 +502,7 @@ status_t Disk::partitionMixed(int8_t ratio) {
}
std::string keyRaw;
if (ReadRandomBytes(16, keyRaw) != OK) {
if (ReadRandomBytes(cryptfs_get_keysize(), keyRaw) != OK) {
LOG(ERROR) << "Failed to generate key";
return -EIO;
}
@ -553,16 +559,6 @@ status_t Disk::partitionMixed(int8_t ratio) {
return OK;
}
void Disk::notifyEvent(int event) {
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
getId().c_str(), false);
}
void Disk::notifyEvent(int event, const std::string& value) {
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
}
int Disk::getMaxMinors() {
// Figure out maximum partition devices supported
unsigned int majorId = major(mDevice);
@ -573,7 +569,7 @@ int Disk::getMaxMinors() {
LOG(ERROR) << "Failed to read max minors";
return -errno;
}
return atoi(tmp.c_str());
return std::stoi(tmp);
}
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC: case kMajorBlockScsiD:
case kMajorBlockScsiE: case kMajorBlockScsiF: case kMajorBlockScsiG: case kMajorBlockScsiH:
@ -590,7 +586,7 @@ int Disk::getMaxMinors() {
LOG(ERROR) << "Failed to read max minors";
return -errno;
}
return atoi(tmp.c_str());
return std::stoi(tmp);
}
default: {
if (isVirtioBlkDevice(majorId)) {

View file

@ -79,9 +79,6 @@ public:
status_t partitionPrivate();
status_t partitionMixed(int8_t ratio);
void notifyEvent(int msg);
void notifyEvent(int msg, const std::string& value);
private:
/* ID that uniquely references this disk */
std::string mId;

View file

@ -21,6 +21,7 @@
#include <android-base/logging.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
#include <utils/Timers.h>
#include <fcntl.h>
#include <stdlib.h>
@ -85,6 +86,7 @@ status_t EmulatedVolume::doMount() {
"-m",
"-w",
"-G",
"-i",
mRawPath.c_str(),
label.c_str(),
NULL)) {
@ -100,9 +102,16 @@ status_t EmulatedVolume::doMount() {
return -errno;
}
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
while (before == GetDevice(mFuseWrite)) {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
if (nanoseconds_to_milliseconds(now - start) > 5000) {
LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
return -ETIMEDOUT;
}
}
/* sdcardfs will have exited already. FUSE will still be running */
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));

130
model/ObbVolume.cpp Normal file
View file

@ -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

57
model/ObbVolume.h Normal file
View file

@ -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

View file

@ -20,7 +20,6 @@
#include "EmulatedVolume.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include "cryptfs.h"
#include <android-base/stringprintf.h>
@ -54,10 +53,11 @@ PrivateVolume::~PrivateVolume() {
}
status_t PrivateVolume::readMetadata() {
status_t res = ReadMetadata(mDmDevPath, mFsType, mFsUuid, mFsLabel);
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
status_t res = ReadMetadata(mDmDevPath, &mFsType, &mFsUuid, &mFsLabel);
auto listener = getListener();
if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
return res;
}
@ -65,6 +65,11 @@ status_t PrivateVolume::doCreate() {
if (CreateDeviceNode(mRawDevPath, mRawDevice)) {
return -EIO;
}
if (mKeyRaw.size() != cryptfs_get_keysize()) {
PLOG(ERROR) << getId() << " Raw keysize " << mKeyRaw.size() <<
" does not match crypt keysize " << cryptfs_get_keysize();
return -EIO;
}
// Recover from stale vold by tearing down any old mappings
cryptfs_revert_ext_volume(getId().c_str());
@ -74,7 +79,7 @@ status_t PrivateVolume::doCreate() {
unsigned char* key = (unsigned char*) mKeyRaw.data();
char crypto_blkdev[MAXPATHLEN];
int res = cryptfs_setup_ext_volume(getId().c_str(), mRawDevPath.c_str(),
key, mKeyRaw.size(), crypto_blkdev);
key, crypto_blkdev);
mDmDevPath = crypto_blkdev;
if (res != 0) {
PLOG(ERROR) << getId() << " failed to setup cryptfs";

View file

@ -39,6 +39,8 @@ class PrivateVolume : public VolumeBase {
public:
PrivateVolume(dev_t device, const std::string& keyRaw);
virtual ~PrivateVolume();
const std::string& getFsType() { return mFsType; };
const std::string& getRawDevPath() { return mRawDevPath; };
protected:
status_t doCreate() override;

View file

@ -14,16 +14,17 @@
* limitations under the License.
*/
#include "fs/Vfat.h"
#include "PublicVolume.h"
#include "Utils.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include "fs/Exfat.h"
#include "fs/Vfat.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
#include <cutils/fs.h>
#include <private/android_filesystem_config.h>
#include <utils/Timers.h>
#include <fcntl.h>
#include <stdlib.h>
@ -52,10 +53,11 @@ PublicVolume::~PublicVolume() {
}
status_t PublicVolume::readMetadata() {
status_t res = ReadMetadataUntrusted(mDevPath, mFsType, mFsUuid, mFsLabel);
notifyEvent(ResponseCode::VolumeFsTypeChanged, mFsType);
notifyEvent(ResponseCode::VolumeFsUuidChanged, mFsUuid);
notifyEvent(ResponseCode::VolumeFsLabelChanged, mFsLabel);
status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel);
auto listener = getListener();
if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
return res;
}
@ -92,18 +94,22 @@ status_t PublicVolume::doDestroy() {
}
status_t PublicVolume::doMount() {
// TODO: expand to support mounting other filesystems
readMetadata();
if (mFsType != "vfat") {
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
return -EIO;
}
if (mFsType == "vfat" && vfat::IsSupported()) {
if (vfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
} else if (mFsType == "exfat" && exfat::IsSupported()) {
if (exfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
} else {
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
return -EIO;
}
// Use UUID as stable name, if available
std::string stableName = getId();
@ -129,11 +135,18 @@ status_t PublicVolume::doMount() {
return -errno;
}
if (vfat::Mount(mDevPath, mRawPath, false, false, false,
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
if (mFsType == "vfat") {
if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007,
true)) {
PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
return -EIO;
}
} else if (mFsType == "exfat") {
if (exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) {
PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
return -EIO;
}
}
if (getMountFlags() & MountFlags::kPrimary) {
initAsecStage();
@ -186,9 +199,16 @@ status_t PublicVolume::doMount() {
return -errno;
}
nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME);
while (before == GetDevice(mFuseWrite)) {
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
usleep(50000); // 50ms
nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME);
if (nanoseconds_to_milliseconds(now - start) > 5000) {
LOG(WARNING) << "Timed out while waiting for FUSE to spin up";
return -ETIMEDOUT;
}
}
/* sdcardfs will have exited already. FUSE will still be running */
TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0));
@ -225,7 +245,7 @@ status_t PublicVolume::doUnmount() {
}
status_t PublicVolume::doFormat(const std::string& fsType) {
if (fsType == "vfat" || fsType == "auto") {
if ((fsType == "vfat" || fsType == "auto") && vfat::IsSupported()) {
if (WipeBlockDevice(mDevPath) != OK) {
LOG(WARNING) << getId() << " failed to wipe";
}
@ -233,6 +253,14 @@ status_t PublicVolume::doFormat(const std::string& fsType) {
LOG(ERROR) << getId() << " failed to format";
return -errno;
}
} else if ((fsType == "exfat" || fsType == "auto") && exfat::IsSupported()) {
if (WipeBlockDevice(mDevPath) != OK) {
LOG(WARNING) << getId() << " failed to wipe";
}
if (exfat::Format(mDevPath)) {
LOG(ERROR) << getId() << " failed to format";
return -errno;
}
} else {
LOG(ERROR) << "Unsupported filesystem " << fsType;
return -EINVAL;

View file

@ -17,7 +17,6 @@
#include "Utils.h"
#include "VolumeBase.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
#include <android-base/stringprintf.h>
#include <android-base/logging.h>
@ -44,7 +43,9 @@ VolumeBase::~VolumeBase() {
void VolumeBase::setState(State state) {
mState = state;
notifyEvent(ResponseCode::VolumeStateChanged, StringPrintf("%d", mState));
auto listener = getListener();
if (listener) listener->onVolumeStateChanged(getId(), static_cast<int32_t>(mState));
}
status_t VolumeBase::setDiskId(const std::string& diskId) {
@ -114,7 +115,10 @@ status_t VolumeBase::setPath(const std::string& path) {
}
mPath = path;
notifyEvent(ResponseCode::VolumePathChanged, mPath);
auto listener = getListener();
if (listener) listener->onVolumePathChanged(getId(), mPath);
return OK;
}
@ -125,20 +129,19 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) {
}
mInternalPath = internalPath;
notifyEvent(ResponseCode::VolumeInternalPathChanged, mInternalPath);
auto listener = getListener();
if (listener) listener->onVolumeInternalPathChanged(getId(), mInternalPath);
return OK;
}
void VolumeBase::notifyEvent(int event) {
if (mSilent) return;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
getId().c_str(), false);
}
void VolumeBase::notifyEvent(int event, const std::string& value) {
if (mSilent) return;
VolumeManager::Instance()->getBroadcaster()->sendBroadcast(event,
StringPrintf("%s %s", getId().c_str(), value.c_str()).c_str(), false);
android::sp<android::os::IVoldListener> VolumeBase::getListener() {
if (mSilent) {
return nullptr;
} else {
return VolumeManager::Instance()->getListener();
}
}
void VolumeBase::addVolume(const std::shared_ptr<VolumeBase>& volume) {
@ -163,8 +166,11 @@ status_t VolumeBase::create() {
mCreated = true;
status_t res = doCreate();
notifyEvent(ResponseCode::VolumeCreated,
StringPrintf("%d \"%s\" \"%s\"", mType, mDiskId.c_str(), mPartGuid.c_str()));
auto listener = getListener();
if (listener) listener->onVolumeCreated(getId(),
static_cast<int32_t>(mType), mDiskId, mPartGuid);
setState(State::kUnmounted);
return res;
}
@ -183,7 +189,10 @@ status_t VolumeBase::destroy() {
setState(State::kRemoved);
}
notifyEvent(ResponseCode::VolumeDestroyed);
auto listener = getListener();
if (listener) listener->onVolumeDestroyed(getId());
status_t res = doDestroy();
mCreated = false;
return res;

View file

@ -17,6 +17,7 @@
#ifndef ANDROID_VOLD_VOLUME_BASE_H
#define ANDROID_VOLD_VOLUME_BASE_H
#include "android/os/IVoldListener.h"
#include "Utils.h"
#include <cutils/multiuser.h>
@ -114,8 +115,7 @@ protected:
status_t setPath(const std::string& path);
status_t setInternalPath(const std::string& internalPath);
void notifyEvent(int msg);
void notifyEvent(int msg, const std::string& value);
android::sp<android::os::IVoldListener> getListener();
private:
/* ID that uniquely references volume while alive */

View file

@ -18,8 +18,6 @@
#include <selinux/selinux.h>
__BEGIN_DECLS
security_context_t secontextFsck();
__END_DECLS
#endif

14
tests/Android.bp Normal file
View file

@ -0,0 +1,14 @@
cc_test {
name: "vold_tests",
defaults: [
"vold_default_flags",
"vold_default_libs",
],
srcs: [
"CryptfsScryptHidlizationEquivalence_test.cpp",
"Utils_test.cpp",
"cryptfs_test.cpp",
],
static_libs: ["libvold"],
}

View file

@ -1,40 +0,0 @@
# Build the unit tests.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_C_INCLUDES := \
system/core/fs_mgr/include
LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto
LOCAL_SRC_FILES := VolumeManager_test.cpp
LOCAL_MODULE := vold_tests
LOCAL_MODULE_TAGS := eng tests
LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_NATIVE_TEST)
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
# LOCAL_C_INCLUDES := \
system/core/fs_mgr/include
LOCAL_STATIC_LIBRARIES := libselinux libvold liblog libcrypto
LOCAL_SHARED_LIBRARIES := \
libutils \
libbase \
libhardware \
libhardware_legacy \
libhwbinder \
libhidlbase \
libkeystore_binder \
android.hardware.keymaster@3.0
LOCAL_SRC_FILES := CryptfsScryptHidlizationEquivalence_test.cpp
LOCAL_MODULE := vold_cryptfs_scrypt_hidlization_equivalence_test
LOCAL_MODULE_TAGS := eng tests
include $(BUILD_NATIVE_TEST)

44
tests/Utils_test.cpp Normal file
View file

@ -0,0 +1,44 @@
/*
* 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 <gtest/gtest.h>
#include "../Utils.h"
namespace android {
namespace vold {
class UtilsTest : public testing::Test {
};
TEST_F(UtilsTest, FindValueTest) {
std::string tmp;
ASSERT_FALSE(FindValue("", "KEY", &tmp));
ASSERT_FALSE(FindValue("BADKEY=\"VALUE\"", "KEY", &tmp));
ASSERT_TRUE(FindValue("KEY=\"VALUE\"", "KEY", &tmp));
ASSERT_EQ("VALUE", tmp);
ASSERT_TRUE(FindValue("FOO=\"BAR\" KEY=\"VALUE VALUE\" BAR=\"BAZ\"", "KEY", &tmp));
ASSERT_EQ("VALUE VALUE", tmp);
ASSERT_TRUE(FindValue("BADKEY=\"VALUE\" KEY=\"BAZ\"", "KEY", &tmp));
ASSERT_EQ("BAZ", tmp);
}
}
}

View file

@ -1,64 +0,0 @@
/*
* Copyright (C) 2010 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 <errno.h>
#define LOG_TAG "VolumeManager_test"
#include <utils/Log.h>
#include <openssl/md5.h>
#include "../VolumeManager.h"
#include <gtest/gtest.h>
namespace android {
class VolumeManagerTest : public testing::Test {
protected:
virtual void SetUp() {
}
virtual void TearDown() {
}
};
TEST_F(VolumeManagerTest, AsecHashTests) {
char buffer[MD5_ASCII_LENGTH_PLUS_NULL];
char* dst = reinterpret_cast<char*>(&buffer);
const char* src1 = "";
const char* exp1 = "d41d8cd98f00b204e9800998ecf8427e";
EXPECT_TRUE(VolumeManager::asecHash(exp1, (char*)NULL, sizeof(buffer)) == NULL && errno == ESPIPE)
<< "Should return NULL and set errno to ESPIPE when destination buffer is NULL";
EXPECT_TRUE(VolumeManager::asecHash(exp1, dst, 0) == NULL && errno == ESPIPE)
<< "Should return NULL and set errno to ESPIPE when destination buffer length is 0";
EXPECT_TRUE(VolumeManager::asecHash((const char*)NULL, dst, sizeof(buffer)) == NULL && errno == ESPIPE)
<< "Should return NULL and set errno to ESPIPE when source buffer is NULL";
EXPECT_FALSE(VolumeManager::asecHash(src1, dst, sizeof(buffer)) == NULL)
<< "Should not return NULL on valid source, destination, and destination size";
EXPECT_STREQ(exp1, dst)
<< "MD5 summed output should match";
const char* src2 = "android";
const char* exp2 = "c31b32364ce19ca8fcd150a417ecce58";
EXPECT_FALSE(VolumeManager::asecHash(src2, dst, sizeof(buffer)) == NULL)
<< "Should not return NULL on valid source, destination, and destination size";
EXPECT_STREQ(exp2, dst)
<< "MD5 summed output should match";
}
}

54
tests/cryptfs_test.cpp Normal file
View file

@ -0,0 +1,54 @@
/*
* 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 <gtest/gtest.h>
#include "../cryptfs.h"
namespace android {
class CryptfsTest : public testing::Test {
protected:
virtual void SetUp() {
}
virtual void TearDown() {
}
};
TEST_F(CryptfsTest, MatchMultiEntryTest) {
ASSERT_NE(0, match_multi_entry("foo", "foo", 0));
ASSERT_NE(0, match_multi_entry("foo_0", "foo", 0));
ASSERT_NE(0, match_multi_entry("foo_1", "foo", 0));
ASSERT_NE(0, match_multi_entry("foo_2", "foo", 0));
ASSERT_EQ(0, match_multi_entry("foo", "foo", 1));
ASSERT_EQ(0, match_multi_entry("foo_0", "foo", 1));
ASSERT_NE(0, match_multi_entry("foo_1", "foo", 1));
ASSERT_NE(0, match_multi_entry("foo_2", "foo", 1));
ASSERT_EQ(0, match_multi_entry("foo", "foo", 2));
ASSERT_EQ(0, match_multi_entry("foo_0", "foo", 2));
ASSERT_EQ(0, match_multi_entry("foo_1", "foo", 2));
ASSERT_NE(0, match_multi_entry("foo_2", "foo", 2));
ASSERT_EQ(0, match_multi_entry("food", "foo", 0));
ASSERT_EQ(0, match_multi_entry("foo", "food", 0));
ASSERT_EQ(0, match_multi_entry("foo", "bar", 0));
ASSERT_EQ(0, match_multi_entry("foo_2", "bar", 0));
}
}

178
vdc.cpp
View file

@ -24,158 +24,94 @@
#include <stdlib.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include "android/os/IVold.h"
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <binder/IServiceManager.h>
#include <binder/Status.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
static void usage(char *progname);
static int do_monitor(int sock, int stop_after_cmd);
static int do_cmd(int sock, int argc, char **argv);
static constexpr int kCommandTimeoutMs = 20 * 1000;
static android::sp<android::IBinder> getServiceAggressive() {
android::sp<android::IBinder> res;
auto sm = android::defaultServiceManager();
auto name = android::String16("vold");
for (int i = 0; i < 5000; i++) {
res = sm->checkService(name);
if (res) {
LOG(VERBOSE) << "Waited " << (i * 10) << "ms for vold";
break;
}
usleep(10000); // 10ms
}
return res;
}
int main(int argc, char **argv) {
int sock;
int wait_for_socket;
char *progname;
progname = argv[0];
static void checkStatus(android::binder::Status status) {
if (status.isOk()) return;
LOG(ERROR) << "Failed: " << status.toString8().string();
exit(ENOTTY);
}
int main(int argc, char** argv) {
setenv("ANDROID_LOG_TAGS", "*:v", 1);
if (getppid() == 1) {
// If init is calling us then it's during boot and we should log to kmsg
android::base::InitLogging(argv, &android::base::KernelLogger);
} else {
android::base::InitLogging(argv, &android::base::StderrLogger);
}
std::vector<std::string> args(argv + 1, argv + argc);
wait_for_socket = argc > 1 && strcmp(argv[1], "--wait") == 0;
if (wait_for_socket) {
argv++;
argc--;
if (args.size() > 0 && args[0] == "--wait") {
// Just ignore the --wait flag
args.erase(args.begin());
}
if (argc < 2) {
usage(progname);
if (args.size() < 2) {
usage(argv[0]);
exit(5);
}
const char* sockname = "vold";
if (!strcmp(argv[1], "cryptfs")) {
sockname = "cryptd";
android::sp<android::IBinder> binder = getServiceAggressive();
if (!binder) {
LOG(ERROR) << "Failed to obtain vold Binder";
exit(EINVAL);
}
auto vold = android::interface_cast<android::os::IVold>(binder);
while ((sock = socket_local_client(sockname,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM)) < 0) {
if (!wait_for_socket) {
PLOG(ERROR) << "Error connecting to " << sockname;
exit(4);
if (args[0] == "cryptfs" && args[1] == "enablefilecrypto") {
checkStatus(vold->fbeEnable());
} else if (args[0] == "cryptfs" && args[1] == "init_user0") {
checkStatus(vold->initUser0());
} else if (args[0] == "cryptfs" && args[1] == "enablecrypto") {
int passwordType = android::os::IVold::PASSWORD_TYPE_DEFAULT;
int encryptionFlags = android::os::IVold::ENCRYPTION_FLAG_NO_UI;
checkStatus(vold->fdeEnable(passwordType, "", encryptionFlags));
} else if (args[0] == "cryptfs" && args[1] == "mountdefaultencrypted") {
checkStatus(vold->mountDefaultEncrypted());
} else if (args[0] == "volume" && args[1] == "shutdown") {
checkStatus(vold->shutdown());
} else if (args[0] == "cryptfs" && args[1] == "checkEncryption" && args.size() == 3) {
checkStatus(vold->checkEncryption(args[2]));
} else if (args[0] == "cryptfs" && args[1] == "mountFstab" && args.size() == 3) {
checkStatus(vold->mountFstab(args[2]));
} else if (args[0] == "cryptfs" && args[1] == "encryptFstab" && args.size() == 3) {
checkStatus(vold->encryptFstab(args[2]));
} else {
usleep(10000);
LOG(ERROR) << "Raw commands are no longer supported";
exit(EINVAL);
}
}
if (!strcmp(argv[1], "monitor")) {
exit(do_monitor(sock, 0));
} else {
exit(do_cmd(sock, argc, argv));
}
}
static int do_cmd(int sock, int argc, char **argv) {
int seq = getpid();
std::string cmd(android::base::StringPrintf("%d ", seq));
for (int i = 1; i < argc; i++) {
if (!strchr(argv[i], ' ')) {
cmd.append(argv[i]);
} else {
cmd.push_back('\"');
cmd.append(argv[i]);
cmd.push_back('\"');
}
if (i < argc - 1) {
cmd.push_back(' ');
}
}
if (TEMP_FAILURE_RETRY(write(sock, cmd.c_str(), cmd.length() + 1)) < 0) {
PLOG(ERROR) << "Failed to write command";
return errno;
}
return do_monitor(sock, seq);
}
static int do_monitor(int sock, int stop_after_seq) {
char buffer[4096];
int timeout = kCommandTimeoutMs;
if (stop_after_seq == 0) {
LOG(INFO) << "Connected to vold";
timeout = -1;
}
while (1) {
struct pollfd poll_sock = { sock, POLLIN, 0 };
int rc = TEMP_FAILURE_RETRY(poll(&poll_sock, 1, timeout));
if (rc == 0) {
LOG(ERROR) << "Timeout waiting for " << stop_after_seq;
return ETIMEDOUT;
} else if (rc < 0) {
PLOG(ERROR) << "Failed during poll";
return errno;
}
if (!(poll_sock.revents & POLLIN)) {
LOG(INFO) << "No data; trying again";
continue;
}
memset(buffer, 0, sizeof(buffer));
rc = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
if (rc == 0) {
LOG(ERROR) << "Lost connection, did vold crash?";
return ECONNRESET;
} else if (rc < 0) {
PLOG(ERROR) << "Error reading data";
return errno;
}
int offset = 0;
for (int i = 0; i < rc; i++) {
if (buffer[i] == '\0') {
char* res = buffer + offset;
fprintf(stdout, "%s\n", res);
int code = atoi(strtok(res, " "));
if (code >= 200 && code < 600) {
int seq = atoi(strtok(nullptr, " "));
if (seq == stop_after_seq) {
if (code == 200) {
return 0;
} else {
return code;
}
}
}
offset = i + 1;
}
}
}
return EIO;
}
static void usage(char *progname) {
LOG(INFO) << "Usage: " << progname << " [--wait] <monitor>|<cmd> [arg1] [arg2...]";
LOG(INFO) << "Usage: " << progname << " [--wait] <system> <subcommand> [args...]";
}

2
vdc.rc
View file

@ -7,6 +7,6 @@ on defaultcrypto
# One shot invocation to encrypt unencrypted volumes
on encrypt
start surfaceflinger
exec - root -- /system/bin/vdc --wait cryptfs enablecrypto inplace default noui
exec - root -- /system/bin/vdc --wait cryptfs enablecrypto
# vold will set vold.decrypt to trigger_restart_framework (default
# encryption)

View file

@ -2,9 +2,7 @@ service vold /system/bin/vold \
--blkid_context=u:r:blkid:s0 --blkid_untrusted_context=u:r:blkid_untrusted:s0 \
--fsck_context=u:r:fsck:s0 --fsck_untrusted_context=u:r:fsck_untrusted:s0
class core
socket vold stream 0660 root mount
socket cryptd stream 0660 root mount
ioprio be 2
writepid /dev/cpuset/foreground/tasks
shutdown critical
group reserved_disk

187
vold_prepare_subdirs.cpp Normal file
View file

@ -0,0 +1,187 @@
/*
* 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.
*/
/*
* Tool to create a directory with the right SELinux context applied, or
* apply the context if it's absent. Also fixes mode, uid, gid.
*/
#include <iostream>
#include <string>
#include <vector>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
#include <cutils/fs.h>
#include <selinux/android.h>
#include "Utils.h"
#include "android/os/IVold.h"
#include <private/android_filesystem_config.h>
static void usage(const char* progname) {
std::cerr << "Usage: " << progname << " [ prepare | destroy ] <volume_uuid> <user_id> <flags>"
<< std::endl;
exit(-1);
}
static bool small_int(const std::string& s) {
return !s.empty() && s.size() < 7 && s.find_first_not_of("0123456789") == std::string::npos;
}
static bool valid_uuid(const std::string& s) {
return s.size() < 40 && s.find_first_not_of("0123456789abcdefABCDEF-_") == std::string::npos;
}
static bool prepare_dir(struct selabel_handle* sehandle, mode_t mode, uid_t uid, gid_t gid,
const std::string& path) {
auto clearfscreatecon = android::base::make_scope_guard([] { setfscreatecon(nullptr); });
auto secontext = std::unique_ptr<char, void (*)(char*)>(nullptr, freecon);
char* tmp_secontext;
if (sehandle && selabel_lookup(sehandle, &tmp_secontext, path.c_str(), S_IFDIR) == 0) {
secontext.reset(tmp_secontext);
}
LOG(DEBUG) << "Setting up mode " << std::oct << mode << std::dec << " uid " << uid << " gid "
<< gid << " context " << secontext.get() << " on path: " << path;
if (secontext) {
if (setfscreatecon(secontext.get()) != 0) {
PLOG(ERROR) << "Unable to read setfscreatecon for: " << path;
return false;
}
}
if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) {
return false;
}
if (secontext) {
char* tmp_oldsecontext = nullptr;
if (lgetfilecon(path.c_str(), &tmp_oldsecontext) < 0) {
PLOG(ERROR) << "Unable to read secontext for: " << path;
return false;
}
auto oldsecontext = std::unique_ptr<char, void (*)(char*)>(tmp_oldsecontext, freecon);
if (strcmp(secontext.get(), oldsecontext.get()) != 0) {
LOG(INFO) << "Relabelling from " << ((char*)oldsecontext.get()) << " to "
<< ((char*)secontext.get()) << ": " << path;
if (lsetfilecon(path.c_str(), secontext.get()) != 0) {
PLOG(ERROR) << "Relabelling failed for: " << path;
return false;
}
}
}
return true;
}
static bool rmrf_contents(const std::string& path) {
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(path.c_str()), closedir);
if (!dirp) {
PLOG(ERROR) << "Unable to open directory: " << path;
return false;
}
bool res = true;
for (;;) {
errno = 0;
auto const entry = readdir(dirp.get());
if (!entry) {
if (errno) {
PLOG(ERROR) << "readdir failed on: " << path;
return false;
}
return res;
}
if (entry->d_name[0] == '.') continue;
auto subdir = path + "/" + entry->d_name;
if (0 !=
android::vold::ForkExecvp(std::vector<std::string>{"/system/bin/rm", "-rf", subdir})) {
LOG(ERROR) << "rm -rf failed on " << subdir;
res = false;
}
}
}
static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int flags) {
struct selabel_handle* sehandle = selinux_android_file_context_handle();
if (volume_uuid.empty()) {
if (flags & android::os::IVold::STORAGE_FLAG_DE) {
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/vold")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/storaged")) return false;
auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, vendor_de_path + "/fpdata")) {
return false;
}
}
if (flags & android::os::IVold::STORAGE_FLAG_CE) {
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/vold")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/storaged")) return false;
}
}
return true;
}
static bool destroy_subdirs(const std::string& volume_uuid, int user_id, int flags) {
bool res = true;
if (volume_uuid.empty()) {
if (flags & android::os::IVold::STORAGE_FLAG_CE) {
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
res &= rmrf_contents(misc_ce_path);
auto vendor_ce_path = android::vold::BuildDataVendorCePath(user_id);
res &= rmrf_contents(vendor_ce_path);
}
if (flags & android::os::IVold::STORAGE_FLAG_DE) {
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
res &= rmrf_contents(misc_de_path);
auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
res &= rmrf_contents(vendor_de_path);
}
}
return res;
}
int main(int argc, const char* const argv[]) {
android::base::InitLogging(const_cast<char**>(argv));
std::vector<std::string> args(argv + 1, argv + argc);
if (args.size() != 4 || !valid_uuid(args[1]) || !small_int(args[2]) || !small_int(args[3])) {
usage(argv[0]);
return -1;
}
auto volume_uuid = args[1];
int user_id = stoi(args[2]);
int flags = stoi(args[3]);
if (args[0] == "prepare") {
if (!prepare_subdirs(volume_uuid, user_id, flags)) return -1;
} else if (args[0] == "destroy") {
if (!destroy_subdirs(volume_uuid, user_id, flags)) return -1;
} else {
usage(argv[0]);
return -1;
}
return 0;
}

33
wait_for_keymaster.cpp Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2018 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 <android-base/logging.h>
#include "Keymaster.h"
int main(int argc, char** argv) {
setenv("ANDROID_LOG_TAGS", "*:v", 1);
if (getppid() == 1) {
// If init is calling us then it's during boot and we should log to kmsg
android::base::InitLogging(argv, &android::base::KernelLogger);
} else {
android::base::InitLogging(argv, &android::base::StderrLogger);
}
LOG(INFO) << "Waiting for Keymaster device";
android::vold::Keymaster keymaster;
LOG(INFO) << "Keymaster device ready";
return 0;
}

5
wait_for_keymaster.rc Normal file
View file

@ -0,0 +1,5 @@
service wait_for_keymaster /system/bin/wait_for_keymaster
user root
group root system
priority -20
ioprio rt 0