Merge "Merge Android Pie into master"
This commit is contained in:
commit
7fcaa13d4c
86 changed files with 5123 additions and 6029 deletions
11
.clang-format
Normal file
11
.clang-format
Normal 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
249
Android.bp
Normal 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"]
|
173
Android.mk
173
Android.mk
|
@ -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
43
Asec.h
|
@ -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
|
209
Benchmark.cpp
209
Benchmark.cpp
|
@ -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) {
|
||||
errno = 0;
|
||||
int orig_prio = getpriority(PRIO_PROCESS, 0);
|
||||
if (errno != 0) {
|
||||
PLOG(ERROR) << "Failed to getpriority";
|
||||
return -1;
|
||||
}
|
||||
if (setpriority(PRIO_PROCESS, 0, -10) != 0) {
|
||||
PLOG(ERROR) << "Failed to setpriority";
|
||||
return -1;
|
||||
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;
|
||||
orig_prio = getpriority(PRIO_PROCESS, 0);
|
||||
if (errno != 0) {
|
||||
PLOG(WARNING) << "Failed to getpriority";
|
||||
orig_prio = 0;
|
||||
}
|
||||
if (setpriority(PRIO_PROCESS, 0, -10) != 0) {
|
||||
PLOG(WARNING) << "Failed to setpriority";
|
||||
}
|
||||
if (android_get_ioprio(0, &orig_clazz, &orig_ioprio)) {
|
||||
PLOG(WARNING) << "Failed to android_get_ioprio";
|
||||
orig_ioprio = 0;
|
||||
orig_clazz = IoSchedClass_NONE;
|
||||
}
|
||||
if (android_set_ioprio(0, IoSchedClass_RT, 0)) {
|
||||
PLOG(WARNING) << "Failed to android_set_ioprio";
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
~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;
|
||||
}
|
||||
if (android_set_ioprio(0, IoSchedClass_RT, 0)) {
|
||||
PLOG(ERROR) << "Failed to android_set_ioprio";
|
||||
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();
|
||||
sync();
|
||||
nsecs_t create = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
|
||||
#if ENABLE_DROP_CACHES
|
||||
LOG(VERBOSE) << "Before drop_caches";
|
||||
if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
|
||||
PLOG(ERROR) << "Failed to drop_caches";
|
||||
// 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();
|
||||
if (res == OK) extras->putLong(String16("create"), timer.duration().count());
|
||||
}
|
||||
LOG(VERBOSE) << "After drop_caches";
|
||||
#endif
|
||||
nsecs_t drop = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
|
||||
BenchmarkRun();
|
||||
sync();
|
||||
nsecs_t run = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
// 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";
|
||||
sync();
|
||||
if (res == OK) extras->putLong(String16("drop"), timer.duration().count());
|
||||
}
|
||||
|
||||
BenchmarkDestroy();
|
||||
sync();
|
||||
nsecs_t destroy = systemTime(SYSTEM_TIME_BOOTTIME);
|
||||
// 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();
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
398
BenchmarkGen.h
398
BenchmarkGen.h
File diff suppressed because it is too large
Load diff
149
CheckEncryption.cpp
Normal file
149
CheckEncryption.cpp
Normal 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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
220
Devmapper.cpp
220
Devmapper.cpp
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,30 +604,33 @@ 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) {
|
||||
return 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) {
|
||||
return 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) {
|
||||
return ENABLE_INPLACE_ERR_DEV;
|
||||
LOG(DEBUG) << "ENABLE_INPLACE_ERR_DEV";
|
||||
return ENABLE_INPLACE_ERR_DEV;
|
||||
}
|
||||
return rc_full;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
308
Ext4Crypt.cpp
308
Ext4Crypt.cpp
|
@ -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,
|
||||
int flags) {
|
||||
LOG(DEBUG) << "e4crypt_prepare_user_storage for volume " << escape_null(volume_uuid)
|
||||
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_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,48 +663,71 @@ 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 (!prepare_dir(system_legacy_path, 0700, AID_SYSTEM, AID_SYSTEM)) return false;
|
||||
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),
|
||||
multiuser_get_uid(user_id, AID_EVERYBODY))) return false;
|
||||
if (!prepare_dir(misc_legacy_path, 0750, multiuser_get_uid(user_id, AID_SYSTEM),
|
||||
multiuser_get_uid(user_id, AID_EVERYBODY))) return false;
|
||||
#endif
|
||||
if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
|
||||
if (!prepare_dir(profiles_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
|
||||
|
||||
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(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 (!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 (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;
|
||||
}
|
||||
|
|
22
Ext4Crypt.h
22
Ext4Crypt.h
|
@ -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
388
IdleMaint.cpp
Normal 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
|
|
@ -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
|
262
KeyStorage.cpp
262
KeyStorage.cpp
|
@ -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{"", ""};
|
||||
|
||||
|
@ -61,7 +60,7 @@ static constexpr size_t SALT_BYTES = 1 << 4;
|
|||
static constexpr size_t SECDISCARDABLE_BYTES = 1 << 14;
|
||||
static constexpr size_t STRETCHED_BYTES = 1 << 6;
|
||||
|
||||
static constexpr uint32_t AUTH_TIMEOUT = 30; // Seconds
|
||||
static constexpr uint32_t AUTH_TIMEOUT = 30; // Seconds
|
||||
|
||||
static const char* kCurrentVersion = "1";
|
||||
static const char* kRmPath = "/system/bin/rm";
|
||||
|
@ -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)>(
|
||||
|
@ -316,16 +351,16 @@ static bool encryptWithoutKeymaster(const std::string& preKey,
|
|||
return false;
|
||||
}
|
||||
if (1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL,
|
||||
reinterpret_cast<const uint8_t*>(key.data()),
|
||||
reinterpret_cast<const uint8_t*>(ciphertext->data()))) {
|
||||
reinterpret_cast<const uint8_t*>(key.data()),
|
||||
reinterpret_cast<const uint8_t*>(ciphertext->data()))) {
|
||||
logOpensslError();
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
|
@ -365,16 +404,16 @@ static bool decryptWithoutKeymaster(const std::string& preKey,
|
|||
return false;
|
||||
}
|
||||
if (1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), NULL,
|
||||
reinterpret_cast<const uint8_t*>(key.data()),
|
||||
reinterpret_cast<const uint8_t*>(ciphertext.data()))) {
|
||||
reinterpret_cast<const uint8_t*>(key.data()),
|
||||
reinterpret_cast<const uint8_t*>(ciphertext.data()))) {
|
||||
logOpensslError();
|
||||
return false;
|
||||
}
|
||||
*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.
|
||||
success &= deleteKey(dir);
|
||||
success &= runSecdiscard(dir);
|
||||
bool uses_km = pathExists(dir + "/" + kFn_keymaster_key_blob);
|
||||
if (uses_km) {
|
||||
success &= deleteKey(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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
10
KeyUtil.cpp
10
KeyUtil.cpp
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
184
Keymaster.cpp
184
Keymaster.cpp
|
@ -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) {
|
||||
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*/,
|
||||
const hidl_vec<uint8_t>& _output) {
|
||||
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,75 +139,72 @@ 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());
|
||||
upgradedKeyBlob.size());
|
||||
};
|
||||
auto error = mDevice->upgradeKey(oldKeyBlob, inParams.hidl_data(), hidlCb);
|
||||
if (!error.isOk()) {
|
||||
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,
|
||||
uint64_t operationHandle) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
83
Keymaster.h
83
Keymaster.h
|
@ -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
|
||||
|
|
314
Loop.cpp
314
Loop.cpp
|
@ -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;
|
||||
return -1;
|
||||
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
9
Loop.h
|
@ -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
|
||||
|
|
|
@ -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,108 +203,45 @@ 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;
|
||||
|
||||
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);
|
||||
if (rc != 0) {
|
||||
LOG(ERROR) << "Inplace crypto failed with code: " << rc;
|
||||
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, false);
|
||||
if (rc != 0) {
|
||||
LOG(ERROR) << "Inplace crypto failed with code: " << rc;
|
||||
return false;
|
||||
}
|
||||
if (static_cast<uint64_t>(size_already_done) != nr_sec) {
|
||||
LOG(ERROR) << "Inplace crypto only got up to sector: " << size_already_done;
|
||||
return false;
|
||||
}
|
||||
LOG(INFO) << "Inplace encryption complete";
|
||||
}
|
||||
if (static_cast<uint64_t>(size_already_done) != nr_sec) {
|
||||
LOG(ERROR) << "Inplace crypto only got up to sector: " << size_already_done;
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
return ForkExecvp(cmd);
|
||||
#else
|
||||
if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
|
||||
return ForkExecvp(cmd);
|
||||
}
|
||||
|
||||
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
|
||||
return ForkExecvp(cmd);
|
||||
#else
|
||||
if (android::base::GetBoolProperty(kPropBlockingExec, false)) {
|
||||
return ForkExecvp(cmd);
|
||||
}
|
||||
|
||||
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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
5
PREUPLOAD.cfg
Normal 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
|
229
Process.cpp
229
Process.cpp
|
@ -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);
|
||||
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 1;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return 0;
|
||||
return found;
|
||||
}
|
||||
|
||||
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;
|
||||
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 (signal != 0) {
|
||||
SLOGW("Sending %s to process %d", strsignal(signal), pid);
|
||||
kill(pid, signal);
|
||||
count++;
|
||||
if (found) {
|
||||
pids.insert(pid);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
return count;
|
||||
if (signal != 0) {
|
||||
for (const auto& pid : pids) {
|
||||
LOG(WARNING) << "Sending " << strsignal(signal) << " to " << pid;
|
||||
kill(pid, signal);
|
||||
}
|
||||
}
|
||||
return pids.size();
|
||||
}
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
|
26
Process.h
26
Process.h
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
151
TrimTask.cpp
151
TrimTask.cpp
|
@ -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
|
196
Utils.cpp
196
Utils.cpp
|
@ -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,14 +271,18 @@ status_t ForkExecvp(const std::vector<std::string>& args, security_context_t con
|
|||
}
|
||||
}
|
||||
|
||||
if (setexeccon(context)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
if (context) {
|
||||
if (setexeccon(context)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
status_t res = android_fork_execvp(argc, argv, NULL, false, true);
|
||||
if (setexeccon(nullptr)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
if (context) {
|
||||
if (setexeccon(nullptr)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
free(argv);
|
||||
|
@ -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,14 +308,18 @@ status_t ForkExecvp(const std::vector<std::string>& args,
|
|||
}
|
||||
output.clear();
|
||||
|
||||
if (setexeccon(context)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
if (context) {
|
||||
if (setexeccon(context)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
FILE* fp = popen(cmd.c_str(), "r"); // NOLINT
|
||||
if (setexeccon(nullptr)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
if (context) {
|
||||
if (setexeccon(nullptr)) {
|
||||
LOG(ERROR) << "Failed to setexeccon";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
if (!fp) {
|
||||
|
@ -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
35
Utils.h
|
@ -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
763
VoldNativeService.cpp
Normal 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
121
VoldNativeService.h
Normal 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_
|
|
@ -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;
|
|
@ -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
|
||||
|
|
1802
VolumeManager.cpp
1802
VolumeManager.cpp
File diff suppressed because it is too large
Load diff
133
VolumeManager.h
133
VolumeManager.h
|
@ -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
|
||||
|
|
|
@ -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, """
|
||||
|
|
142
binder/android/os/IVold.aidl
Normal file
142
binder/android/os/IVold.aidl
Normal 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;
|
||||
}
|
37
binder/android/os/IVoldListener.aidl
Normal file
37
binder/android/os/IVoldListener.aidl
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
751
cryptfs.cpp
751
cryptfs.cpp
File diff suppressed because it is too large
Load diff
62
cryptfs.h
62
cryptfs.h
|
@ -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
97
fs/Exfat.cpp
Normal 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
39
fs/Exfat.h
Normal 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
|
|
@ -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>
|
||||
|
||||
|
|
19
fs/F2fs.cpp
19
fs/F2fs.cpp
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
20
fs/Vfat.cpp
20
fs/Vfat.cpp
|
@ -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
109
main.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,45 +352,57 @@ 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)) {
|
||||
case 0x06: // FAT16
|
||||
case 0x0b: // W95 FAT32 (LBA)
|
||||
case 0x0c: // W95 FAT32 (LBA)
|
||||
case 0x0e: // W95 FAT16 (LBA)
|
||||
createPublicVolume(partDevice);
|
||||
break;
|
||||
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)
|
||||
createPublicVolume(partDevice);
|
||||
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)) {
|
|
@ -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;
|
|
@ -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
130
model/ObbVolume.cpp
Normal 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
57
model/ObbVolume.h
Normal 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
|
|
@ -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";
|
|
@ -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;
|
|
@ -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,19 +94,23 @@ status_t PublicVolume::doDestroy() {
|
|||
}
|
||||
|
||||
status_t PublicVolume::doMount() {
|
||||
// TODO: expand to support mounting other filesystems
|
||||
readMetadata();
|
||||
|
||||
if (mFsType != "vfat") {
|
||||
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;
|
||||
}
|
||||
|
||||
if (vfat::Check(mDevPath)) {
|
||||
LOG(ERROR) << getId() << " failed filesystem check";
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
// Use UUID as stable name, if available
|
||||
std::string stableName = getId();
|
||||
if (!mFsUuid.empty()) {
|
||||
|
@ -129,10 +135,17 @@ status_t PublicVolume::doMount() {
|
|||
return -errno;
|
||||
}
|
||||
|
||||
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;
|
||||
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) {
|
||||
|
@ -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;
|
|
@ -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;
|
|
@ -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 */
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
#include <selinux/selinux.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
security_context_t secontextFsck();
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
14
tests/Android.bp
Normal file
14
tests/Android.bp
Normal 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"],
|
||||
}
|
|
@ -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
44
tests/Utils_test.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
54
tests/cryptfs_test.cpp
Normal 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));
|
||||
}
|
||||
|
||||
}
|
180
vdc.cpp
180
vdc.cpp
|
@ -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);
|
||||
} else {
|
||||
usleep(10000);
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "monitor")) {
|
||||
exit(do_monitor(sock, 0));
|
||||
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 {
|
||||
exit(do_cmd(sock, argc, argv));
|
||||
LOG(ERROR) << "Raw commands are no longer supported";
|
||||
exit(EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
2
vdc.rc
|
@ -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)
|
||||
|
|
4
vold.rc
4
vold.rc
|
@ -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
187
vold_prepare_subdirs.cpp
Normal 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
33
wait_for_keymaster.cpp
Normal 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
5
wait_for_keymaster.rc
Normal file
|
@ -0,0 +1,5 @@
|
|||
service wait_for_keymaster /system/bin/wait_for_keymaster
|
||||
user root
|
||||
group root system
|
||||
priority -20
|
||||
ioprio rt 0
|
Loading…
Reference in a new issue